summaryrefslogtreecommitdiff
path: root/gcc/config/rs6000
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rs6000')
-rwxr-xr-xgcc/config/rs6000/aix31.h41
-rwxr-xr-xgcc/config/rs6000/aix3newas.h88
-rwxr-xr-xgcc/config/rs6000/aix41.h169
-rwxr-xr-xgcc/config/rs6000/aix43.h199
-rwxr-xr-xgcc/config/rs6000/beos.h124
-rwxr-xr-xgcc/config/rs6000/cygwin.h67
-rwxr-xr-xgcc/config/rs6000/eabi-ci.asm131
-rwxr-xr-xgcc/config/rs6000/eabi-cn.asm121
-rwxr-xr-xgcc/config/rs6000/eabi-ctors.c92
-rwxr-xr-xgcc/config/rs6000/eabi.asm575
-rwxr-xr-xgcc/config/rs6000/eabi.h40
-rwxr-xr-xgcc/config/rs6000/eabiaix.h41
-rwxr-xr-xgcc/config/rs6000/eabile.h49
-rwxr-xr-xgcc/config/rs6000/eabilesim.h46
-rwxr-xr-xgcc/config/rs6000/eabisim.h46
-rwxr-xr-xgcc/config/rs6000/linux.h76
-rwxr-xr-xgcc/config/rs6000/lynx.h104
-rwxr-xr-xgcc/config/rs6000/mach.h42
-rwxr-xr-xgcc/config/rs6000/milli.exp7
-rwxr-xr-xgcc/config/rs6000/netware.h284
-rwxr-xr-xgcc/config/rs6000/nt-ci.asm48
-rwxr-xr-xgcc/config/rs6000/nt-cn.asm48
-rwxr-xr-xgcc/config/rs6000/ntstack.asm42
-rwxr-xr-xgcc/config/rs6000/powerpc.h61
-rwxr-xr-xgcc/config/rs6000/rs6000.c7156
-rwxr-xr-xgcc/config/rs6000/rs6000.h3403
-rwxr-xr-xgcc/config/rs6000/rs6000.md13242
-rwxr-xr-xgcc/config/rs6000/rtems.h38
-rwxr-xr-xgcc/config/rs6000/sol-c0.c122
-rwxr-xr-xgcc/config/rs6000/sol-ci.asm104
-rwxr-xr-xgcc/config/rs6000/sol-cn.asm82
-rwxr-xr-xgcc/config/rs6000/sol2.h179
-rwxr-xr-xgcc/config/rs6000/sysv4.h1770
-rwxr-xr-xgcc/config/rs6000/sysv4le.h54
-rwxr-xr-xgcc/config/rs6000/t-aix4348
-rwxr-xr-xgcc/config/rs6000/t-beos51
-rwxr-xr-xgcc/config/rs6000/t-newas52
-rwxr-xr-xgcc/config/rs6000/t-ppc12
-rwxr-xr-xgcc/config/rs6000/t-ppccomm79
-rwxr-xr-xgcc/config/rs6000/t-ppcgas22
-rwxr-xr-xgcc/config/rs6000/t-ppcos12
-rwxr-xr-xgcc/config/rs6000/t-rs600022
-rwxr-xr-xgcc/config/rs6000/t-vxworks3
-rwxr-xr-xgcc/config/rs6000/t-winnt35
-rwxr-xr-xgcc/config/rs6000/t-xnewas58
-rwxr-xr-xgcc/config/rs6000/t-xrs600028
-rwxr-xr-xgcc/config/rs6000/tramp.asm120
-rwxr-xr-xgcc/config/rs6000/vxppc.h107
-rwxr-xr-xgcc/config/rs6000/vxppcle.h58
-rwxr-xr-xgcc/config/rs6000/win-nt.h481
-rwxr-xr-xgcc/config/rs6000/x-aix319
-rwxr-xr-xgcc/config/rs6000/x-aix4112
-rwxr-xr-xgcc/config/rs6000/x-aix4315
-rwxr-xr-xgcc/config/rs6000/x-beos9
-rwxr-xr-xgcc/config/rs6000/x-cygwin4
-rwxr-xr-xgcc/config/rs6000/x-lynx14
-rwxr-xr-xgcc/config/rs6000/x-mach7
-rwxr-xr-xgcc/config/rs6000/x-rs60009
-rwxr-xr-xgcc/config/rs6000/x-sysv42
-rwxr-xr-xgcc/config/rs6000/xm-beos.h89
-rwxr-xr-xgcc/config/rs6000/xm-cygwin.h1
-rwxr-xr-xgcc/config/rs6000/xm-lynx.h35
-rwxr-xr-xgcc/config/rs6000/xm-mach.h2
-rwxr-xr-xgcc/config/rs6000/xm-rs6000.h65
-rwxr-xr-xgcc/config/rs6000/xm-sysv4.h72
65 files changed, 30224 insertions, 0 deletions
diff --git a/gcc/config/rs6000/aix31.h b/gcc/config/rs6000/aix31.h
new file mode 100755
index 0000000..46bd03c
--- /dev/null
+++ b/gcc/config/rs6000/aix31.h
@@ -0,0 +1,41 @@
+/* Definitions of target machine for GNU compiler,
+ for IBM RS/6000 running AIX version 3.1.
+ Copyright (C) 1993,1997 Free Software Foundation, Inc.
+ Contributed by Richard Kenner (kenner@nyu.edu)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#include "rs6000/rs6000.h"
+
+/* AIX 3.2 defined _AIX32, but older versions do not. */
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D_IBMR2 -D_AIX -Asystem(unix) -Asystem(aix) -Acpu(rs6000) -Amachine(rs6000)"
+
+/* AIX 3.1 uses bit 15 in CROR as the magic nop. */
+#undef RS6000_CALL_GLUE
+#define RS6000_CALL_GLUE "cror 15,15,15"
+
+/* AIX 3.1 does not prepend underscores to itrunc, uitrunc, or mcount. */
+#undef RS6000_ITRUNC
+#define RS6000_ITRUNC "itrunc"
+#undef RS6000_UITRUNC
+#define RS6000_UITRUNC "uitrunc"
+#undef RS6000_MCOUNT
+#define RS6000_MCOUNT ".mcount"
+
diff --git a/gcc/config/rs6000/aix3newas.h b/gcc/config/rs6000/aix3newas.h
new file mode 100755
index 0000000..9659794
--- /dev/null
+++ b/gcc/config/rs6000/aix3newas.h
@@ -0,0 +1,88 @@
+/* Definitions of target machine for GNU compiler,
+ for IBM RS/6000 POWER running AIX version 3.x with the fixed assembler.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by Jason Merrill (jason@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Enable AIX XL compiler calling convention breakage compatibility. */
+#define MASK_XL_CALL 0x40000000
+#define TARGET_XL_CALL (target_flags & MASK_XL_CALL)
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ {"xl-call", MASK_XL_CALL}, \
+ {"no-xl-call", - MASK_XL_CALL},
+
+#include "rs6000/rs6000.h"
+
+/* Tell the assembler to assume that all undefined names are external. */
+
+#undef ASM_SPEC
+#define ASM_SPEC "-u %(asm_cpu)"
+
+#undef ASM_DEFAULT_SPEC
+#define ASM_DEFAULT_SPEC "-mpwr"
+
+/* Define the options for the binder: Start text at 512, align all segments
+ to 512 bytes, and warn if there is text relocation.
+
+ The -bhalt:4 option supposedly changes the level at which ld will abort,
+ but it also suppresses warnings about multiply defined symbols and is
+ used by the AIX cc command. So we use it here.
+
+ -bnodelcsect undoes a poor choice of default relating to multiply-defined
+ csects. See AIX documentation for more information about this.
+
+ -bM:SRE tells the linker that the output file is Shared REusable. Note
+ that to actually build a shared library you will also need to specify an
+ export list with the -Wl,-bE option.
+
+ If -mcpu=common, export the architecture dependent multiply/divide routines
+ as per README.RS6000. */
+
+#undef LINK_SPEC
+#ifndef CROSS_COMPILE
+#define LINK_SPEC "-T512 -H512 %{!r:-btextro} -bhalt:4 -bnodelcsect\
+ %{static:-bnso -bI:/lib/syscalls.exp} \
+ %{mcpu=common: milli.exp%s} \
+ %{!shared:%{g*:-bexport:/usr/lib/libg.exp}} %{shared:-bM:SRE}"
+#else
+#define LINK_SPEC "-T512 -H512 %{!r:-btextro} -bhalt:4 -bnodelcsect\
+ %{static:-bnso} \
+ %{mcpu=common: milli.exp%s} \
+ %{shared:-bM:SRE}"
+#endif
+
+/* These are not necessary when we pass -u to the assembler, and undefining
+ them saves a great deal of space in object files. */
+
+#undef ASM_OUTPUT_EXTERNAL
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
+{ rtx _symref = XEXP (DECL_RTL (DECL), 0); \
+ if ((TREE_CODE (DECL) == VAR_DECL \
+ || TREE_CODE (DECL) == FUNCTION_DECL) \
+ && (NAME)[strlen (NAME) - 1] != ']') \
+ { \
+ char *_name = (char *) permalloc (strlen (XSTR (_symref, 0)) + 5); \
+ strcpy (_name, XSTR (_symref, 0)); \
+ strcat (_name, TREE_CODE (DECL) == FUNCTION_DECL ? "[DS]" : "[RW]"); \
+ XSTR (_symref, 0) = _name; \
+ } \
+}
diff --git a/gcc/config/rs6000/aix41.h b/gcc/config/rs6000/aix41.h
new file mode 100755
index 0000000..b35fe93
--- /dev/null
+++ b/gcc/config/rs6000/aix41.h
@@ -0,0 +1,169 @@
+/* Definitions of target machine for GNU compiler,
+ for IBM RS/6000 POWER running AIX version 4.1.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by David Edelsohn (edelsohn@npac.syr.edu).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Enable AIX XL compiler calling convention breakage compatibility. */
+#define MASK_XL_CALL 0x40000000
+#define TARGET_XL_CALL (target_flags & MASK_XL_CALL)
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ {"xl-call", MASK_XL_CALL}, \
+ {"no-xl-call", - MASK_XL_CALL}, \
+ {"threads", 0}, \
+ {"pe", 0},
+
+#include "rs6000/rs6000.h"
+
+#undef ASM_SPEC
+#define ASM_SPEC "-u %(asm_cpu)"
+
+/* Common ASM definitions used by ASM_SPEC amonst the various targets
+ for handling -mcpu=xxx switches. */
+#undef ASM_CPU_SPEC
+#define ASM_CPU_SPEC \
+"%{!mcpu*: \
+ %{mpower: %{!mpower2: -mpwr}} \
+ %{mpower2: -mpwr2} \
+ %{mpowerpc*: -mppc} \
+ %{!mpower*: %{!mpowerpc*: %(asm_default)}}} \
+%{mcpu=common: -mcom} \
+%{mcpu=power: -mpwr} \
+%{mcpu=power2: -mpwr2} \
+%{mcpu=powerpc: -mppc} \
+%{mcpu=rios: -mpwr} \
+%{mcpu=rios1: -mpwr} \
+%{mcpu=rios2: -mpwr2} \
+%{mcpu=rsc: -mpwr} \
+%{mcpu=rsc1: -mpwr} \
+%{mcpu=403: -mppc} \
+%{mcpu=505: -mppc} \
+%{mcpu=601: -m601} \
+%{mcpu=602: -mppc} \
+%{mcpu=603: -m603} \
+%{mcpu=603e: -m603} \
+%{mcpu=604: -m604} \
+%{mcpu=620: -mppc} \
+%{mcpu=821: -mppc} \
+%{mcpu=860: -mppc}"
+
+#undef ASM_DEFAULT_SPEC
+#define ASM_DEFAULT_SPEC "-mcom"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D_IBMR2 -D_POWER -D_AIX -D_AIX32 -D_AIX41 \
+-D_LONG_LONG -Asystem(unix) -Asystem(aix)"
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{posix: -D_POSIX_SOURCE}\
+ %{mpe: -I/usr/lpp/ppe.poe/include}\
+ %{mthreads: -D_THREAD_SAFE}\
+ %(cpp_cpu)"
+
+/* Common CPP definitions used by CPP_SPEC among the various targets
+ for handling -mcpu=xxx switches. */
+#undef CPP_CPU_SPEC
+#define CPP_CPU_SPEC \
+"%{!mcpu*: \
+ %{mpower: %{!mpower2: -D_ARCH_PWR}} \
+ %{mpower2: -D_ARCH_PWR2} \
+ %{mpowerpc*: -D_ARCH_PPC} \
+ %{!mpower*: %{!mpowerpc*: %(cpp_default)}}} \
+%{mcpu=common: -D_ARCH_COM} \
+%{mcpu=power: -D_ARCH_PWR} \
+%{mcpu=power2: -D_ARCH_PWR2} \
+%{mcpu=powerpc: -D_ARCH_PPC} \
+%{mcpu=rios: -D_ARCH_PWR} \
+%{mcpu=rios1: -D_ARCH_PWR} \
+%{mcpu=rios2: -D_ARCH_PWR2} \
+%{mcpu=rsc: -D_ARCH_PWR} \
+%{mcpu=rsc1: -D_ARCH_PWR} \
+%{mcpu=403: -D_ARCH_PPC} \
+%{mcpu=505: -D_ARCH_PPC} \
+%{mcpu=601: -D_ARCH_PPC -D_ARCH_PWR} \
+%{mcpu=602: -D_ARCH_PPC} \
+%{mcpu=603: -D_ARCH_PPC} \
+%{mcpu=603e: -D_ARCH_PPC} \
+%{mcpu=604: -D_ARCH_PPC} \
+%{mcpu=620: -D_ARCH_PPC} \
+%{mcpu=821: -D_ARCH_PPC} \
+%{mcpu=860: -D_ARCH_PPC}"
+
+#undef CPP_DEFAULT_SPEC
+#define CPP_DEFAULT_SPEC "-D_ARCH_COM"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT MASK_NEW_MNEMONICS
+
+#undef PROCESSOR_DEFAULT
+#define PROCESSOR_DEFAULT PROCESSOR_PPC601
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using `MULTILIB_OPTIONS'.
+
+ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
+ the target makefile fragment or if none of the options listed in
+ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mcpu=common" }
+
+/* These are not necessary when we pass -u to the assembler, and undefining
+ them saves a great deal of space in object files. */
+
+#undef ASM_OUTPUT_EXTERNAL
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
+{ rtx _symref = XEXP (DECL_RTL (DECL), 0); \
+ if ((TREE_CODE (DECL) == VAR_DECL \
+ || TREE_CODE (DECL) == FUNCTION_DECL) \
+ && (NAME)[strlen (NAME) - 1] != ']') \
+ { \
+ char *_name = (char *) permalloc (strlen (XSTR (_symref, 0)) + 5); \
+ strcpy (_name, XSTR (_symref, 0)); \
+ strcat (_name, TREE_CODE (DECL) == FUNCTION_DECL ? "[DS]" : "[RW]"); \
+ XSTR (_symref, 0) = _name; \
+ } \
+}
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{pg:-L/lib/profiled -L/usr/lib/profiled}\
+ %{p:-L/lib/profiled -L/usr/lib/profiled} %{!shared:%{g*:-lg}}\
+ %{mpe:-L/usr/lpp/ppe.poe/lib -lmpi -lvtd}\
+ %{mthreads: -L/usr/lib/threads -lpthreads -lc_r /usr/lib/libc.a}\
+ %{!mthreads: -lc}"
+
+#undef LINK_SPEC
+#define LINK_SPEC "-bpT:0x10000000 -bpD:0x20000000 %{!r:-btextro} -bnodelcsect\
+ %{static:-bnso %(link_syscalls) } %{!shared: %{g*: %(link_libg) }}\
+ %{shared:-bM:SRE %{!e:-bnoentry}}"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared:\
+ %{mpe:%{pg:/usr/lpp/ppe.poe/lib/gcrt0.o}\
+ %{!pg:%{p:/usr/lpp/ppe.poe/lib/mcrt0.o}\
+ %{!p:/usr/lpp/ppe.poe/lib/crt0.o}}}\
+ %{!mpe:\
+ %{mthreads:%{pg:gcrt0_r%O%s}%{!pg:%{p:mcrt0_r%O%s}%{!p:crt0_r%O%s}}}\
+ %{!mthreads:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}}}"
+
diff --git a/gcc/config/rs6000/aix43.h b/gcc/config/rs6000/aix43.h
new file mode 100755
index 0000000..124fc17
--- /dev/null
+++ b/gcc/config/rs6000/aix43.h
@@ -0,0 +1,199 @@
+/* Definitions of target machine for GNU compiler,
+ for IBM RS/6000 POWER running AIX version 4.3.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by David Edelsohn (edelsohn@mhpcc.edu).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Enable AIX XL compiler calling convention breakage compatibility. */
+#define MASK_XL_CALL 0x40000000
+#define TARGET_XL_CALL (target_flags & MASK_XL_CALL)
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ {"aix64", MASK_64BIT | MASK_POWERPC64 | MASK_POWERPC}, \
+ {"aix32", - (MASK_64BIT | MASK_POWERPC64)}, \
+ {"xl-call", MASK_XL_CALL}, \
+ {"no-xl-call", - MASK_XL_CALL}, \
+ {"threads", 0}, \
+ {"pe", 0},
+
+/* Sometimes certain combinations of command options do not make sense
+ on a particular target machine. You can define a macro
+ `OVERRIDE_OPTIONS' to take account of this. This macro, if
+ defined, is executed once just after all the command options have
+ been parsed.
+
+ The macro SUBTARGET_OVERRIDE_OPTIONS is provided for subtargets, to
+ get control. */
+
+#define NON_POWERPC_MASKS (MASK_POWER | MASK_POWER2 | MASK_STRING)
+#define SUBTARGET_OVERRIDE_OPTIONS \
+do { \
+ if (TARGET_64BIT && (target_flags & NON_POWERPC_MASKS)) \
+ { \
+ target_flags &= ~NON_POWERPC_MASKS; \
+ error ("-maix64 and POWER architecture are incompatible."); \
+ } \
+} while (0);
+
+#include "rs6000/rs6000.h"
+
+#undef ASM_SPEC
+#define ASM_SPEC "-u %{maix64:-a64 -mppc64} %(asm_cpu)"
+
+/* Common ASM definitions used by ASM_SPEC amonst the various targets
+ for handling -mcpu=xxx switches. */
+#undef ASM_CPU_SPEC
+#define ASM_CPU_SPEC \
+"%{!mcpu*: %{!maix64: \
+ %{mpower: %{!mpower2: -mpwr}} \
+ %{mpower2: -mpwr2} \
+ %{mpowerpc*: %{!mpowerpc64: -mppc}} \
+ %{mpowerpc64: -mppc64} \
+ %{!mpower*: %{!mpowerpc*: %(asm_default)}}}} \
+%{mcpu=common: -mcom} \
+%{mcpu=power: -mpwr} \
+%{mcpu=power2: -mpwr2} \
+%{mcpu=powerpc: -mppc} \
+%{mcpu=rios: -mpwr} \
+%{mcpu=rios1: -mpwr} \
+%{mcpu=rios2: -mpwr2} \
+%{mcpu=rsc: -mpwr} \
+%{mcpu=rsc1: -mpwr} \
+%{mcpu=403: -mppc} \
+%{mcpu=505: -mppc} \
+%{mcpu=601: -m601} \
+%{mcpu=602: -mppc} \
+%{mcpu=603: -m603} \
+%{mcpu=603e: -m603} \
+%{mcpu=604: -m604} \
+%{mcpu=620: -mppc} \
+%{mcpu=821: -mppc} \
+%{mcpu=860: -mppc}"
+
+#undef ASM_DEFAULT_SPEC
+#define ASM_DEFAULT_SPEC "-mcom"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D_IBMR2 -D_POWER -D_AIX -D_AIX32 -D_AIX41 -D_AIX43 \
+-D_LONG_LONG -Asystem(unix) -Asystem(aix)"
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{posix: -D_POSIX_SOURCE}\
+ %{maix64: -D__64BIT__ -D_ARCH_PPC}\
+ %{mpe: -I/usr/lpp/ppe.poe/include}\
+ %{mthreads: -D_THREAD_SAFE}\
+ %(cpp_cpu)"
+
+/* Common CPP definitions used by CPP_SPEC among the various targets
+ for handling -mcpu=xxx switches. */
+#undef CPP_CPU_SPEC
+#define CPP_CPU_SPEC \
+"%{!mcpu*: %{!maix64: \
+ %{mpower: %{!mpower2: -D_ARCH_PWR}} \
+ %{mpower2: -D_ARCH_PWR2} \
+ %{mpowerpc*: -D_ARCH_PPC} \
+ %{!mpower*: %{!mpowerpc*: %(cpp_default)}}}} \
+%{mcpu=common: -D_ARCH_COM} \
+%{mcpu=power: -D_ARCH_PWR} \
+%{mcpu=power2: -D_ARCH_PWR2} \
+%{mcpu=powerpc: -D_ARCH_PPC} \
+%{mcpu=rios: -D_ARCH_PWR} \
+%{mcpu=rios1: -D_ARCH_PWR} \
+%{mcpu=rios2: -D_ARCH_PWR2} \
+%{mcpu=rsc: -D_ARCH_PWR} \
+%{mcpu=rsc1: -D_ARCH_PWR} \
+%{mcpu=403: -D_ARCH_PPC} \
+%{mcpu=505: -D_ARCH_PPC} \
+%{mcpu=601: -D_ARCH_PPC -D_ARCH_PWR} \
+%{mcpu=602: -D_ARCH_PPC} \
+%{mcpu=603: -D_ARCH_PPC} \
+%{mcpu=603e: -D_ARCH_PPC} \
+%{mcpu=604: -D_ARCH_PPC} \
+%{mcpu=620: -D_ARCH_PPC} \
+%{mcpu=821: -D_ARCH_PPC} \
+%{mcpu=860: -D_ARCH_PPC}"
+
+#undef CPP_DEFAULT_SPEC
+#define CPP_DEFAULT_SPEC "-D_ARCH_COM"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT MASK_NEW_MNEMONICS
+
+#undef PROCESSOR_DEFAULT
+#define PROCESSOR_DEFAULT PROCESSOR_PPC604
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using `MULTILIB_OPTIONS'.
+
+ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
+ the target makefile fragment or if none of the options listed in
+ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mcpu=common" }
+
+/* These are not necessary when we pass -u to the assembler, and undefining
+ them saves a great deal of space in object files. */
+
+#undef ASM_OUTPUT_EXTERNAL
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
+{ rtx _symref = XEXP (DECL_RTL (DECL), 0); \
+ if ((TREE_CODE (DECL) == VAR_DECL \
+ || TREE_CODE (DECL) == FUNCTION_DECL) \
+ && (NAME)[strlen (NAME) - 1] != ']') \
+ { \
+ char *_name = (char *) permalloc (strlen (XSTR (_symref, 0)) + 5); \
+ strcpy (_name, XSTR (_symref, 0)); \
+ strcat (_name, TREE_CODE (DECL) == FUNCTION_DECL ? "[DS]" : "[RW]"); \
+ XSTR (_symref, 0) = _name; \
+ } \
+}
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{pg:-L/lib/profiled -L/usr/lib/profiled}\
+ %{p:-L/lib/profiled -L/usr/lib/profiled} %{!shared:%{g*:-lg}}\
+ %{mpe:-L/usr/lpp/ppe.poe/lib -lmpi -lvtd}\
+ %{mthreads: -L/usr/lib/threads -lpthreads -lc_r /usr/lib/libc.a}\
+ %{!mthreads: -lc}"
+
+#undef LINK_SPEC
+#define LINK_SPEC "-bpT:0x10000000 -bpD:0x20000000 %{!r:-btextro} -bnodelcsect\
+ %{static:-bnso %(link_syscalls) } %{!shared: %{g*: %(link_libg) }}\
+ %{shared:-bM:SRE %{!e:-bnoentry}} %{maix64:-b64}"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared:\
+ %{mpe:%{pg:/usr/lpp/ppe.poe/lib/gcrt0.o}\
+ %{!pg:%{p:/usr/lpp/ppe.poe/lib/mcrt0.o}\
+ %{!p:/usr/lpp/ppe.poe/lib/crt0.o}}}\
+ %{!mpe:\
+ %{maix64:%{pg:gcrt0_64%O%s}%{!pg:%{p:mcrt0_64%O%s}%{!p:crt0_64%O%s}}}\
+ %{!maix64:\
+ %{mthreads:%{pg:gcrt0_r%O%s}%{!pg:%{p:mcrt0_r%O%s}%{!p:crt0_r%O%s}}}\
+ %{!mthreads:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}}}}"
+
+/* AIX 4.3 typedefs ptrdiff_t as "long" while earlier releases used "int". */
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "long int"
+
diff --git a/gcc/config/rs6000/beos.h b/gcc/config/rs6000/beos.h
new file mode 100755
index 0000000..851601f
--- /dev/null
+++ b/gcc/config/rs6000/beos.h
@@ -0,0 +1,124 @@
+/* Definitions of target machine for GNU compiler, for BeOS.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Contributed by Fred Fish (fnf@cygnus.com), based on aix41.h
+ from David Edelsohn (edelsohn@npac.syr.edu).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Enable AIX XL compiler calling convention breakage compatibility. */
+#define MASK_XL_CALL 0x40000000
+#define TARGET_XL_CALL (target_flags & MASK_XL_CALL)
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ {"xl-call", MASK_XL_CALL}, \
+ {"no-xl-call", - MASK_XL_CALL}, \
+ {"threads", 0}, \
+ {"pe", 0},
+
+#include "rs6000/rs6000.h"
+
+#undef ASM_SPEC
+#define ASM_SPEC "-u %(asm_cpu)"
+
+#undef CPP_PREDEFINES
+/* __POWERPC__ must be defined for some header files */
+#define CPP_PREDEFINES "-D__BEOS__ -D__POWERPC__ -Asystem(beos) -Acpu(powerpc) -Amachine(powerpc)"
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{posix: -D_POSIX_SOURCE} %(cpp_cpu)"
+
+#undef CPP_DEFAULT_SPEC
+#define CPP_DEFAULT_SPEC "-D_ARCH_PPC"
+
+/* This is the easiest way to disable use of gcc's builtin alloca,
+ which in the current BeOS release (DR9) is a problem because of the
+ relatively low default stack size of 256K with no way to expand it.
+ So anything we compile for the BeOS target should not use the
+ builtin alloca. This also has the unwanted side effect of
+ disabling all builtin functions though. */
+
+#undef CC1_SPEC
+#define CC1_SPEC "%{!fbuiltin: -fno-builtin}"
+#undef CC1PLUS_SPEC
+#define CC1PLUS_SPEC "%{!fbuiltin: -fno-builtin}"
+
+#undef ASM_DEFAULT_SPEC
+#define ASM_DEFAULT_SPEC "-mppc"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS)
+
+#undef PROCESSOR_DEFAULT
+#define PROCESSOR_DEFAULT PROCESSOR_PPC603
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using `MULTILIB_OPTIONS'.
+
+ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
+ the target makefile fragment or if none of the options listed in
+ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mcpu=powerpc" }
+
+/* These are not necessary when we pass -u to the assembler, and undefining
+ them saves a great deal of space in object files. */
+
+#undef ASM_OUTPUT_EXTERNAL
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
+{ rtx _symref = XEXP (DECL_RTL (DECL), 0); \
+ if ((TREE_CODE (DECL) == VAR_DECL \
+ || TREE_CODE (DECL) == FUNCTION_DECL) \
+ && (NAME)[strlen (NAME) - 1] != ']') \
+ { \
+ char *_name = (char *) permalloc (strlen (XSTR (_symref, 0)) + 5); \
+ strcpy (_name, XSTR (_symref, 0)); \
+ strcat (_name, TREE_CODE (DECL) == FUNCTION_DECL ? "[DS]" : "[RW]"); \
+ XSTR (_symref, 0) = _name; \
+ } \
+}
+
+/* These empty definitions get rid of the attempt to link in crt0.o
+ and any libraries like libc.a.
+ On BeOS the ld executable is actually a linker front end that first runs
+ the GNU linker with the -r option to generate a relocatable XCOFF output
+ file, and then runs Metrowork's linker (mwld) to generate a fully linked
+ executable. */
+
+#undef LIB_SPEC
+#define LIB_SPEC ""
+
+#undef LINK_SPEC
+#define LINK_SPEC ""
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+/* Text to write out after a CALL that may be replaced by glue code by
+ the loader. */
+
+#undef RS6000_CALL_GLUE
+#define RS6000_CALL_GLUE "cror 15,15,15"
+
+/* Struct alignments are done on 4 byte boundaries for all types. */
+#undef BIGGEST_FIELD_ALIGNMENT
+#define BIGGEST_FIELD_ALIGNMENT 32
diff --git a/gcc/config/rs6000/cygwin.h b/gcc/config/rs6000/cygwin.h
new file mode 100755
index 0000000..0ed448b
--- /dev/null
+++ b/gcc/config/rs6000/cygwin.h
@@ -0,0 +1,67 @@
+/* Operating system specific defines to be used when targeting GCC for
+ hosting on Windows NT 3.x, using the Cygnus API
+
+ This is different to the winnt.h file, since that is used
+ to build GCC for use with a windows style library and tool
+ set, winnt.h uses the Microsoft tools to do that.
+
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Ugly hack */
+#include "rs6000/win-nt.h"
+
+
+#ifdef CPP_PREDEFINES
+#undef CPP_PREDEFINES
+#endif
+
+#define CPP_PREDEFINES "-D_WIN32 -DWINNT -D__CYGWIN__ -D__CYGWIN32__ -DPOSIX \
+ -D_POWER -D_ARCH_PPC -D__PPC__ -Asystem(winnt) -Acpu(powerpc) -Amachine(powerpc)"
+
+#undef CPP_SPEC
+#define CPP_SPEC "-remap %{posix: -D_POSIX_SOURCE} %(cpp_cpu)"
+
+/* We have to dynamic link to get to the system DLLs. All of libc, libm and
+ the Unix stuff is in cygwin.dll. The import library is called
+ 'libcygwin.a'. For Windows applications, include more libraries, but
+ always include kernel32. We'd like to specific subsystem windows to
+ ld, but that doesn't work just yet. */
+
+#undef LIB_SPEC
+#define LIB_SPEC "-lcygwin %{mwindows:-luser32 -lgdi32 -lcomdlg32} -lkernel32"
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{v:-V}"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "crti%O%s crt0%O%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtn%O%s"
+
+#define PTRDIFF_TYPE "int"
+#define WCHAR_UNSIGNED 1
+#define WCHAR_TYPE_SIZE 16
+#define WCHAR_TYPE "short unsigned int"
+
+#define DBX_DEBUGGING_INFO
+#undef SDB_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
diff --git a/gcc/config/rs6000/eabi-ci.asm b/gcc/config/rs6000/eabi-ci.asm
new file mode 100755
index 0000000..da3914c
--- /dev/null
+++ b/gcc/config/rs6000/eabi-ci.asm
@@ -0,0 +1,131 @@
+# crti.s for eabi
+
+# Copyright (C) 1996 Free Software Foundation, Inc.
+# Written By Michael Meissner
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# In addition to the permissions in the GNU General Public License, the
+# Free Software Foundation gives you unlimited permission to link the
+# compiled version of this file with other programs, and to distribute
+# those programs without any restriction coming from the use of this
+# file. (The General Public License restrictions do apply in other
+# respects; for example, they cover modification of the file, and
+# distribution when not linked into another program.)
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# As a special exception, if you link this library with files
+# compiled with GCC to produce an executable, this does not cause
+# the resulting executable to be covered by the GNU General Public License.
+# This exception does not however invalidate any other reasons why
+# the executable file might be covered by the GNU General Public License.
+#
+
+# This file just supplies labeled starting points for the .got* and other
+# special sections. It is linked in first before other modules.
+
+ .file "crti.s"
+ .ident "GNU C crti.s"
+
+#include <ppc-asm.h>
+
+ .section ".got","aw"
+ .globl __GOT_START__
+ .type __GOT_START__,@object
+__GOT_START__:
+
+ .section ".got1","aw"
+ .globl __GOT1_START__
+ .type __GOT1_START__,@object
+__GOT1_START__:
+
+ .section ".got2","aw"
+ .globl __GOT2_START__
+ .type __GOT2_START__,@object
+__GOT2_START__:
+
+ .section ".fixup","aw"
+ .globl __FIXUP_START__
+ .type __FIXUP_START__,@object
+__FIXUP_START__:
+
+ .section ".ctors","aw"
+ .globl __CTOR_LIST__
+ .type __CTOR_LIST__,@object
+__CTOR_LIST__:
+
+# CYGNUS LOCAL vmakarov
+ .globl ___CTOR_LIST__ # add support for -fleading-underscore
+ .type ___CTOR_LIST__,@object
+___CTOR_LIST__:
+# END CYGNUS LOCAL
+
+ .section ".dtors","aw"
+ .globl __DTOR_LIST__
+ .type __DTOR_LIST__,@object
+__DTOR_LIST__:
+
+# CYGNUS LOCAL vmakarov
+ .globl ___DTOR_LIST__
+ .type ___DTOR_LIST__,@object
+___DTOR_LIST__:
+# END CYGNUS LOCAL
+
+ .section ".sdata","aw"
+ .globl __SDATA_START__
+ .type __SDATA_START__,@object
+ .weak _SDA_BASE_
+ .type _SDA_BASE_,@object
+__SDATA_START__:
+_SDA_BASE_:
+
+ .section ".sbss","aw",@nobits
+ .globl __SBSS_START__
+ .type __SBSS_START__,@object
+__SBSS_START__:
+
+ .section ".sdata2","a"
+ .weak _SDA2_BASE_
+ .type _SDA2_BASE_,@object
+ .globl __SDATA2_START__
+ .type __SDATA2_START__,@object
+__SDATA2_START__:
+_SDA2_BASE_:
+
+ .section ".sbss2","a"
+ .globl __SBSS2_START__
+ .type __SBSS2_START__,@object
+__SBSS2_START__:
+
+ .section ".gcc_except_table","aw"
+ .globl __EXCEPT_START__
+ .type __EXCEPT_START__,@object
+__EXCEPT_START__:
+
+# Head of __init function used for static constructors in Solaris
+ .section ".init","ax"
+ .align 2
+FUNC_START(__init)
+ stwu 1,-8(1)
+ mflr 0
+ stw 0,12(1)
+
+# Head of __fini function used for static destructors in Solaris
+ .section ".fini","ax"
+ .align 2
+FUNC_START(__fini)
+ stwu 1,-8(1)
+ mflr 0
+ stw 0,12(1)
diff --git a/gcc/config/rs6000/eabi-cn.asm b/gcc/config/rs6000/eabi-cn.asm
new file mode 100755
index 0000000..9456762
--- /dev/null
+++ b/gcc/config/rs6000/eabi-cn.asm
@@ -0,0 +1,121 @@
+# crtn.s for eabi
+
+# Copyright (C) 1996 Free Software Foundation, Inc.
+# Written By Michael Meissner
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# In addition to the permissions in the GNU General Public License, the
+# Free Software Foundation gives you unlimited permission to link the
+# compiled version of this file with other programs, and to distribute
+# those programs without any restriction coming from the use of this
+# file. (The General Public License restrictions do apply in other
+# respects; for example, they cover modification of the file, and
+# distribution when not linked into another program.)
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# As a special exception, if you link this library with files
+# compiled with GCC to produce an executable, this does not cause
+# the resulting executable to be covered by the GNU General Public License.
+# This exception does not however invalidate any other reasons why
+# the executable file might be covered by the GNU General Public License.
+#
+
+# This file just supplies labeled ending points for the .got* and other
+# special sections. It is linked in last after other modules.
+
+ .file "crtn.s"
+ .ident "GNU C crtn.s"
+
+ .section ".got","aw"
+ .globl __GOT_END__
+ .type __GOT_END__,@object
+__GOT_END__:
+
+ .section ".got1","aw"
+ .globl __GOT1_END__
+ .type __GOT1_END__,@object
+__GOT1_END__:
+
+ .section ".got2","aw"
+ .globl __GOT2_END__
+ .type __GOT2_END__,@object
+__GOT2_END__:
+
+ .section ".fixup","aw"
+ .globl __FIXUP_END__
+ .type __FIXUP_END__,@object
+__FIXUP_END__:
+
+ .section ".ctors","aw"
+ .globl __CTOR_END__
+ .type __CTOR_END__,@object
+__CTOR_END__:
+
+# CYGNUS LOCAL vmakarov
+ .globl ___CTOR_END__ # add support for -fleading-underscore
+ .type ___CTOR_END__,@object
+___CTOR_END__:
+# END CYGNUS LOCAL
+
+ .section ".dtors","aw"
+ .globl __DTOR_END__
+ .type __DTOR_END__,@object
+__DTOR_END__:
+
+# CYGNUS LOCAL vmakarov
+ .globl ___DTOR_END__
+ .type ___DTOR_END__,@object
+___DTOR_END__:
+# END CYGNUS LOCAL
+
+ .section ".sdata","aw"
+ .globl __SDATA_END__
+ .type __SDATA_END__,@object
+__SDATA_END__:
+
+ .section ".sbss","aw",@nobits
+ .globl __SBSS_END__
+ .type __SBSS_END__,@object
+__SBSS_END__:
+
+ .section ".sdata2","a"
+ .globl __SDATA2_END__
+ .type __SDATA2_END__,@object
+__SDATA2_END__:
+
+ .section ".sbss2","a"
+ .globl __SBSS2_END__
+ .type __SBSS2_END__,@object
+__SBSS2_END__:
+
+ .section ".gcc_except_table","aw"
+ .globl __EXCEPT_END__
+ .type __EXCEPT_END__,@object
+__EXCEPT_END__:
+
+# Tail of __init used for static constructors in Solaris
+ .section ".init","ax"
+ lwz 0,12(1)
+ mtlr 0
+ addi 1,1,8
+ blr
+
+# Tail of __fini used for static destructors in Solaris
+ .section ".fini","ax"
+ lwz 0,12(1)
+ mtlr 0
+ addi 1,1,8
+ blr
diff --git a/gcc/config/rs6000/eabi-ctors.c b/gcc/config/rs6000/eabi-ctors.c
new file mode 100755
index 0000000..ebc23de
--- /dev/null
+++ b/gcc/config/rs6000/eabi-ctors.c
@@ -0,0 +1,92 @@
+/* Stripped down support to run global constructors and destructors on
+ embedded PowerPC systems.
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by Michael Meissner (meissner@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+
+/* Declare a pointer to void function type. */
+
+typedef void (*func_ptr) (void);
+
+/* Declare the set of symbols use as begin and end markers for the lists
+ of global object constructors and global object destructors. */
+
+extern func_ptr __CTOR_LIST__[];
+extern func_ptr __CTOR_END__ [];
+extern func_ptr __DTOR_LIST__[];
+extern func_ptr __DTOR_END__ [];
+
+extern void __do_global_ctors (void);
+extern void __do_global_dtors (void);
+
+extern void __init (), __fini ();
+
+/* The Solaris linker seems to incorrectly relocate PC relative relocations
+ to a different section (ie, calls to __init, __fini), so avoid it by
+ using a function pointer. */
+static void (*init_ptr) (void) = __init;
+static void (*fini_ptr) (void) = __fini;
+
+void (*__atexit)(func_ptr);
+
+/* Call all global constructors */
+void
+__do_global_ctors (void)
+{
+ func_ptr *ptr = &__CTOR_LIST__[0];
+ func_ptr *end = &__CTOR_END__[0];
+
+ if (__atexit)
+ __atexit (__do_global_dtors);
+
+ /* Call the constructors collected in the .ctors section. */
+ for ( ; ptr != end; ptr++)
+ if (*ptr)
+ (*ptr)();
+
+ /* Call the initialization function in the .init section. */
+ (*init_ptr) ();
+}
+
+/* Call all global destructors */
+void
+__do_global_dtors (void)
+{
+ func_ptr *ptr = &__DTOR_END__[0] - 1;
+ func_ptr *start = &__DTOR_LIST__[0];
+
+ /* Call the termination function in the .fini section. */
+ (*fini_ptr) ();
+
+ /* Call the destructors collected in the .dtors section. Run
+ the destructors in reverse order. */
+ for ( ; ptr >= start; ptr--)
+ if (*ptr)
+ (*ptr)();
+}
+
diff --git a/gcc/config/rs6000/eabi.asm b/gcc/config/rs6000/eabi.asm
new file mode 100755
index 0000000..803105f
--- /dev/null
+++ b/gcc/config/rs6000/eabi.asm
@@ -0,0 +1,575 @@
+/*
+ * special support for eabi
+ *
+ * Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
+ * Written By Michael Meissner
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * In addition to the permissions in the GNU General Public License, the
+ * Free Software Foundation gives you unlimited permission to link the
+ * compiled version of this file with other programs, and to distribute
+ * those programs without any restriction coming from the use of this
+ * file. (The General Public License restrictions do apply in other
+ * respects; for example, they cover modification of the file, and
+ * distribution when not linked into another program.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * As a special exception, if you link this library with files
+ * compiled with GCC to produce an executable, this does not cause
+ * the resulting executable to be covered by the GNU General Public License.
+ * This exception does not however invalidate any other reasons why
+ * the executable file might be covered by the GNU General Public License.
+ */
+
+/* Do any initializations needed for the eabi environment */
+
+ .file "eabi.asm"
+ .section ".text"
+ #include "ppc-asm.h"
+
+ .section ".got2","aw"
+ .align 2
+.LCTOC1 = . /* +32768 */
+
+/* Table of addresses */
+.Ltable = .-.LCTOC1
+ .long .LCTOC1 /* address we are really at */
+
+.Lsda = .-.LCTOC1
+ .long _SDA_BASE_ /* address of the first small data area */
+
+.Lsdas = .-.LCTOC1
+ .long __SDATA_START__ /* start of .sdata/.sbss section */
+
+.Lsdae = .-.LCTOC1
+ .long __SBSS_END__ /* end of .sdata/.sbss section */
+
+.Lsda2 = .-.LCTOC1
+ .long _SDA2_BASE_ /* address of the second small data area */
+
+.Lsda2s = .-.LCTOC1
+ .long __SDATA2_START__ /* start of .sdata2/.sbss2 section */
+
+.Lsda2e = .-.LCTOC1
+ .long __SBSS2_END__ /* end of .sdata2/.sbss2 section */
+
+#ifdef _RELOCATABLE
+.Lgots = .-.LCTOC1
+ .long __GOT_START__ /* Global offset table start */
+
+.Lgotm1 = .-.LCTOC1
+ .long _GLOBAL_OFFSET_TABLE_-4 /* end of GOT ptrs before BLCL + 3 reserved words */
+
+.Lgotm2 = .-.LCTOC1
+ .long _GLOBAL_OFFSET_TABLE_+12 /* start of GOT ptrs after BLCL + 3 reserved words */
+
+.Lgote = .-.LCTOC1
+ .long __GOT_END__ /* Global offset table end */
+
+.Lgot2s = .-.LCTOC1
+ .long __GOT2_START__ /* -mrelocatable GOT pointers start */
+
+.Lgot2e = .-.LCTOC1
+ .long __GOT2_END__ /* -mrelocatable GOT pointers end */
+
+.Lfixups = .-.LCTOC1
+ .long __FIXUP_START__ /* start of .fixup section */
+
+.Lfixupe = .-.LCTOC1
+ .long __FIXUP_END__ /* end of .fixup section */
+
+.Lctors = .-.LCTOC1
+ .long __CTOR_LIST__ /* start of .ctor section */
+
+.Lctore = .-.LCTOC1
+ .long __CTOR_END__ /* end of .ctor section */
+
+.Ldtors = .-.LCTOC1
+ .long __DTOR_LIST__ /* start of .dtor section */
+
+.Ldtore = .-.LCTOC1
+ .long __DTOR_END__ /* end of .dtor section */
+
+.Lexcepts = .-.LCTOC1
+ .long __EXCEPT_START__ /* start of .gcc_except_table section */
+
+.Lexcepte = .-.LCTOC1
+ .long __EXCEPT_END__ /* end of .gcc_except_table section */
+
+.Linit = .-.LCTOC1
+ .long .Linit_p /* address of variable to say we've been called */
+
+ .text
+ .align 2
+.Lptr:
+ .long .LCTOC1-.Laddr /* PC relative pointer to .got2 */
+#endif
+
+ .data
+ .align 2
+.Linit_p:
+ .long 0
+
+ .text
+
+/* CYGNUS LOCAL vmakarov */
+#if 0
+/* END CYGNUS LOCAL */
+FUNC_START(__eabi)
+/* CYGNUS LOCAL vmakarov */
+#endif
+ /* Don't use FUNC_NAME here, this name doesn't depend on
+ -fleading-underscore. */
+ .globl __eabi
+ .type __eabi@function
+__eabi:
+/* END CYGNUS LOCAL */
+
+/* Eliminate -mrelocatable code if not -mrelocatable, so that this file can
+ be assembled with other assemblers than GAS, such as the Solaris PowerPC
+ assembler. */
+
+#ifndef _RELOCATABLE
+ addis 10,0,.Linit_p@ha /* init flag */
+ addis 11,0,.LCTOC1@ha /* load address of .LCTOC1 */
+ lwz 9,.Linit_p@l(10) /* init flag */
+ addi 11,11,.LCTOC1@l
+ cmplwi 2,9,0 /* init flag != 0? */
+ bnelr 2 /* return now, if we've been called already */
+ stw 1,.Linit_p@l(10) /* store a non-zero value in the done flag */
+
+#else /* -mrelocatable */
+ mflr 0
+ bl .Laddr /* get current address */
+.Laddr:
+ mflr 12 /* real address of .Laddr */
+ lwz 11,(.Lptr-.Laddr)(12) /* linker generated address of .LCTOC1 */
+ add 11,11,12 /* correct to real pointer */
+ lwz 12,.Ltable(11) /* get linker's idea of where .Laddr is */
+ lwz 10,.Linit(11) /* address of init flag */
+ subf. 12,12,11 /* calculate difference */
+ lwzx 9,10,12 /* done flag */
+ cmplwi 2,9,0 /* init flag != 0? */
+ mtlr 0 /* restore in case branch was taken */
+ bnelr 2 /* return now, if we've been called already */
+ stwx 1,10,12 /* store a non-zero value in the done flag */
+ beq+ 0,.Lsdata /* skip if we don't need to relocate */
+
+/* We need to relocate the .got2 pointers. */
+
+ lwz 3,.Lgot2s(11) /* GOT2 pointers start */
+ lwz 4,.Lgot2e(11) /* GOT2 pointers end */
+ add 3,12,3 /* adjust pointers */
+ add 4,12,4
+ bl FUNC_NAME(__eabi_convert) /* convert pointers in .got2 section */
+
+/* Fixup the .ctor section for static constructors */
+
+ lwz 3,.Lctors(11) /* constructors pointers start */
+ lwz 4,.Lctore(11) /* constructors pointers end */
+ bl FUNC_NAME(__eabi_convert) /* convert constructors */
+
+/* Fixup the .dtor section for static destructors */
+
+ lwz 3,.Ldtors(11) /* destructors pointers start */
+ lwz 4,.Ldtore(11) /* destructors pointers end */
+ bl FUNC_NAME(__eabi_convert) /* convert destructors */
+
+/* Fixup the .gcc_except_table section for G++ exceptions */
+
+ lwz 3,.Lexcepts(11) /* exception table pointers start */
+ lwz 4,.Lexcepte(11) /* exception table pointers end */
+ bl FUNC_NAME(__eabi_convert) /* convert exceptions */
+
+/* Fixup the addresses in the GOT below _GLOBAL_OFFSET_TABLE_-4 */
+
+ lwz 3,.Lgots(11) /* GOT table pointers start */
+ lwz 4,.Lgotm1(11) /* GOT table pointers below _GLOBAL_OFFSET_TABLE-4 */
+ bl FUNC_NAME(__eabi_convert) /* convert lower GOT */
+
+/* Fixup the addresses in the GOT above _GLOBAL_OFFSET_TABLE_+12 */
+
+ lwz 3,.Lgotm2(11) /* GOT table pointers above _GLOBAL_OFFSET_TABLE+12 */
+ lwz 4,.Lgote(11) /* GOT table pointers end */
+ bl FUNC_NAME(__eabi_convert) /* convert lower GOT */
+
+/* Fixup any user initialized pointers now (the compiler drops pointers to */
+/* each of the relocs that it does in the .fixup section). */
+
+.Lfix:
+ lwz 3,.Lfixups(11) /* fixup pointers start */
+ lwz 4,.Lfixupe(11) /* fixup pointers end */
+ bl FUNC_NAME(__eabi_uconvert) /* convert user initialized pointers */
+
+.Lsdata:
+ mtlr 0 /* restore link register */
+#endif /* _RELOCATABLE */
+
+/* Only load up register 13 if there is a .sdata and/or .sbss section */
+ lwz 3,.Lsdas(11) /* start of .sdata/.sbss section */
+ lwz 4,.Lsdae(11) /* end of .sdata/.sbss section */
+ cmpw 1,3,4 /* .sdata/.sbss section non-empty? */
+ beq- 1,.Lsda2l /* skip loading r13 */
+
+ lwz 13,.Lsda(11) /* load r13 with _SDA_BASE_ address */
+
+/* Only load up register 2 if there is a .sdata2 and/or .sbss2 section */
+
+.Lsda2l:
+ lwz 3,.Lsda2s(11) /* start of .sdata/.sbss section */
+ lwz 4,.Lsda2e(11) /* end of .sdata/.sbss section */
+ cmpw 1,3,4 /* .sdata/.sbss section non-empty? */
+ beq+ 1,.Ldone /* skip loading r2 */
+
+ lwz 2,.Lsda2(11) /* load r2 with _SDA2_BASE_ address */
+
+/* Done adjusting pointers, return by way of doing the C++ global constructors. */
+
+.Ldone:
+ b FUNC_NAME(__do_global_ctors) /* do any C++ global constructors (which returns to caller) */
+/* CYGNUS LOCAL vmakarov */
+#if 0
+/* END CYGNUS LOCAL */
+FUNC_END(__eabi)
+/* CYGNUS LOCAL vmakarov */
+#endif
+.L.end:
+ .size __eabi,.L.end-__eabi
+/* END CYGNUS LOCAL */
+
+/* Special subroutine to convert a bunch of pointers directly.
+ r0 has original link register
+ r3 has low pointer to convert
+ r4 has high pointer to convert
+ r5 .. r10 are scratch registers
+ r11 has the address of .LCTOC1 in it.
+ r12 has the value to add to each pointer
+ r13 .. r31 are unchanged */
+
+FUNC_START(__eabi_convert)
+ cmplw 1,3,4 /* any pointers to convert? */
+ subf 5,3,4 /* calculate number of words to convert */
+ bclr 4,4 /* return if no pointers */
+
+ srawi 5,5,2
+ addi 3,3,-4 /* start-4 for use with lwzu */
+ mtctr 5
+
+.Lcvt:
+ lwzu 6,4(3) /* pointer to convert */
+ cmpi 0,6,0
+ beq- .Lcvt2 /* if pointer is null, don't convert */
+
+ add 6,6,12 /* convert pointer */
+ stw 6,0(3)
+.Lcvt2:
+ bdnz+ .Lcvt
+ blr
+
+FUNC_END(__eabi_convert)
+
+/* Special subroutine to convert the pointers the user has initialized. The
+ compiler has placed the address of the initialized pointer into the .fixup
+ section.
+
+ r0 has original link register
+ r3 has low pointer to convert
+ r4 has high pointer to convert
+ r5 .. r10 are scratch registers
+ r11 has the address of .LCTOC1 in it.
+ r12 has the value to add to each pointer
+ r13 .. r31 are unchanged */
+
+FUNC_START(__eabi_uconvert)
+ cmplw 1,3,4 /* any pointers to convert? */
+ subf 5,3,4 /* calculate number of words to convert */
+ bclr 4,4 /* return if no pointers */
+
+ srawi 5,5,2
+ addi 3,3,-4 /* start-4 for use with lwzu */
+ mtctr 5
+
+.Lucvt:
+ lwzu 6,4(3) /* next pointer to pointer to convert */
+ add 6,6,12 /* adjust pointer */
+ lwz 7,0(6) /* get the pointer it points to */
+ stw 6,0(3) /* store adjusted pointer */
+ add 7,7,12 /* adjust */
+ stw 7,0(6)
+ bdnz+ .Lucvt
+ blr
+
+FUNC_END(__eabi_uconvert)
+
+/* Routines for saving floating point registers, called by the compiler. */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the floating point save area. */
+
+FUNC_START(_savefpr_14) stfd 14,-144(11) /* save fp registers */
+FUNC_START(_savefpr_15) stfd 15,-136(11)
+FUNC_START(_savefpr_16) stfd 16,-128(11)
+FUNC_START(_savefpr_17) stfd 17,-120(11)
+FUNC_START(_savefpr_18) stfd 18,-112(11)
+FUNC_START(_savefpr_19) stfd 19,-104(11)
+FUNC_START(_savefpr_20) stfd 20,-96(11)
+FUNC_START(_savefpr_21) stfd 21,-88(11)
+FUNC_START(_savefpr_22) stfd 22,-80(11)
+FUNC_START(_savefpr_23) stfd 23,-72(11)
+FUNC_START(_savefpr_24) stfd 24,-64(11)
+FUNC_START(_savefpr_25) stfd 25,-56(11)
+FUNC_START(_savefpr_26) stfd 26,-48(11)
+FUNC_START(_savefpr_27) stfd 27,-40(11)
+FUNC_START(_savefpr_28) stfd 28,-32(11)
+FUNC_START(_savefpr_29) stfd 29,-24(11)
+FUNC_START(_savefpr_30) stfd 30,-16(11)
+FUNC_START(_savefpr_31) stfd 31,-8(11)
+ blr
+FUNC_END(_savefpr_31)
+FUNC_END(_savefpr_30)
+FUNC_END(_savefpr_29)
+FUNC_END(_savefpr_28)
+FUNC_END(_savefpr_27)
+FUNC_END(_savefpr_26)
+FUNC_END(_savefpr_25)
+FUNC_END(_savefpr_24)
+FUNC_END(_savefpr_23)
+FUNC_END(_savefpr_22)
+FUNC_END(_savefpr_21)
+FUNC_END(_savefpr_20)
+FUNC_END(_savefpr_19)
+FUNC_END(_savefpr_18)
+FUNC_END(_savefpr_17)
+FUNC_END(_savefpr_16)
+FUNC_END(_savefpr_15)
+FUNC_END(_savefpr_14)
+
+/* Routines for saving integer registers, called by the compiler. */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer save area. */
+
+FUNC_START(_savegpr_14) stw 14,-72(11) /* save gp registers */
+FUNC_START(_savegpr_15) stw 15,-68(11)
+FUNC_START(_savegpr_16) stw 16,-64(11)
+FUNC_START(_savegpr_17) stw 17,-60(11)
+FUNC_START(_savegpr_18) stw 18,-56(11)
+FUNC_START(_savegpr_19) stw 19,-52(11)
+FUNC_START(_savegpr_20) stw 20,-48(11)
+FUNC_START(_savegpr_21) stw 21,-44(11)
+FUNC_START(_savegpr_22) stw 22,-40(11)
+FUNC_START(_savegpr_23) stw 23,-36(11)
+FUNC_START(_savegpr_24) stw 24,-32(11)
+FUNC_START(_savegpr_25) stw 25,-28(11)
+FUNC_START(_savegpr_26) stw 26,-24(11)
+FUNC_START(_savegpr_27) stw 27,-20(11)
+FUNC_START(_savegpr_28) stw 28,-16(11)
+FUNC_START(_savegpr_29) stw 29,-12(11)
+FUNC_START(_savegpr_30) stw 30,-8(11)
+FUNC_START(_savegpr_31) stw 31,-4(11)
+ blr
+FUNC_END(_savegpr_31)
+FUNC_END(_savegpr_30)
+FUNC_END(_savegpr_29)
+FUNC_END(_savegpr_28)
+FUNC_END(_savegpr_27)
+FUNC_END(_savegpr_26)
+FUNC_END(_savegpr_25)
+FUNC_END(_savegpr_24)
+FUNC_END(_savegpr_23)
+FUNC_END(_savegpr_22)
+FUNC_END(_savegpr_21)
+FUNC_END(_savegpr_20)
+FUNC_END(_savegpr_19)
+FUNC_END(_savegpr_18)
+FUNC_END(_savegpr_17)
+FUNC_END(_savegpr_16)
+FUNC_END(_savegpr_15)
+FUNC_END(_savegpr_14)
+
+/* Routines for restoring floating point registers, called by the compiler. */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the floating point save area. */
+
+FUNC_START(_restfpr_14) lfd 14,-144(11) /* restore fp registers */
+FUNC_START(_restfpr_15) lfd 15,-136(11)
+FUNC_START(_restfpr_16) lfd 16,-128(11)
+FUNC_START(_restfpr_17) lfd 17,-120(11)
+FUNC_START(_restfpr_18) lfd 18,-112(11)
+FUNC_START(_restfpr_19) lfd 19,-104(11)
+FUNC_START(_restfpr_20) lfd 20,-96(11)
+FUNC_START(_restfpr_21) lfd 21,-88(11)
+FUNC_START(_restfpr_22) lfd 22,-80(11)
+FUNC_START(_restfpr_23) lfd 23,-72(11)
+FUNC_START(_restfpr_24) lfd 24,-64(11)
+FUNC_START(_restfpr_25) lfd 25,-56(11)
+FUNC_START(_restfpr_26) lfd 26,-48(11)
+FUNC_START(_restfpr_27) lfd 27,-40(11)
+FUNC_START(_restfpr_28) lfd 28,-32(11)
+FUNC_START(_restfpr_29) lfd 29,-24(11)
+FUNC_START(_restfpr_30) lfd 30,-16(11)
+FUNC_START(_restfpr_31) lfd 31,-8(11)
+ blr
+FUNC_END(_restfpr_31)
+FUNC_END(_restfpr_30)
+FUNC_END(_restfpr_29)
+FUNC_END(_restfpr_28)
+FUNC_END(_restfpr_27)
+FUNC_END(_restfpr_26)
+FUNC_END(_restfpr_25)
+FUNC_END(_restfpr_24)
+FUNC_END(_restfpr_23)
+FUNC_END(_restfpr_22)
+FUNC_END(_restfpr_21)
+FUNC_END(_restfpr_20)
+FUNC_END(_restfpr_19)
+FUNC_END(_restfpr_18)
+FUNC_END(_restfpr_17)
+FUNC_END(_restfpr_16)
+FUNC_END(_restfpr_15)
+FUNC_END(_restfpr_14)
+
+/* Routines for restoring integer registers, called by the compiler. */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer restore area. */
+
+FUNC_START(_restgpr_14) lwz 14,-72(11) /* restore gp registers */
+FUNC_START(_restgpr_15) lwz 15,-68(11)
+FUNC_START(_restgpr_16) lwz 16,-64(11)
+FUNC_START(_restgpr_17) lwz 17,-60(11)
+FUNC_START(_restgpr_18) lwz 18,-56(11)
+FUNC_START(_restgpr_19) lwz 19,-52(11)
+FUNC_START(_restgpr_20) lwz 20,-48(11)
+FUNC_START(_restgpr_21) lwz 21,-44(11)
+FUNC_START(_restgpr_22) lwz 22,-40(11)
+FUNC_START(_restgpr_23) lwz 23,-36(11)
+FUNC_START(_restgpr_24) lwz 24,-32(11)
+FUNC_START(_restgpr_25) lwz 25,-28(11)
+FUNC_START(_restgpr_26) lwz 26,-24(11)
+FUNC_START(_restgpr_27) lwz 27,-20(11)
+FUNC_START(_restgpr_28) lwz 28,-16(11)
+FUNC_START(_restgpr_29) lwz 29,-12(11)
+FUNC_START(_restgpr_30) lwz 30,-8(11)
+FUNC_START(_restgpr_31) lwz 31,-4(11)
+ blr
+FUNC_END(_restgpr_31)
+FUNC_END(_restgpr_30)
+FUNC_END(_restgpr_29)
+FUNC_END(_restgpr_28)
+FUNC_END(_restgpr_27)
+FUNC_END(_restgpr_26)
+FUNC_END(_restgpr_25)
+FUNC_END(_restgpr_24)
+FUNC_END(_restgpr_23)
+FUNC_END(_restgpr_22)
+FUNC_END(_restgpr_21)
+FUNC_END(_restgpr_20)
+FUNC_END(_restgpr_19)
+FUNC_END(_restgpr_18)
+FUNC_END(_restgpr_17)
+FUNC_END(_restgpr_16)
+FUNC_END(_restgpr_15)
+FUNC_END(_restgpr_14)
+
+/* Routines for restoring floating point registers, called by the compiler. */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the floating point save area. */
+/* In addition to restoring the fp registers, it will return to the caller's */
+/* caller */
+
+FUNC_START(_restfpr_14_x) lfd 14,-144(11) /* restore fp registers */
+FUNC_START(_restfpr_15_x) lfd 15,-136(11)
+FUNC_START(_restfpr_16_x) lfd 16,-128(11)
+FUNC_START(_restfpr_17_x) lfd 17,-120(11)
+FUNC_START(_restfpr_18_x) lfd 18,-112(11)
+FUNC_START(_restfpr_19_x) lfd 19,-104(11)
+FUNC_START(_restfpr_20_x) lfd 20,-96(11)
+FUNC_START(_restfpr_21_x) lfd 21,-88(11)
+FUNC_START(_restfpr_22_x) lfd 22,-80(11)
+FUNC_START(_restfpr_23_x) lfd 23,-72(11)
+FUNC_START(_restfpr_24_x) lfd 24,-64(11)
+FUNC_START(_restfpr_25_x) lfd 25,-56(11)
+FUNC_START(_restfpr_26_x) lfd 26,-48(11)
+FUNC_START(_restfpr_27_x) lfd 27,-40(11)
+FUNC_START(_restfpr_28_x) lfd 28,-32(11)
+FUNC_START(_restfpr_29_x) lfd 29,-24(11)
+FUNC_START(_restfpr_30_x) lfd 30,-16(11)
+FUNC_START(_restfpr_31_x) lwz 0,4(11)
+ lfd 31,-8(11)
+ mtlr 0
+ mr 1,11
+ blr
+FUNC_END(_restfpr_31_x)
+FUNC_END(_restfpr_30_x)
+FUNC_END(_restfpr_29_x)
+FUNC_END(_restfpr_28_x)
+FUNC_END(_restfpr_27_x)
+FUNC_END(_restfpr_26_x)
+FUNC_END(_restfpr_25_x)
+FUNC_END(_restfpr_24_x)
+FUNC_END(_restfpr_23_x)
+FUNC_END(_restfpr_22_x)
+FUNC_END(_restfpr_21_x)
+FUNC_END(_restfpr_20_x)
+FUNC_END(_restfpr_19_x)
+FUNC_END(_restfpr_18_x)
+FUNC_END(_restfpr_17_x)
+FUNC_END(_restfpr_16_x)
+FUNC_END(_restfpr_15_x)
+FUNC_END(_restfpr_14_x)
+
+/* Routines for restoring integer registers, called by the compiler. */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer restore area. */
+
+FUNC_START(_restgpr_14_x) lwz 14,-72(11) /* restore gp registers */
+FUNC_START(_restgpr_15_x) lwz 15,-68(11)
+FUNC_START(_restgpr_16_x) lwz 16,-64(11)
+FUNC_START(_restgpr_17_x) lwz 17,-60(11)
+FUNC_START(_restgpr_18_x) lwz 18,-56(11)
+FUNC_START(_restgpr_19_x) lwz 19,-52(11)
+FUNC_START(_restgpr_20_x) lwz 20,-48(11)
+FUNC_START(_restgpr_21_x) lwz 21,-44(11)
+FUNC_START(_restgpr_22_x) lwz 22,-40(11)
+FUNC_START(_restgpr_23_x) lwz 23,-36(11)
+FUNC_START(_restgpr_24_x) lwz 24,-32(11)
+FUNC_START(_restgpr_25_x) lwz 25,-28(11)
+FUNC_START(_restgpr_26_x) lwz 26,-24(11)
+FUNC_START(_restgpr_27_x) lwz 27,-20(11)
+FUNC_START(_restgpr_28_x) lwz 28,-16(11)
+FUNC_START(_restgpr_29_x) lwz 29,-12(11)
+FUNC_START(_restgpr_30_x) lwz 30,-8(11)
+FUNC_START(_restgpr_31_x) lwz 0,4(11)
+ lwz 31,-4(11)
+ mtlr 0
+ mr 1,11
+ blr
+FUNC_END(_restgpr_31_x)
+FUNC_END(_restgpr_30_x)
+FUNC_END(_restgpr_29_x)
+FUNC_END(_restgpr_28_x)
+FUNC_END(_restgpr_27_x)
+FUNC_END(_restgpr_26_x)
+FUNC_END(_restgpr_25_x)
+FUNC_END(_restgpr_24_x)
+FUNC_END(_restgpr_23_x)
+FUNC_END(_restgpr_22_x)
+FUNC_END(_restgpr_21_x)
+FUNC_END(_restgpr_20_x)
+FUNC_END(_restgpr_19_x)
+FUNC_END(_restgpr_18_x)
+FUNC_END(_restgpr_17_x)
+FUNC_END(_restgpr_16_x)
+FUNC_END(_restgpr_15_x)
+FUNC_END(_restgpr_14_x)
diff --git a/gcc/config/rs6000/eabi.h b/gcc/config/rs6000/eabi.h
new file mode 100755
index 0000000..1c225ea
--- /dev/null
+++ b/gcc/config/rs6000/eabi.h
@@ -0,0 +1,40 @@
+/* Core target definitions for GNU compiler
+ for IBM RS/6000 PowerPC targeted to embedded ELF systems.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "rs6000/sysv4.h"
+
+/* Add -meabi to target flags */
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_EABI)
+
+/* Invoke an initializer function to set up the GOT */
+#define NAME__MAIN "__eabi"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (PowerPC Embedded)");
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-DPPC -D__embedded__ -Asystem(embedded) -Acpu(powerpc) -Amachine(powerpc)"
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mbig", "mcall-sysv" }
diff --git a/gcc/config/rs6000/eabiaix.h b/gcc/config/rs6000/eabiaix.h
new file mode 100755
index 0000000..5cfd890
--- /dev/null
+++ b/gcc/config/rs6000/eabiaix.h
@@ -0,0 +1,41 @@
+/* Embedded ELF system support, using old AIX based calling sequence.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "rs6000/eabi.h"
+
+/* Default ABI to use */
+#undef RS6000_ABI_NAME
+#define RS6000_ABI_NAME "aix"
+
+#undef CPP_SYSV_DEFAULT_SPEC
+#define CPP_SYSV_DEFAULT_SPEC "-D_CALL_AIX"
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using `MULTILIB_OPTIONS'.
+
+ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
+ the target makefile fragment or if none of the options listed in
+ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mbig", "mcall-aix" }
diff --git a/gcc/config/rs6000/eabile.h b/gcc/config/rs6000/eabile.h
new file mode 100755
index 0000000..97e2b7c
--- /dev/null
+++ b/gcc/config/rs6000/eabile.h
@@ -0,0 +1,49 @@
+/* Core target definitions for GNU compiler for PowerPC targeted to
+ little endian embedded ELF systems.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "rs6000/eabi.h"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_LITTLE_ENDIAN | MASK_EABI)
+
+#undef CPP_ENDIAN_DEFAULT_SPEC
+#define CPP_ENDIAN_DEFAULT_SPEC "%(cpp_endian_little)"
+
+#undef CC1_ENDIAN_DEFAULT_SPEC
+#define CC1_ENDIAN_DEFAULT_SPEC "%(cc1_endian_little)"
+
+#undef LINK_TARGET_SPEC
+#define LINK_TARGET_SPEC "\
+%{mbig: -oformat elf32-powerpc } %{mbig-endian: -oformat elf32-powerpc } \
+%{!mlittle: %{!mlittle-endian: %{!mbig: %{!mbig-endian: %{mcall-linux: -oformat elf32-powerpc}}}}}"
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using `MULTILIB_OPTIONS'.
+
+ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
+ the target makefile fragment or if none of the options listed in
+ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mlittle", "mcall-sysv" }
diff --git a/gcc/config/rs6000/eabilesim.h b/gcc/config/rs6000/eabilesim.h
new file mode 100755
index 0000000..7ced05c
--- /dev/null
+++ b/gcc/config/rs6000/eabilesim.h
@@ -0,0 +1,46 @@
+/* Support for GCC on simulated PowerPC systems targeted to embedded ELF
+ systems.
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "rs6000/eabile.h"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (PowerPC Simulated)");
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-DPPC -D__embedded__ -D__simulator__ -Asystem(embedded) -Asystem(simulator) -Acpu(powerpc) -Amachine(powerpc)"
+
+/* Make the simulator the default */
+#undef LIB_DEFAULT_SPEC
+#define LIB_DEFAULT_SPEC "%(lib_sim)"
+
+#undef STARTFILE_DEFAULT_SPEC
+#define STARTFILE_DEFAULT_SPEC "%(startfile_sim)"
+
+#undef ENDFILE_DEFAULT_SPEC
+#define ENDFILE_DEFAULT_SPEC "%(endfile_sim)"
+
+#undef LINK_START_DEFAULT_SPEC
+#define LINK_START_DEFAULT_SPEC "%(link_start_sim)"
+
+#undef LINK_OS_DEFAULT_SPEC
+#define LINK_OS_DEFAULT_SPEC "%(link_start_sim)"
diff --git a/gcc/config/rs6000/eabisim.h b/gcc/config/rs6000/eabisim.h
new file mode 100755
index 0000000..0fc590b
--- /dev/null
+++ b/gcc/config/rs6000/eabisim.h
@@ -0,0 +1,46 @@
+/* Support for GCC on simulated PowerPC systems targeted to embedded ELF
+ systems.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "rs6000/eabi.h"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (PowerPC Simulated)");
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-DPPC -D__embedded__ -D__simulator__ -Asystem(embedded) -Asystem(simulator) -Acpu(powerpc) -Amachine(powerpc)"
+
+/* Make the simulator the default */
+#undef LIB_DEFAULT_SPEC
+#define LIB_DEFAULT_SPEC "%(lib_sim)"
+
+#undef STARTFILE_DEFAULT_SPEC
+#define STARTFILE_DEFAULT_SPEC "%(startfile_sim)"
+
+#undef ENDFILE_DEFAULT_SPEC
+#define ENDFILE_DEFAULT_SPEC "%(endfile_sim)"
+
+#undef LINK_START_DEFAULT_SPEC
+#define LINK_START_DEFAULT_SPEC "%(link_start_sim)"
+
+#undef LINK_OS_DEFAULT_SPEC
+#define LINK_OS_DEFAULT_SPEC "%(link_os_sim)"
diff --git a/gcc/config/rs6000/linux.h b/gcc/config/rs6000/linux.h
new file mode 100755
index 0000000..cdc4dc0
--- /dev/null
+++ b/gcc/config/rs6000/linux.h
@@ -0,0 +1,76 @@
+/* Definitions of target machine for GNU compiler,
+ for IBM RS/6000 running AIX version 3.1.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Michael Meissner (meissner@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "rs6000/sysv4.h"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-DPPC -D__ELF__ -Dunix -Dlinux -Dpowerpc -Asystem(unix) -Asystem(linux) -Acpu(powerpc) -Amachine(powerpc)"
+
+#undef CPP_OS_DEFAULT_SPEC
+#define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)"
+
+#undef LINK_SPEC
+#define LINK_SPEC "-m elf32ppc %{G*} %{shared:-shared} \
+ %{!shared: \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /lib/ld.so.1}} \
+ %{static:-static}}"
+
+#undef LIB_DEFAULT_SPEC
+#define LIB_DEFAULT_SPEC "%(lib_linux)"
+
+#undef STARTFILE_DEFAULT_SPEC
+#define STARTFILE_DEFAULT_SPEC "%(startfile_linux)"
+
+#undef ENDFILE_DEFAULT_SPEC
+#define ENDFILE_DEFAULT_SPEC "%(endfile_linux)"
+
+#undef LINK_START_DEFAULT_SPEC
+#define LINK_START_DEFAULT_SPEC "%(link_start_linux)"
+
+#undef LINK_OS_DEFAULT_SPEC
+#define LINK_OS_DEFAULT_SPEC "%(link_os_linux)"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (PowerPC GNU/Linux)");
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using `MULTILIB_OPTIONS'.
+
+ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
+ the target makefile fragment or if none of the options listed in
+ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mbig", "mcall-linux" }
+
+#undef DEFAULT_VTABLE_THUNKS
+#ifndef USE_GNULIBC_1
+#define DEFAULT_VTABLE_THUNKS 1
+#endif
+
+#undef JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION 0
diff --git a/gcc/config/rs6000/lynx.h b/gcc/config/rs6000/lynx.h
new file mode 100755
index 0000000..e2fe633
--- /dev/null
+++ b/gcc/config/rs6000/lynx.h
@@ -0,0 +1,104 @@
+/* Definitions for Rs6000 running LynxOS.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by David Henkel-Wallace, Cygnus Support (gumby@cygnus.com)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <lynx.h>
+
+/* Definitions we want to override with those from rs6000.h: */
+#undef LIB_SPEC
+#undef PTRDIFF_TYPE
+#undef WCHAR_TYPE
+#undef WCHAR_TYPE_SIZE
+#undef ASM_FILE_START
+#undef EXTRA_SECTIONS
+#undef READONLY_DATA_SECTION
+#undef EXTRA_SECTION_FUNCTIONS
+#undef SELECT_RTX_SECTION
+#undef SELECT_SECTION
+#undef USER_LABEL_PREFIX
+#undef ASM_OUTPUT_LABELREF
+#undef ASM_OUTPUT_INTERNAL_LABEL
+#undef ASM_GENERATE_INTERNAL_LABEL
+#undef ASM_OUTPUT_COMMON
+#undef ASM_OUTPUT_LOCAL
+#undef ASM_OUTPUT_CONSTRUCTOR
+#undef ASM_OUTPUT_DESTRUCTOR
+#undef CTORS_SECTION_FUNCTION
+#undef DTORS_SECTION_FUNCTION
+
+#undef SDB_DEBUGGING_INFO
+#undef DBX_DEBUGGING_INFO
+#undef PREFERRED_DEBUGGING_TYPE
+
+#undef FUNCTION_PROFILER
+
+#include <rs6000/rs6000.h>
+
+/* LynxOS has signed chars, regardless of what most R/S 6000 systems do */
+#undef DEFAULT_SIGNED_CHAR
+#define DEFAULT_SIGNED_CHAR 1
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Acpu(rs6000) -Amachine(rs6000) -Asystem(lynx) -Asystem(unix) -DLynx -D_IBMR2 -Dunix -Drs6000 -Dlynx -DLYNX"
+
+#undef LINK_SPEC
+#define LINK_SPEC "-T0x10001000 -H0x1000 -D0x20000000 -btextro -bhalt:4 -bnodelcsect -bnso -bro -bnoglink %{v} %{b*}"
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{mthreads:-L/lib/thread/} \
+ %{msystem-v:-lc_v -lm.v} \
+ %{!msystem-v:%{mposix:-lc_p} -lc -lm}"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{p:%{mthreads:thread/pinit.o%s}%{!mthreads:pinit.o%s}}%{!p:%{msystem-v:vinit.o%s -e_start}%{!msystem-v:%{mthreads:thread/init.o%s}%{!mthreads:init.o%s}}}"
+
+#undef ENDFILE_SPEC
+
+/* This can become more refined as we have more powerpc options. */
+#undef ASM_SPEC
+#define ASM_SPEC "-u %(asm_cpu)"
+
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ {"threads", MASK_THREADS}, \
+ {"posix", MASK_POSIX}, \
+ {"system-v", MASK_SYSTEM_V},
+
+#undef SUBTARGET_OVERRIDE_OPTIONS
+#define SUBTARGET_OVERRIDE_OPTIONS \
+do { \
+ if (TARGET_SYSTEM_V && profile_flag) \
+ warning ("-msystem-v and -p are incompatible"); \
+ if (TARGET_SYSTEM_V && TARGET_THREADS) \
+ warning ("-msystem-v and -mthreads are incompatible"); \
+} while (0)
+
+/* For collect2 */
+#define OBJECT_FORMAT_NONE
+#undef OBJECT_FORMAT_COFF
+#undef OBJECT_FORMAT_ROSE
+#undef MD_EXEC_PREFIX
+#undef REAL_LD_FILE_NAME
+#undef REAL_NM_FILE_NAME
+#undef REAL_STRIP_FILE_NAME
+
+/* LynxOS doesn't have mcount. */
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER(file, profile_label_no)
diff --git a/gcc/config/rs6000/mach.h b/gcc/config/rs6000/mach.h
new file mode 100755
index 0000000..bb4e8b4
--- /dev/null
+++ b/gcc/config/rs6000/mach.h
@@ -0,0 +1,42 @@
+/* Definitions of target machine for GNU compiler,
+ for IBM RS/6000 running MACH.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Contributed by Richard Kenner (kenner@nyu.edu)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define TARGET_AIX 0
+
+#include "rs6000/rs6000.h"
+
+/* We don't define AIX under MACH; instead we define `unix'. */
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Drios -D_IBMR2 -Dunix -Asystem(unix) -Asystem(mach) -Acpu(rs6000) -Amachine(rs6000)"
+
+/* Define different binder options for MACH. */
+#undef LINK_SPEC
+#define LINK_SPEC \
+ "-T0x10000000 -D0x20000000 -K %{!nostdlib:%{!r*:%{!e*:-e __start}}} \
+ -bnoso -berrmsg -btextro -bhalt:4 -bnodelcsect"
+
+/* MACH doesn't have atexit. */
+#undef HAVE_ATEXIT
+
+/* Don't default to pcc-struct-return, because gcc is the only compiler, and
+ we want to retain compatibility with older gcc versions. */
+#define DEFAULT_PCC_STRUCT_RETURN 0
diff --git a/gcc/config/rs6000/milli.exp b/gcc/config/rs6000/milli.exp
new file mode 100755
index 0000000..ea3a2b7
--- /dev/null
+++ b/gcc/config/rs6000/milli.exp
@@ -0,0 +1,7 @@
+#!
+__mulh 0x3100
+__mull 0x3180
+__divss 0x3200
+__divus 0x3280
+__quoss 0x3300
+__quous 0x3380
diff --git a/gcc/config/rs6000/netware.h b/gcc/config/rs6000/netware.h
new file mode 100755
index 0000000..61133b9
--- /dev/null
+++ b/gcc/config/rs6000/netware.h
@@ -0,0 +1,284 @@
+/* Core target definitions for GNU compiler
+ for IBM RS/6000 PowerPC running NetWare
+ Copyright (C) 1994, 1995, 1996, 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define TARGET_AIX 0
+
+#define CPP_DEFAULT_SPEC "-D_ARCH_PPC"
+
+#define ASM_DEFAULT_SPEC "-mppc"
+
+#include "rs6000/rs6000.h"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS)
+
+#undef PROCESSOR_DEFAULT
+#define PROCESSOR_DEFAULT PROCESSOR_PPC601
+
+/* Don't generate XCOFF debugging information. */
+
+#undef XCOFF_DEBUGGING_INFO
+
+/* Don't use the COFF object file format. */
+
+#undef OBJECT_FORMAT_COFF
+
+/* The XCOFF support uses weird symbol suffixes, which we don't want
+ for ELF. */
+
+#undef STRIP_NAME_ENCODING
+
+/* Don't bother to output .extern pseudo-ops. They are not needed by
+ ELF assemblers. */
+
+#undef ASM_OUTPUT_EXTERNAL
+
+/* Undefine some things which are defined by the generic svr4.h. */
+
+#undef ASM_FILE_END
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+#undef READONLY_DATA_SECTION
+#undef SELECT_SECTION
+#undef ASM_DECLARE_FUNCTION_NAME
+
+/* Use the regular svr4 definitions. */
+
+#include "svr4.h"
+#include "netware.h"
+
+/* Create a function descriptor when we declare a function name. This
+ is a mixture of the ASM_DECLARE_FUNCTION_NAME macros in rs6000.h
+ and svr4.h. The unmodified function name is used to name the
+ descriptor. The function name with an initial `.' is used to name
+ the code. */
+
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+ do { \
+ fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \
+ putc ('\n', FILE); \
+ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
+ if (TREE_PUBLIC (DECL)) \
+ { \
+ fprintf (FILE, "\t.globl ."); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } \
+ data_section (); \
+ ASM_OUTPUT_ALIGN (FILE, 2); \
+ ASM_OUTPUT_LABEL (FILE, NAME); \
+ fprintf (FILE, "\t.long ."); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ", __GOT0, 0\n"); \
+ text_section (); \
+ fprintf (FILE, "."); \
+ ASM_OUTPUT_LABEL (FILE, NAME); \
+ } while (0)
+
+/* We need to override the .size output in order to put a `.' before
+ the function name. */
+
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
+ do { \
+ if (!flag_inhibit_size_directive) \
+ { \
+ char label[256]; \
+ static int labelno; \
+ labelno++; \
+ ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, (FNAME)); \
+ fprintf (FILE, ","); \
+ assemble_name (FILE, label); \
+ fprintf (FILE, "-."); \
+ assemble_name (FILE, (FNAME)); \
+ putc ('\n', FILE); \
+ } \
+ } while (0)
+
+/* Use ELF style section commands. */
+
+#undef TEXT_SECTION_ASM_OP
+#define TEXT_SECTION_ASM_OP "\t.section\t\".text\""
+
+#undef DATA_SECTION_ASM_OP
+#define DATA_SECTION_ASM_OP "\t.section\t\".data\""
+
+/* Besides the usual ELF sections, we need a toc section. */
+
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_const, in_ctors, in_dtors, in_toc
+
+#undef EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS \
+ CONST_SECTION_FUNCTION \
+ CTORS_SECTION_FUNCTION \
+ DTORS_SECTION_FUNCTION \
+ TOC_SECTION_FUNCTION
+
+#define TOC_SECTION_FUNCTION \
+void \
+toc_section () \
+{ \
+ if (TARGET_MINIMAL_TOC) \
+ { \
+ static int toc_initialized = 0; \
+ \
+ if (! toc_initialized) \
+ { \
+ fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP); \
+ fprintf (asm_out_file, ".LCTOC0:\n"); \
+ fprintf (asm_out_file, "\t.tc .LCTOC1\n"); \
+ fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); \
+ fprintf (asm_out_file, ".LCTOC1:\n"); \
+ toc_initialized = 1; \
+ } \
+ } \
+ \
+ if (in_section != in_toc) \
+ { \
+ fprintf (asm_out_file, "%s\n", \
+ (TARGET_MINIMAL_TOC \
+ ? MINIMAL_TOC_SECTION_ASM_OP \
+ : TOC_SECTION_ASM_OP)); \
+ in_section = in_toc; \
+ } \
+}
+
+#define TOC_SECTION_ASM_OP "\t.section\t.got,\"aw\""
+#define MINIMAL_TOC_SECTION_ASM_OP "\t.section\t.got1,\"aw\""
+
+/* Use the TOC section for TOC entries. */
+
+#undef SELECT_RTX_SECTION
+#define SELECT_RTX_SECTION(MODE, X) \
+{ if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (X)) \
+ toc_section (); \
+ else \
+ const_section (); \
+}
+
+/* How to renumber registers for dbx and gdb. */
+
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+/* svr4.h overrides ASM_OUTPUT_INTERNAL_LABEL. */
+
+#undef ASM_OUTPUT_INTERNAL_LABEL_PREFIX
+#define ASM_OUTPUT_INTERNAL_LABEL_PREFIX(FILE,PREFIX) \
+ fprintf (FILE, ".%s", PREFIX)
+
+#undef ASM_SPEC
+#define ASM_SPEC "-u %(asm_cpu) \
+{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*}"
+/* This is the end of what might become sysv4.h. */
+
+/* Enable output of DBX (stabs) debugging information when asked for it. */
+
+#define DBX_DEBUGGING_INFO
+
+/* Prefer DBX (stabs) debugging information over the native (DWARF) format. */
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+/* Line numbers are relative to the current function. */
+
+#undef ASM_OUTPUT_SOURCE_LINE
+#define ASM_OUTPUT_SOURCE_LINE(file, line) \
+ { static int sym_lineno = 1; \
+ fprintf (file, ".stabn 68,0,%d,.LM%d-.%s\n.LM%d:\n",\
+ line, sym_lineno, \
+ XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0), \
+ sym_lineno); \
+ sym_lineno += 1; }
+
+/* But, to make this work, we have to output the stabs for the function
+ name *first*... */
+
+#define DBX_FUNCTION_FIRST
+
+/* We need to output LBRAC and RBRAC lines specially to include the
+ dot in from of the text symbol for a function. */
+
+#define DBX_OUTPUT_LBRAC(FILE, BUF) \
+do \
+ { \
+ fprintf (FILE, "%s %d,0,0,", ASM_STABN_OP, N_LBRAC); \
+ assemble_name (FILE, BUF); \
+ fprintf (FILE, "-."); \
+ assemble_name (asmfile, \
+ XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); \
+ fprintf (asmfile, "\n"); \
+ } \
+while (0)
+
+#define DBX_OUTPUT_RBRAC(FILE, BUF) \
+do \
+ { \
+ fprintf (FILE, "%s %d,0,0,", ASM_STABN_OP, N_RBRAC); \
+ assemble_name (FILE, BUF); \
+ fprintf (FILE, "-."); \
+ assemble_name (asmfile, \
+ XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); \
+ fprintf (asmfile, "\n"); \
+ } \
+while (0)
+
+/* We are using function descriptors, so the value of a function
+ symbol is in the .data section. However, we want the stabs entry
+ for that function to point at the actual function code in the .text
+ section, which we get by prefixing the symbol with a dot. */
+
+#define DBX_FINISH_SYMBOL(sym) \
+do { \
+ int line = 0; \
+ if (use_gnu_debug_info_extensions && sym != 0) \
+ line = DECL_SOURCE_LINE (sym); \
+ \
+ fprintf (asmfile, "\",%d,0,%d,", current_sym_code, line); \
+ if (current_sym_addr) \
+ { \
+ if (TREE_CODE (sym) == FUNCTION_DECL) \
+ fprintf (asmfile, "."); \
+ output_addr_const (asmfile, current_sym_addr); \
+ } \
+ else \
+ fprintf (asmfile, "%d", current_sym_value); \
+ putc ('\n', asmfile); \
+} while (0)
+
+/* This is the end of what might become sysv4dbx.h. */
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (PowerPC Netware)");
+
+/* FIXME: These should actually indicate PowerPC, when there is some
+ standard way of expressing that. */
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-DPPC D__netware__ -Asystem(netware) -Acpu(powerpc) -Amachine(powerpc)"
diff --git a/gcc/config/rs6000/nt-ci.asm b/gcc/config/rs6000/nt-ci.asm
new file mode 100755
index 0000000..67ca956
--- /dev/null
+++ b/gcc/config/rs6000/nt-ci.asm
@@ -0,0 +1,48 @@
+# crti.s for Windows NT
+
+# Copyright (C) 1996 Free Software Foundation, Inc.
+# Written By Michael Meissner
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# In addition to the permissions in the GNU General Public License, the
+# Free Software Foundation gives you unlimited permission to link the
+# compiled version of this file with other programs, and to distribute
+# those programs without any restriction coming from the use of this
+# file. (The General Public License restrictions do apply in other
+# respects; for example, they cover modification of the file, and
+# distribution when not linked into another program.)
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# As a special exception, if you link this library with files
+# compiled with GCC to produce an executable, this does not cause
+# the resulting executable to be covered by the GNU General Public License.
+# This exception does not however invalidate any other reasons why
+# the executable file might be covered by the GNU General Public License.
+#
+
+# This file just supplies labeled starting points for the static constructors
+# and destructors. It is linked in first before other modules.
+
+ .file "crti.s"
+ .ident "GNU C crti.s"
+
+ .section .ctors,"w"
+ .globl __CTOR_LIST__
+__CTOR_LIST__:
+
+ .section .dtors,"w"
+ .globl __DTOR_LIST__
+__DTOR_LIST__:
diff --git a/gcc/config/rs6000/nt-cn.asm b/gcc/config/rs6000/nt-cn.asm
new file mode 100755
index 0000000..dd6daf2
--- /dev/null
+++ b/gcc/config/rs6000/nt-cn.asm
@@ -0,0 +1,48 @@
+# crtn.s for Windows NT
+
+# Copyright (C) 1996 Free Software Foundation, Inc.
+# Written By Michael Meissner
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# In addition to the permissions in the GNU General Public License, the
+# Free Software Foundation gives you unlimited permission to link the
+# compiled version of this file with other programs, and to distribute
+# those programs without any restriction coming from the use of this
+# file. (The General Public License restrictions do apply in other
+# respects; for example, they cover modification of the file, and
+# distribution when not linked into another program.)
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# As a special exception, if you link this library with files
+# compiled with GCC to produce an executable, this does not cause
+# the resulting executable to be covered by the GNU General Public License.
+# This exception does not however invalidate any other reasons why
+# the executable file might be covered by the GNU General Public License.
+#
+
+# This file just supplies labeled ending points for the static constructors
+# and destructors. It is linked in last after other modules.
+
+ .file "crtn.s"
+ .ident "GNU C crtn.s"
+
+ .section .ctors,"w"
+ .globl __CTOR_END__
+__CTOR_END__:
+
+ .section .dtors,"w"
+ .globl __DTOR_END__
+__DTOR_END__:
diff --git a/gcc/config/rs6000/ntstack.asm b/gcc/config/rs6000/ntstack.asm
new file mode 100755
index 0000000..aa4179e
--- /dev/null
+++ b/gcc/config/rs6000/ntstack.asm
@@ -0,0 +1,42 @@
+# Allocate stack for NT, inserting stack probes every 4k pages
+
+ .file "ntstack.asm"
+
+# Setup MS Structured-Exception-Handling
+ .pdata
+ .align 2
+ .ualong ..__allocate_stack,__allocate_stack.e,0,0,__allocate_stack.b
+
+# Switch to the relocation section
+ .reldata
+ .globl __allocate_stack
+ .globl ..__allocate_stack
+__allocate_stack:
+ .ualong ..__allocate_stack,.toc
+
+ .text
+ .align 2
+..__allocate_stack:
+ .function ..__allocate_stack
+__allocate_stack.b:
+ addi 3,3,15 # round up to 16 byte alignment
+ lwz 0,0(1) # old stack link
+ rlwinm 3,3,0,0,28
+ srawi. 4,3,12 # get # of pages to check
+ neg 3,3 # negate so we can use stwux
+ bgt- 0,.Lcheck
+ stwux 0,1,3 # small request, just decrement and return
+ blr
+
+.Lcheck:
+ mtctr 4 # number of pages to check
+ mr 5,1 # tmp pointer
+.Lloop:
+ lwzu 6,-4096(5) # touch the page
+ bdnz+ .Lloop # and loop back
+
+ stwux 0,1,3 # update stack pointer
+ blr
+
+__allocate_stack.e:
+FE_MOT_RESVD..__allocate_stack:
diff --git a/gcc/config/rs6000/powerpc.h b/gcc/config/rs6000/powerpc.h
new file mode 100755
index 0000000..9f1ffd6
--- /dev/null
+++ b/gcc/config/rs6000/powerpc.h
@@ -0,0 +1,61 @@
+/* Definitions of target machine for GNU compiler,
+ for IBM RS/6000 PowerPC running AIX version 3.2.
+ Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Contributed by David Edelsohn (edelsohn@npac.syr.edu).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#include "rs6000/rs6000.h"
+
+#undef ASM_SPEC
+#define ASM_SPEC "-u %(asm_cpu)"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D_IBMR2 -D_POWER -D_AIX -D_AIX32 \
+-Asystem(unix) -Asystem(aix) -Acpu(powerpc) -Amachine(powerpc)"
+
+#undef CPP_DEFAULT_SPEC
+#define CPP_DEFAULT_SPEC "-D_ARCH_PPC"
+
+#undef ASM_DEFAULT_SPEC
+#define ASM_DEFAULT_SPEC "-mppc"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS)
+
+#undef PROCESSOR_DEFAULT
+#define PROCESSOR_DEFAULT PROCESSOR_PPC601
+
+/* These are not necessary when we pass -u to the assembler, and undefining
+ them saves a great deal of space in object files. */
+
+#undef ASM_OUTPUT_EXTERNAL
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
+{ rtx _symref = XEXP (DECL_RTL (DECL), 0); \
+ if ((TREE_CODE (DECL) == VAR_DECL \
+ || TREE_CODE (DECL) == FUNCTION_DECL) \
+ && (NAME)[strlen (NAME) - 1] != ']') \
+ { \
+ char *_name = (char *) permalloc (strlen (XSTR (_symref, 0)) + 5); \
+ strcpy (_name, XSTR (_symref, 0)); \
+ strcat (_name, TREE_CODE (DECL) == FUNCTION_DECL ? "[DS]" : "[RW]"); \
+ XSTR (_symref, 0) = _name; \
+ } \
+}
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
new file mode 100755
index 0000000..53ef3f1
--- /dev/null
+++ b/gcc/config/rs6000/rs6000.c
@@ -0,0 +1,7156 @@
+/* Subroutines used for code generation on IBM RS/6000.
+ Copyright (C) 1991, 93-8, 1999 Free Software Foundation, Inc.
+ Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-flags.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "recog.h"
+#include "expr.h"
+#include "obstack.h"
+#include "tree.h"
+#include "except.h"
+#include "function.h"
+#include "output.h"
+#include "toplev.h"
+
+#ifndef TARGET_NO_PROTOTYPE
+#define TARGET_NO_PROTOTYPE 0
+#endif
+
+extern char *language_string;
+extern int profile_block_flag;
+
+#define min(A,B) ((A) < (B) ? (A) : (B))
+#define max(A,B) ((A) > (B) ? (A) : (B))
+
+/* Target cpu type */
+
+enum processor_type rs6000_cpu;
+struct rs6000_cpu_select rs6000_select[3] =
+{
+ /* switch name, tune arch */
+ { (char *)0, "--with-cpu=", 1, 1 },
+ { (char *)0, "-mcpu=", 1, 1 },
+ { (char *)0, "-mtune=", 1, 0 },
+};
+
+/* Set to non-zero by "fix" operation to indicate that itrunc and
+ uitrunc must be defined. */
+
+int rs6000_trunc_used;
+
+/* Set to non-zero once they have been defined. */
+
+static int trunc_defined;
+
+/* Set to non-zero once AIX common-mode calls have been defined. */
+static int common_mode_defined;
+
+/* Save information from a "cmpxx" operation until the branch or scc is
+ emitted. */
+rtx rs6000_compare_op0, rs6000_compare_op1;
+int rs6000_compare_fp_p;
+
+/* CYGNUS LOCAL -- vmakarov */
+/* Override for BRANCH_COST */
+char *rs6000_branch_cost_string;
+int rs6000_branch_cost = BRANCH_COST_DEFAULT;
+/* END CYGNUS LOCAL */
+
+#ifdef USING_SVR4_H
+/* Label number of label created for -mrelocatable, to call to so we can
+ get the address of the GOT section */
+int rs6000_pic_labelno;
+int rs6000_pic_func_labelno;
+
+/* Which abi to adhere to */
+char *rs6000_abi_name = RS6000_ABI_NAME;
+
+/* Semantics of the small data area */
+enum rs6000_sdata_type rs6000_sdata = SDATA_DATA;
+
+/* Which small data model to use */
+char *rs6000_sdata_name = (char *)0;
+#endif
+
+/* Whether a System V.4 varargs area was created. */
+int rs6000_sysv_varargs_p;
+
+/* ABI enumeration available for subtarget to use. */
+enum rs6000_abi rs6000_current_abi;
+
+/* Offset & size for fpmem stack locations used for converting between
+ float and integral types. */
+int rs6000_fpmem_offset;
+int rs6000_fpmem_size;
+
+/* Debug flags */
+char *rs6000_debug_name;
+int rs6000_debug_stack; /* debug stack applications */
+int rs6000_debug_arg; /* debug argument handling */
+
+/* Flag to say the TOC is initialized */
+int toc_initialized;
+
+
+/* Default register names. */
+char rs6000_reg_names[][8] =
+{
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", "10", "11", "12", "13", "14", "15",
+ "16", "17", "18", "19", "20", "21", "22", "23",
+ "24", "25", "26", "27", "28", "29", "30", "31",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", "10", "11", "12", "13", "14", "15",
+ "16", "17", "18", "19", "20", "21", "22", "23",
+ "24", "25", "26", "27", "28", "29", "30", "31",
+ "mq", "lr", "ctr","ap",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "fpmem"
+};
+
+#ifdef TARGET_REGNAMES
+static char alt_reg_names[][8] =
+{
+ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
+ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+ "%r16", "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
+ "%r24", "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31",
+ "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
+ "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
+ "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
+ "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
+ "mq", "lr", "ctr", "ap",
+ "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
+ "fpmem"
+};
+#endif
+
+#ifndef MASK_STRICT_ALIGN
+#define MASK_STRICT_ALIGN 0
+#endif
+
+/* Override command line options. Mostly we process the processor
+ type and sometimes adjust other TARGET_ options. */
+
+void
+rs6000_override_options (default_cpu)
+ char *default_cpu;
+{
+ size_t i, j;
+ struct rs6000_cpu_select *ptr;
+
+ /* Simplify the entries below by making a mask for any POWER
+ variant and any PowerPC variant. */
+
+#define POWER_MASKS (MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING)
+#define POWERPC_MASKS (MASK_POWERPC | MASK_PPC_GPOPT \
+ | MASK_PPC_GFXOPT | MASK_POWERPC64)
+#define POWERPC_OPT_MASKS (MASK_PPC_GPOPT | MASK_PPC_GFXOPT)
+
+ static struct ptt
+ {
+ char *name; /* Canonical processor name. */
+ enum processor_type processor; /* Processor type enum value. */
+ int target_enable; /* Target flags to enable. */
+ int target_disable; /* Target flags to disable. */
+ } processor_target_table[]
+ = {{"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_MASKS},
+ {"power", PROCESSOR_POWER,
+ MASK_POWER | MASK_MULTIPLE | MASK_STRING,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"power2", PROCESSOR_POWER,
+ MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
+ POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"powerpc", PROCESSOR_POWERPC,
+ MASK_POWERPC | MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"rios", PROCESSOR_RIOS1,
+ MASK_POWER | MASK_MULTIPLE | MASK_STRING,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"rios1", PROCESSOR_RIOS1,
+ MASK_POWER | MASK_MULTIPLE | MASK_STRING,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"rsc", PROCESSOR_PPC601,
+ MASK_POWER | MASK_MULTIPLE | MASK_STRING,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"rsc1", PROCESSOR_PPC601,
+ MASK_POWER | MASK_MULTIPLE | MASK_STRING,
+ MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"rios2", PROCESSOR_RIOS2,
+ MASK_POWER | MASK_MULTIPLE | MASK_STRING | MASK_POWER2,
+ POWERPC_MASKS | MASK_NEW_MNEMONICS},
+ {"401", PROCESSOR_PPC403,
+ MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"403", PROCESSOR_PPC403,
+ MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS | MASK_STRICT_ALIGN,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"505", PROCESSOR_MPCCORE,
+ MASK_POWERPC | MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"601", PROCESSOR_PPC601,
+ MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_MULTIPLE | MASK_STRING,
+ MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"602", PROCESSOR_PPC603,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"603", PROCESSOR_PPC603,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"603e", PROCESSOR_PPC603,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"ec603e", PROCESSOR_PPC603,
+ MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"604", PROCESSOR_PPC604,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"604e", PROCESSOR_PPC604e,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"620", PROCESSOR_PPC620,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT},
+ {"740", PROCESSOR_PPC750,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"750", PROCESSOR_PPC750,
+ MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+ {"801", PROCESSOR_MPCCORE,
+ MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"821", PROCESSOR_MPCCORE,
+ MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"823", PROCESSOR_MPCCORE,
+ MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+ {"860", PROCESSOR_MPCCORE,
+ MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
+ POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}};
+
+ size_t ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
+
+ int multiple = TARGET_MULTIPLE; /* save current -mmultiple/-mno-multiple status */
+ int string = TARGET_STRING; /* save current -mstring/-mno-string status */
+
+ profile_block_flag = 0;
+
+ /* Identify the processor type */
+ rs6000_select[0].string = default_cpu;
+ rs6000_cpu = PROCESSOR_DEFAULT;
+
+ for (i = 0; i < sizeof (rs6000_select) / sizeof (rs6000_select[0]); i++)
+ {
+ ptr = &rs6000_select[i];
+ if (ptr->string != (char *)0 && ptr->string[0] != '\0')
+ {
+ for (j = 0; j < ptt_size; j++)
+ if (! strcmp (ptr->string, processor_target_table[j].name))
+ {
+ if (ptr->set_tune_p)
+ rs6000_cpu = processor_target_table[j].processor;
+
+ if (ptr->set_arch_p)
+ {
+ target_flags |= processor_target_table[j].target_enable;
+ target_flags &= ~processor_target_table[j].target_disable;
+ }
+ break;
+ }
+
+ if (i == ptt_size)
+ error ("bad value (%s) for %s switch", ptr->string, ptr->name);
+ }
+ }
+
+ /* If we are optimizing big endian systems for space, use the
+ store multiple instructions. */
+ if (BYTES_BIG_ENDIAN && optimize_size)
+ target_flags |= MASK_MULTIPLE;
+
+ /* If -mmultiple or -mno-multiple was explicitly used, don't
+ override with the processor default */
+ if (TARGET_MULTIPLE_SET)
+ target_flags = (target_flags & ~MASK_MULTIPLE) | multiple;
+
+ /* If -mstring or -mno-string was explicitly used, don't
+ override with the processor default */
+ if (TARGET_STRING_SET)
+ target_flags = (target_flags & ~MASK_STRING) | string;
+
+ /* Don't allow -mmultiple or -mstring on little endian systems unless the cpu
+ is a 750, because the hardware doesn't support the instructions used in
+ little endian mode, and causes an alignment trap. The 750 does not cause
+ an alignment trap (except when the target is unaligned). */
+
+ if (!BYTES_BIG_ENDIAN && rs6000_cpu != PROCESSOR_PPC750)
+ {
+ if (TARGET_MULTIPLE)
+ {
+ target_flags &= ~MASK_MULTIPLE;
+ if (TARGET_MULTIPLE_SET)
+ warning ("-mmultiple is not supported on little endian systems");
+ }
+
+ if (TARGET_STRING)
+ {
+ target_flags &= ~MASK_STRING;
+ if (TARGET_STRING_SET)
+ warning ("-mstring is not supported on little endian systems");
+ }
+ }
+
+ if (flag_pic && (DEFAULT_ABI == ABI_AIX))
+ {
+ warning ("-f%s ignored for AIX (all code is position independent)",
+ (flag_pic > 1) ? "PIC" : "pic");
+ flag_pic = 0;
+ }
+
+ /* Set debug flags */
+ if (rs6000_debug_name)
+ {
+ if (!strcmp (rs6000_debug_name, "all"))
+ rs6000_debug_stack = rs6000_debug_arg = 1;
+ else if (!strcmp (rs6000_debug_name, "stack"))
+ rs6000_debug_stack = 1;
+ else if (!strcmp (rs6000_debug_name, "arg"))
+ rs6000_debug_arg = 1;
+ else
+ error ("Unknown -mdebug-%s switch", rs6000_debug_name);
+ }
+
+#ifdef TARGET_REGNAMES
+ /* If the user desires alternate register names, copy in the alternate names
+ now. */
+ if (TARGET_REGNAMES)
+ bcopy ((char *)alt_reg_names, (char *)rs6000_reg_names, sizeof (rs6000_reg_names));
+#endif
+
+ /* CYGNUS LOCAL -- vmakarov */
+ /* Override BRANCH_COST if -mbranch-cost= */
+ if (rs6000_branch_cost_string)
+ rs6000_branch_cost = atoi (rs6000_branch_cost_string);
+ /* END CYGNUS LOCAL */
+
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+ SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+}
+
+void
+optimization_options (level, size)
+ int level;
+ int size ATTRIBUTE_UNUSED;
+{
+#ifdef HAVE_decrement_and_branch_on_count
+ /* When optimizing, enable use of BCT instruction. */
+ if (level >= 1)
+ flag_branch_on_count_reg = 1;
+#endif
+}
+
+/* Do anything needed at the start of the asm file. */
+
+void
+rs6000_file_start (file, default_cpu)
+ FILE *file;
+ char *default_cpu;
+{
+ size_t i;
+ char buffer[80];
+ char *start = buffer;
+ struct rs6000_cpu_select *ptr;
+
+ if (flag_verbose_asm)
+ {
+ sprintf (buffer, "\n%s rs6000/powerpc options:", ASM_COMMENT_START);
+ rs6000_select[0].string = default_cpu;
+
+ for (i = 0; i < sizeof (rs6000_select) / sizeof (rs6000_select[0]); i++)
+ {
+ ptr = &rs6000_select[i];
+ if (ptr->string != (char *)0 && ptr->string[0] != '\0')
+ {
+ fprintf (file, "%s %s%s", start, ptr->name, ptr->string);
+ start = "";
+ }
+ }
+
+#ifdef USING_SVR4_H
+ switch (rs6000_sdata)
+ {
+ case SDATA_NONE: fprintf (file, "%s -msdata=none", start); start = ""; break;
+ case SDATA_DATA: fprintf (file, "%s -msdata=data", start); start = ""; break;
+ case SDATA_SYSV: fprintf (file, "%s -msdata=sysv", start); start = ""; break;
+ case SDATA_EABI: fprintf (file, "%s -msdata=eabi", start); start = ""; break;
+ }
+
+ if (rs6000_sdata && g_switch_value)
+ {
+ fprintf (file, "%s -G %d", start, g_switch_value);
+ start = "";
+ }
+#endif
+
+ if (*start == '\0')
+ fputs ("\n", file);
+ }
+}
+
+
+/* Create a CONST_DOUBLE from a string. */
+
+struct rtx_def *
+rs6000_float_const (string, mode)
+ char *string;
+ enum machine_mode mode;
+{
+ REAL_VALUE_TYPE value = REAL_VALUE_ATOF (string, mode);
+ return immed_real_const_1 (value, mode);
+}
+
+/* Return non-zero if this function is known to have a null epilogue. */
+
+int
+direct_return ()
+{
+ if (reload_completed)
+ {
+ rs6000_stack_t *info = rs6000_stack_info ();
+
+ if (info->first_gp_reg_save == 32
+ && info->first_fp_reg_save == 64
+ && !info->lr_save_p
+ && !info->cr_save_p
+ && !info->push_p)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Returns 1 always. */
+
+int
+any_operand (op, mode)
+ register rtx op ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return 1;
+}
+
+/* Returns 1 if op is the count register */
+int
+count_register_operand(op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) != REG)
+ return 0;
+
+ if (REGNO (op) == COUNT_REGISTER_REGNUM)
+ return 1;
+
+ if (REGNO (op) > FIRST_PSEUDO_REGISTER)
+ return 1;
+
+ return 0;
+}
+
+/* Returns 1 if op is memory location for float/int conversions that masquerades
+ as a register. */
+int
+fpmem_operand(op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) != REG)
+ return 0;
+
+ if (FPMEM_REGNO_P (REGNO (op)))
+ return 1;
+
+#if 0
+ if (REGNO (op) > FIRST_PSEUDO_REGISTER)
+ return 1;
+#endif
+
+ return 0;
+}
+
+/* Return 1 if OP is a constant that can fit in a D field. */
+
+int
+short_cint_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return ((GET_CODE (op) == CONST_INT
+ && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) < 0x10000)
+ || GET_CODE (op) == CONSTANT_P_RTX);
+}
+
+/* Similar for a unsigned D field. */
+
+int
+u_short_cint_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return ((GET_CODE (op) == CONST_INT
+ && (INTVAL (op) & (~ (HOST_WIDE_INT) 0xffff)) == 0)
+ || GET_CODE (op) == CONSTANT_P_RTX);
+}
+
+/* Return 1 if OP is a CONST_INT that cannot fit in a signed D field. */
+
+int
+non_short_cint_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == CONST_INT
+ && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) >= 0x10000);
+}
+
+/* Returns 1 if OP is a register that is not special (i.e., not MQ,
+ ctr, or lr). */
+
+int
+gpc_reg_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return (register_operand (op, mode)
+ && (GET_CODE (op) != REG
+ || (REGNO (op) >= 67 && !FPMEM_REGNO_P (REGNO (op)))
+ || REGNO (op) < 64));
+}
+
+/* Returns 1 if OP is either a pseudo-register or a register denoting a
+ CR field. */
+
+int
+cc_reg_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return (register_operand (op, mode)
+ && (GET_CODE (op) != REG
+ || REGNO (op) >= FIRST_PSEUDO_REGISTER
+ || CR_REGNO_P (REGNO (op))));
+}
+
+/* Returns 1 if OP is either a pseudo-register or a register denoting a
+ CR field that isn't CR0. */
+
+int
+cc_reg_not_cr0_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return (register_operand (op, mode)
+ && (GET_CODE (op) != REG
+ || REGNO (op) >= FIRST_PSEUDO_REGISTER
+ || CR_REGNO_NOT_CR0_P (REGNO (op))));
+}
+
+/* Returns 1 if OP is either a constant integer valid for a D-field or a
+ non-special register. If a register, it must be in the proper mode unless
+ MODE is VOIDmode. */
+
+int
+reg_or_short_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return short_cint_operand (op, mode) || gpc_reg_operand (op, mode);
+}
+
+/* Similar, except check if the negation of the constant would be valid for
+ a D-field. */
+
+int
+reg_or_neg_short_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) == CONST_INT)
+ return CONST_OK_FOR_LETTER_P (INTVAL (op), 'P');
+
+ return gpc_reg_operand (op, mode);
+}
+
+/* Return 1 if the operand is either a register or an integer whose high-order
+ 16 bits are zero. */
+
+int
+reg_or_u_short_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return u_short_cint_operand (op, mode) || gpc_reg_operand (op, mode);
+}
+
+/* Return 1 is the operand is either a non-special register or ANY
+ constant integer. */
+
+int
+reg_or_cint_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return (GET_CODE (op) == CONST_INT
+ || GET_CODE (op) == CONSTANT_P_RTX
+ || gpc_reg_operand (op, mode));
+}
+
+/* Return 1 if the operand is an operand that can be loaded via the GOT */
+
+int
+got_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == SYMBOL_REF
+ || GET_CODE (op) == CONST
+ || GET_CODE (op) == LABEL_REF);
+}
+
+/* Return 1 if the operand is a simple references that can be loaded via
+ the GOT (labels involving addition aren't allowed). */
+
+int
+got_no_const_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF);
+}
+
+/* Return the number of instructions it takes to form a constant in an
+ integer register. */
+
+static int
+num_insns_constant_wide (value)
+ HOST_WIDE_INT value;
+{
+ /* signed constant loadable with {cal|addi} */
+ if (((unsigned HOST_WIDE_INT)value + 0x8000) < 0x10000)
+ return 1;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+ /* constant loadable with {cau|addis} */
+ else if ((value & 0xffff) == 0)
+ return 1;
+
+#else
+ /* constant loadable with {cau|addis} */
+ else if ((value & 0xffff) == 0 && (value & ~0xffffffff) == 0)
+ return 1;
+
+ else if (TARGET_64BIT)
+ {
+ HOST_WIDE_INT low = value & 0xffffffff;
+ HOST_WIDE_INT high = value >> 32;
+
+ if (high == 0 && (low & 0x80000000) == 0)
+ return 2;
+
+ else if (high == 0xffffffff && (low & 0x80000000) != 0)
+ return 2;
+
+ else if (!low)
+ return num_insns_constant_wide (high) + 1;
+
+ else
+ return (num_insns_constant_wide (high)
+ + num_insns_constant_wide (low) + 1);
+ }
+#endif
+
+ else
+ return 2;
+}
+
+int
+num_insns_constant (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) == CONST_INT)
+ return num_insns_constant_wide (INTVAL (op));
+
+ else if (GET_CODE (op) == CONST_DOUBLE && mode == SFmode)
+ {
+ long l;
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+ return num_insns_constant_wide ((HOST_WIDE_INT)l);
+ }
+
+ else if (GET_CODE (op) == CONST_DOUBLE)
+ {
+ HOST_WIDE_INT low;
+ HOST_WIDE_INT high;
+ long l[2];
+ REAL_VALUE_TYPE rv;
+ int endian = (WORDS_BIG_ENDIAN == 0);
+
+ if (mode == VOIDmode || mode == DImode)
+ {
+ high = CONST_DOUBLE_HIGH (op);
+ low = CONST_DOUBLE_LOW (op);
+ }
+ else
+ {
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
+ high = l[endian];
+ low = l[1 - endian];
+ }
+
+ if (TARGET_32BIT)
+ return (num_insns_constant_wide (low)
+ + num_insns_constant_wide (high));
+
+ else
+ {
+ if (high == 0 && (low & 0x80000000) == 0)
+ return num_insns_constant_wide (low);
+
+ else if (((high & 0xffffffff) == 0xffffffff)
+ && ((low & 0x80000000) != 0))
+ return num_insns_constant_wide (low);
+
+ else if (mask64_operand (op, mode))
+ return 2;
+
+ else if (low == 0)
+ return num_insns_constant_wide (high) + 1;
+
+ else
+ return (num_insns_constant_wide (high)
+ + num_insns_constant_wide (low) + 1);
+ }
+ }
+
+ else
+ abort ();
+}
+
+/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a register
+ with one instruction per word. We only do this if we can safely read
+ CONST_DOUBLE_{LOW,HIGH}. */
+
+int
+easy_fp_constant (op, mode)
+ register rtx op;
+ register enum machine_mode mode;
+{
+ if (GET_CODE (op) != CONST_DOUBLE
+ || GET_MODE (op) != mode
+ || (GET_MODE_CLASS (mode) != MODE_FLOAT && mode != DImode))
+ return 0;
+
+ /* Consider all constants with -msoft-float to be easy */
+ if (TARGET_SOFT_FLOAT && mode != DImode)
+ return 1;
+
+ /* If we are using V.4 style PIC, consider all constants to be hard */
+ if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS))
+ return 0;
+
+#ifdef TARGET_RELOCATABLE
+ /* Similarly if we are using -mrelocatable, consider all constants to be hard */
+ if (TARGET_RELOCATABLE)
+ return 0;
+#endif
+
+ if (mode == DFmode)
+ {
+ long k[2];
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
+
+ return (num_insns_constant_wide ((HOST_WIDE_INT)k[0]) == 1
+ && num_insns_constant_wide ((HOST_WIDE_INT)k[1]) == 1);
+ }
+
+ else if (mode == SFmode)
+ {
+ long l;
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+
+ return num_insns_constant_wide (l) == 1;
+ }
+
+ else if (mode == DImode)
+ return ((TARGET_64BIT
+ && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 0)
+ || (num_insns_constant (op, DImode) <= 2));
+
+ else
+ abort ();
+}
+
+/* Return 1 if the operand is in volatile memory. Note that during the
+ RTL generation phase, memory_operand does not return TRUE for
+ volatile memory references. So this function allows us to
+ recognize volatile references where its safe. */
+
+int
+volatile_mem_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) != MEM)
+ return 0;
+
+ if (!MEM_VOLATILE_P (op))
+ return 0;
+
+ if (mode != GET_MODE (op))
+ return 0;
+
+ if (reload_completed)
+ return memory_operand (op, mode);
+
+ if (reload_in_progress)
+ return strict_memory_address_p (mode, XEXP (op, 0));
+
+ return memory_address_p (mode, XEXP (op, 0));
+}
+
+/* Return 1 if the operand is an offsettable memory address. */
+
+int
+offsettable_addr_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return offsettable_address_p (reload_completed | reload_in_progress,
+ mode, op);
+}
+
+/* Return 1 if the operand is either an easy FP constant (see above) or
+ memory. */
+
+int
+mem_or_easy_const_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return memory_operand (op, mode) || easy_fp_constant (op, mode);
+}
+
+/* Return 1 if the operand is either a non-special register or an item
+ that can be used as the operand of an SI add insn. */
+
+int
+add_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return (reg_or_short_operand (op, mode)
+ || (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0));
+}
+
+/* Return 1 if OP is a constant but not a valid add_operand. */
+
+int
+non_add_cint_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == CONST_INT
+ && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) >= 0x10000
+ && (INTVAL (op) & 0xffff) != 0);
+}
+
+/* Return 1 if the operand is a non-special register or a constant that
+ can be used as the operand of an OR or XOR insn on the RS/6000. */
+
+int
+logical_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return (gpc_reg_operand (op, mode)
+ || (GET_CODE (op) == CONST_INT
+ && ((INTVAL (op) & (~ (HOST_WIDE_INT) 0xffff)) == 0
+ || (INTVAL (op) & 0xffff) == 0))
+ || GET_CODE (op) == CONSTANT_P_RTX);
+}
+
+/* Return 1 if C is a constant that is not a logical operand (as
+ above). */
+
+int
+non_logical_cint_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == CONST_INT
+ && (INTVAL (op) & (~ (HOST_WIDE_INT) 0xffff)) != 0
+ && (INTVAL (op) & 0xffff) != 0);
+}
+
+/* Return 1 if C is a constant that can be encoded in a mask on the
+ RS/6000. It is if there are no more than two 1->0 or 0->1 transitions.
+ Reject all ones and all zeros, since these should have been optimized
+ away and confuse the making of MB and ME. */
+
+int
+mask_constant (c)
+ register HOST_WIDE_INT c;
+{
+ int i;
+ int last_bit_value;
+ int transitions = 0;
+
+ if (c == 0 || c == ~0)
+ return 0;
+
+ last_bit_value = c & 1;
+
+ for (i = 1; i < 32; i++)
+ if (((c >>= 1) & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+
+ return transitions <= 2;
+}
+
+/* Return 1 if the operand is a constant that is a mask on the RS/6000. */
+
+int
+mask_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return GET_CODE (op) == CONST_INT && mask_constant (INTVAL (op));
+}
+
+/* Return 1 if the operand is a constant that is a PowerPC64 mask.
+ It is if there are no more than one 1->0 or 0->1 transitions.
+ Reject all ones and all zeros, since these should have been optimized
+ away and confuse the making of MB and ME. */
+
+int
+mask64_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) == CONST_INT)
+ {
+ HOST_WIDE_INT c = INTVAL (op);
+ int i;
+ int last_bit_value;
+ int transitions = 0;
+
+ if (c == 0 || c == ~0)
+ return 0;
+
+ last_bit_value = c & 1;
+
+ for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++)
+ if (((c >>= 1) & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+ /* Consider CONST_INT sign-extended. */
+ transitions += (last_bit_value != 1);
+#endif
+
+ return transitions <= 1;
+ }
+ else if (GET_CODE (op) == CONST_DOUBLE
+ && (mode == VOIDmode || mode == DImode))
+ {
+ HOST_WIDE_INT low = CONST_DOUBLE_LOW (op);
+#if HOST_BITS_PER_WIDE_INT == 32
+ HOST_WIDE_INT high = CONST_DOUBLE_HIGH (op);
+#endif
+ int i;
+ int last_bit_value;
+ int transitions = 0;
+
+ if ((low == 0
+#if HOST_BITS_PER_WIDE_INT == 32
+ && high == 0
+#endif
+ )
+ || (low == ~0
+#if HOST_BITS_PER_WIDE_INT == 32
+ && high == ~0
+#endif
+ ))
+ return 0;
+
+ last_bit_value = low & 1;
+
+ for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++)
+ if (((low >>= 1) & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+ if ((high & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+
+ for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++)
+ if (((high >>= 1) & 1) != last_bit_value)
+ last_bit_value ^= 1, transitions++;
+#endif
+
+ return transitions <= 1;
+ }
+ else
+ return 0;
+}
+
+/* Return 1 if the operand is either a non-special register or a constant
+ that can be used as the operand of a PowerPC64 logical AND insn. */
+
+int
+and64_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return (logical_operand (op, mode)
+ || mask64_operand (op, mode));
+}
+
+/* Return 1 if the operand is either a non-special register or a
+ constant that can be used as the operand of an RS/6000 logical AND insn. */
+
+int
+and_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return (logical_operand (op, mode)
+ || mask_operand (op, mode));
+}
+
+/* Return 1 if the operand is a general register or memory operand. */
+
+int
+reg_or_mem_operand (op, mode)
+ register rtx op;
+ register enum machine_mode mode;
+{
+ return (gpc_reg_operand (op, mode)
+ || memory_operand (op, mode)
+ || volatile_mem_operand (op, mode));
+}
+
+/* Return 1 if the operand is a general register or memory operand without
+ pre-inc or pre_dec which produces invalid form of PowerPC lwa
+ instruction. */
+
+int
+lwa_operand (op, mode)
+ register rtx op;
+ register enum machine_mode mode;
+{
+ rtx inner = op;
+
+ if (reload_completed && GET_CODE (inner) == SUBREG)
+ inner = SUBREG_REG (inner);
+
+ return gpc_reg_operand (inner, mode)
+ || (memory_operand (inner, mode)
+ && GET_CODE (XEXP (inner, 0)) != PRE_INC
+ && GET_CODE (XEXP (inner, 0)) != PRE_DEC);
+}
+
+/* Return 1 if the operand, used inside a MEM, is a valid first argument
+ to CALL. This is a SYMBOL_REF or a pseudo-register, which will be
+ forced to lr. */
+
+int
+call_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && GET_MODE (op) != mode)
+ return 0;
+
+ return (GET_CODE (op) == SYMBOL_REF
+ || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER));
+}
+
+
+/* Return 1 if the operand is a SYMBOL_REF for a function known to be in
+ this file. */
+
+int
+current_file_function_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == SYMBOL_REF
+ && (SYMBOL_REF_FLAG (op)
+ || op == XEXP (DECL_RTL (current_function_decl), 0)));
+}
+
+
+/* Return 1 if this operand is a valid input for a move insn. */
+
+int
+input_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ /* Memory is always valid. */
+ if (memory_operand (op, mode))
+ return 1;
+
+ /* For floating-point, easy constants are valid. */
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ && CONSTANT_P (op)
+ && easy_fp_constant (op, mode))
+ return 1;
+
+ /* Allow any integer constant. */
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && (GET_CODE (op) == CONST_INT
+ || GET_CODE (op) == CONSTANT_P_RTX
+ || GET_CODE (op) == CONST_DOUBLE))
+ return 1;
+
+ /* For floating-point or multi-word mode, the only remaining valid type
+ is a register. */
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ || GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ return register_operand (op, mode);
+
+ /* The only cases left are integral modes one word or smaller (we
+ do not get called for MODE_CC values). These can be in any
+ register. */
+ if (register_operand (op, mode))
+ return 1;
+
+ /* A SYMBOL_REF referring to the TOC is valid. */
+ if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (op))
+ return 1;
+
+ /* Windows NT allows SYMBOL_REFs and LABEL_REFs against the TOC
+ directly in the instruction stream */
+ if (DEFAULT_ABI == ABI_NT
+ && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF))
+ return 1;
+
+ /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region
+ to be valid. */
+ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST)
+ && small_data_operand (op, Pmode))
+ return 1;
+
+ return 0;
+}
+
+/* Return 1 for an operand in small memory on V.4/eabi */
+
+int
+small_data_operand (op, mode)
+ rtx op ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+#if TARGET_ELF
+ rtx sym_ref, const_part;
+
+ if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
+ return 0;
+
+ if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
+ return 0;
+
+ if (GET_CODE (op) == SYMBOL_REF)
+ sym_ref = op;
+
+ else if (GET_CODE (op) != CONST
+ || GET_CODE (XEXP (op, 0)) != PLUS
+ || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF
+ || GET_CODE (XEXP (XEXP (op, 0), 1)) != CONST_INT)
+ return 0;
+
+ else
+ {
+ rtx sum = XEXP (op, 0);
+ HOST_WIDE_INT summand;
+
+ /* We have to be careful here, because it is the referenced address
+ that must be 32k from _SDA_BASE_, not just the symbol. */
+ summand = INTVAL (XEXP (sum, 1));
+ if (summand < 0 || summand > g_switch_value)
+ return 0;
+
+ sym_ref = XEXP (sum, 0);
+ }
+
+ if (*XSTR (sym_ref, 0) != '@')
+ return 0;
+
+ return 1;
+
+#else
+ return 0;
+#endif
+}
+
+
+/* Initialize a variable CUM of type CUMULATIVE_ARGS
+ for a call to a function whose data type is FNTYPE.
+ For a library call, FNTYPE is 0.
+
+ For incoming args we set the number of arguments in the prototype large
+ so we never return a PARALLEL. */
+
+void
+init_cumulative_args (cum, fntype, libname, incoming)
+ CUMULATIVE_ARGS *cum;
+ tree fntype;
+ rtx libname ATTRIBUTE_UNUSED;
+ int incoming;
+{
+ static CUMULATIVE_ARGS zero_cumulative;
+ enum rs6000_abi abi = DEFAULT_ABI;
+
+ *cum = zero_cumulative;
+ cum->words = 0;
+ cum->fregno = FP_ARG_MIN_REG;
+ cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
+ cum->call_cookie = CALL_NORMAL;
+
+ if (incoming)
+ {
+ cum->nargs_prototype = 1000; /* don't return a PARALLEL */
+ if (abi == ABI_V4 || abi == ABI_SOLARIS)
+ cum->varargs_offset = RS6000_VARARGS_OFFSET;
+ }
+
+ else if (cum->prototype)
+ cum->nargs_prototype = (list_length (TYPE_ARG_TYPES (fntype)) - 1
+ + (TYPE_MODE (TREE_TYPE (fntype)) == BLKmode
+ || RETURN_IN_MEMORY (TREE_TYPE (fntype))));
+
+ else
+ cum->nargs_prototype = 0;
+
+ cum->orig_nargs = cum->nargs_prototype;
+
+ /* Check for DLL import functions */
+ if (abi == ABI_NT
+ && fntype
+ && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (fntype)))
+ cum->call_cookie = CALL_NT_DLLIMPORT;
+
+ /* Also check for longcall's */
+ else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
+ cum->call_cookie = CALL_LONG;
+
+ if (TARGET_DEBUG_ARG)
+ {
+ fprintf (stderr, "\ninit_cumulative_args:");
+ if (fntype)
+ {
+ tree ret_type = TREE_TYPE (fntype);
+ fprintf (stderr, " ret code = %s,",
+ tree_code_name[ (int)TREE_CODE (ret_type) ]);
+ }
+
+ if ((abi == ABI_V4 || abi == ABI_SOLARIS) && incoming)
+ fprintf (stderr, " varargs = %d, ", cum->varargs_offset);
+
+ if (cum->call_cookie & CALL_NT_DLLIMPORT)
+ fprintf (stderr, " dllimport,");
+
+ if (cum->call_cookie & CALL_LONG)
+ fprintf (stderr, " longcall,");
+
+ fprintf (stderr, " proto = %d, nargs = %d\n",
+ cum->prototype, cum->nargs_prototype);
+ }
+}
+
+/* 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, `downward' to pad below, or `none' to inhibit
+ padding.
+
+ For the AIX ABI structs are always stored left shifted in their
+ argument slot. */
+
+int
+function_arg_padding (mode, type)
+ enum machine_mode mode;
+ tree type;
+{
+ if (type != 0 && AGGREGATE_TYPE_P (type))
+ return (int)upward;
+
+ /* This is the default definition. */
+ return (! BYTES_BIG_ENDIAN
+ ? (int)upward
+ : ((mode == BLKmode
+ ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
+ && int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT))
+ : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
+ ? (int)downward : (int)upward));
+}
+
+/* If defined, a C expression that gives the alignment boundary, in bits,
+ of an argument with the specified mode and type. If it is not defined,
+ PARM_BOUNDARY is used for all arguments.
+
+ Windows NT wants anything >= 8 bytes to be double word aligned.
+
+ V.4 wants long longs to be double word aligned. */
+
+int
+function_arg_boundary (mode, type)
+ enum machine_mode mode;
+ tree type;
+{
+ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && mode == DImode)
+ return 64;
+
+ if (DEFAULT_ABI != ABI_NT || TARGET_64BIT)
+ return PARM_BOUNDARY;
+
+ if (mode != BLKmode)
+ return (GET_MODE_SIZE (mode)) >= 8 ? 64 : 32;
+
+ return (int_size_in_bytes (type) >= 8) ? 64 : 32;
+}
+
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ (TYPE is null for libcalls where that information may not be available.) */
+
+void
+function_arg_advance (cum, mode, type, named)
+ CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int named;
+{
+ int align = (TARGET_32BIT && (cum->words & 1) != 0
+ && function_arg_boundary (mode, type) == 64) ? 1 : 0;
+ cum->words += align;
+ cum->nargs_prototype--;
+
+ if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ {
+ /* Long longs must not be split between registers and stack */
+ if ((GET_MODE_CLASS (mode) != MODE_FLOAT || TARGET_SOFT_FLOAT)
+ && type && !AGGREGATE_TYPE_P (type)
+ && cum->words < GP_ARG_NUM_REG
+ && cum->words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG)
+ {
+ cum->words = GP_ARG_NUM_REG;
+ }
+
+ /* Aggregates get passed as pointers */
+ if (type && AGGREGATE_TYPE_P (type))
+ cum->words++;
+
+ /* Floats go in registers, & don't occupy space in the GP registers
+ like they do for AIX unless software floating point. */
+ else if (GET_MODE_CLASS (mode) == MODE_FLOAT
+ && TARGET_HARD_FLOAT
+ && cum->fregno <= FP_ARG_V4_MAX_REG)
+ cum->fregno++;
+
+ else
+ cum->words += RS6000_ARG_SIZE (mode, type, 1);
+ }
+ else
+ if (named)
+ {
+ cum->words += RS6000_ARG_SIZE (mode, type, named);
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)
+ cum->fregno++;
+ }
+
+ if (TARGET_DEBUG_ARG)
+ fprintf (stderr,
+ "function_adv: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n",
+ cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named, align);
+}
+
+/* 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.
+
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis).
+
+ On RS/6000 the first eight words of non-FP are normally in registers
+ and the rest are pushed. Under AIX, the first 13 FP args are in registers.
+ Under V.4, the first 8 FP args are in registers.
+
+ If this is floating-point and no prototype is specified, we use
+ both an FP and integer register (or possibly FP reg and stack). Library
+ functions (when TYPE is zero) always have the proper types for args,
+ so we can pass the FP value just in one register. emit_library_function
+ doesn't support PARALLEL anyway. */
+
+struct rtx_def *
+function_arg (cum, mode, type, named)
+ CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int named;
+{
+ int align = (TARGET_32BIT && (cum->words & 1) != 0
+ && function_arg_boundary (mode, type) == 64) ? 1 : 0;
+ int align_words = cum->words + align;
+
+ if (TARGET_DEBUG_ARG)
+ fprintf (stderr,
+ "function_arg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n",
+ cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named, align);
+
+ /* Return a marker to indicate whether CR1 needs to set or clear the bit that V.4
+ uses to say fp args were passed in registers. Assume that we don't need the
+ marker for software floating point, or compiler generated library calls. */
+ if (mode == VOIDmode)
+ {
+ enum rs6000_abi abi = DEFAULT_ABI;
+
+ if ((abi == ABI_V4 || abi == ABI_SOLARIS)
+ && TARGET_HARD_FLOAT
+ && cum->nargs_prototype < 0
+ && type && (cum->prototype || TARGET_NO_PROTOTYPE))
+ {
+ return GEN_INT (cum->call_cookie
+ | ((cum->fregno == FP_ARG_MIN_REG)
+ ? CALL_V4_SET_FP_ARGS
+ : CALL_V4_CLEAR_FP_ARGS));
+ }
+
+ return GEN_INT (cum->call_cookie);
+ }
+
+ if (!named)
+ {
+ if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
+ return NULL_RTX;
+ }
+
+ if (type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ return NULL_RTX;
+
+ if (USE_FP_FOR_ARG_P (*cum, mode, type))
+ {
+ if (DEFAULT_ABI == ABI_V4 /* V.4 never passes FP values in GP registers */
+ || DEFAULT_ABI == ABI_SOLARIS
+ || ! type
+ || ((cum->nargs_prototype > 0)
+ /* IBM AIX extended its linkage convention definition always to
+ require FP args after register save area hole on the stack. */
+ && (DEFAULT_ABI != ABI_AIX
+ || ! TARGET_XL_CALL
+ || (align_words < GP_ARG_NUM_REG))))
+ return gen_rtx_REG (mode, cum->fregno);
+
+ return gen_rtx_PARALLEL (mode,
+ gen_rtvec
+ (2,
+ gen_rtx_EXPR_LIST (VOIDmode,
+ ((align_words >= GP_ARG_NUM_REG)
+ ? NULL_RTX
+ : (align_words
+ + RS6000_ARG_SIZE (mode, type, named)
+ > GP_ARG_NUM_REG
+ /* If this is partially on the stack, then
+ we only include the portion actually
+ in registers here. */
+ ? gen_rtx_REG (SImode,
+ GP_ARG_MIN_REG + align_words)
+ : gen_rtx_REG (mode,
+ GP_ARG_MIN_REG + align_words))),
+ const0_rtx),
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (mode, cum->fregno),
+ const0_rtx)));
+ }
+
+ /* Long longs won't be split between register and stack;
+ FP arguments get passed on the stack if they didn't get a register. */
+ else if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) &&
+ (align_words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG
+ || (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)))
+ {
+ return NULL_RTX;
+ }
+
+ else if (align_words < GP_ARG_NUM_REG)
+ return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+
+ return NULL_RTX;
+}
+
+/* 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. */
+
+int
+function_arg_partial_nregs (cum, mode, type, named)
+ CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int named;
+{
+ if (! named)
+ return 0;
+
+ if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ return 0;
+
+ if (USE_FP_FOR_ARG_P (*cum, mode, type))
+ {
+ if (cum->nargs_prototype >= 0)
+ return 0;
+ }
+
+ if (cum->words < GP_ARG_NUM_REG
+ && GP_ARG_NUM_REG < (cum->words + RS6000_ARG_SIZE (mode, type, named)))
+ {
+ int ret = GP_ARG_NUM_REG - cum->words;
+ if (ret && TARGET_DEBUG_ARG)
+ fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+/* 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.
+
+ Under V.4, structures and unions are passed by reference. */
+
+int
+function_arg_pass_by_reference (cum, mode, type, named)
+ CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ tree type;
+ int named ATTRIBUTE_UNUSED;
+{
+ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && type && AGGREGATE_TYPE_P (type))
+ {
+ if (TARGET_DEBUG_ARG)
+ fprintf (stderr, "function_arg_pass_by_reference: aggregate\n");
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* Perform any needed actions needed for a function that is receiving a
+ variable number of arguments.
+
+ CUM is as above.
+
+ MODE and TYPE are the mode and type of the current parameter.
+
+ PRETEND_SIZE is a variable that should be set to the amount of stack
+ that must be pushed by the prolog to pretend that our caller pushed
+ it.
+
+ Normally, this macro will push all remaining incoming registers on the
+ stack and set PRETEND_SIZE to the length of the registers pushed. */
+
+void
+setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
+ CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int *pretend_size;
+ int no_rtl;
+
+{
+ rtx save_area = virtual_incoming_args_rtx;
+ int reg_size = TARGET_32BIT ? 4 : 8;
+
+ if (TARGET_DEBUG_ARG)
+ fprintf (stderr,
+ "setup_vararg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, no_rtl= %d\n",
+ cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), no_rtl);
+
+ if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ {
+ rs6000_sysv_varargs_p = 1;
+ if (! no_rtl)
+ save_area = plus_constant (frame_pointer_rtx, RS6000_VARARGS_OFFSET);
+ }
+ else
+ rs6000_sysv_varargs_p = 0;
+
+ if (cum->words < 8)
+ {
+ int first_reg_offset = cum->words;
+
+ if (MUST_PASS_IN_STACK (mode, type))
+ first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type, 1);
+
+ if (first_reg_offset > GP_ARG_NUM_REG)
+ first_reg_offset = GP_ARG_NUM_REG;
+
+ if (!no_rtl && first_reg_offset != GP_ARG_NUM_REG)
+ move_block_from_reg
+ (GP_ARG_MIN_REG + first_reg_offset,
+ gen_rtx_MEM (BLKmode,
+ plus_constant (save_area, first_reg_offset * reg_size)),
+ GP_ARG_NUM_REG - first_reg_offset,
+ (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD);
+
+ *pretend_size = (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD;
+ }
+
+ /* Save FP registers if needed. */
+ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && TARGET_HARD_FLOAT && !no_rtl)
+ {
+ int fregno = cum->fregno;
+ int num_fp_reg = FP_ARG_V4_MAX_REG + 1 - fregno;
+
+ if (num_fp_reg >= 0)
+ {
+ rtx cr1 = gen_rtx_REG (CCmode, 69);
+ rtx lab = gen_label_rtx ();
+ int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8);
+
+ emit_jump_insn (gen_rtx_SET (VOIDmode,
+ pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode,
+ gen_rtx_NE (VOIDmode, cr1, const0_rtx),
+ gen_rtx_LABEL_REF (VOIDmode, lab),
+ pc_rtx)));
+
+ while ( num_fp_reg-- >= 0)
+ {
+ emit_move_insn (gen_rtx_MEM (DFmode, plus_constant (save_area, off)),
+ gen_rtx_REG (DFmode, fregno++));
+ off += 8;
+ }
+
+ emit_label (lab);
+ }
+ }
+}
+
+/* If defined, is a C expression that produces the machine-specific
+ code for a call to `__builtin_saveregs'. This code will be moved
+ to the very beginning of the function, before any parameter access
+ are made. The return value of this function should be an RTX that
+ contains the value to use as the return of `__builtin_saveregs'.
+
+ The argument ARGS is a `tree_list' containing the arguments that
+ were passed to `__builtin_saveregs'.
+
+ If this macro is not defined, the compiler will output an ordinary
+ call to the library function `__builtin_saveregs'.
+
+ On the Power/PowerPC return the address of the area on the stack
+ used to hold arguments. Under AIX, this includes the 8 word register
+ save area. Under V.4 this does not. */
+
+struct rtx_def *
+expand_builtin_saveregs (args)
+ tree args ATTRIBUTE_UNUSED;
+{
+ return virtual_incoming_args_rtx;
+}
+
+
+/* Generate a memory reference for expand_block_move, copying volatile,
+ and other bits from an original memory reference. */
+
+static rtx
+expand_block_move_mem (mode, addr, orig_mem)
+ enum machine_mode mode;
+ rtx addr;
+ rtx orig_mem;
+{
+ rtx mem = gen_rtx_MEM (mode, addr);
+
+ RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (orig_mem);
+ MEM_COPY_ATTRIBUTES (mem, orig_mem);
+#ifdef MEM_UNALIGNED_P
+ MEM_UNALIGNED_P (mem) = MEM_UNALIGNED_P (orig_mem);
+#endif
+ return mem;
+}
+
+/* Expand a block move operation, and return 1 if successful. Return 0
+ if we should let the compiler generate normal code.
+
+ operands[0] is the destination
+ operands[1] is the source
+ operands[2] is the length
+ operands[3] is the alignment */
+
+#define MAX_MOVE_REG 4
+
+int
+expand_block_move (operands)
+ rtx operands[];
+{
+ rtx orig_dest = operands[0];
+ rtx orig_src = operands[1];
+ rtx bytes_rtx = operands[2];
+ rtx align_rtx = operands[3];
+ int constp = (GET_CODE (bytes_rtx) == CONST_INT);
+ int align = XINT (align_rtx, 0);
+ int bytes;
+ int offset;
+ int num_reg;
+ int i;
+ rtx src_reg;
+ rtx dest_reg;
+ rtx src_addr;
+ rtx dest_addr;
+ rtx tmp_reg;
+ rtx stores[MAX_MOVE_REG];
+ int move_bytes;
+
+ /* If this is not a fixed size move, just call memcpy */
+ if (!constp)
+ return 0;
+
+ /* Anything to move? */
+ bytes = INTVAL (bytes_rtx);
+ if (bytes <= 0)
+ return 1;
+
+ /* Don't support real large moves. If string instructions are not used,
+ then don't generate more than 8 loads. */
+ if (TARGET_STRING)
+ {
+ if (bytes > 4*8)
+ return 0;
+ }
+ else if (!STRICT_ALIGNMENT)
+ {
+ if (bytes > 4*8)
+ return 0;
+ }
+ else if (bytes > 8*align)
+ return 0;
+
+ /* Move the address into scratch registers. */
+ dest_reg = copy_addr_to_reg (XEXP (orig_dest, 0));
+ src_reg = copy_addr_to_reg (XEXP (orig_src, 0));
+
+ if (TARGET_STRING) /* string instructions are available */
+ {
+ for ( ; bytes > 0; bytes -= move_bytes)
+ {
+ if (bytes > 24 /* move up to 32 bytes at a time */
+ && !fixed_regs[5]
+ && !fixed_regs[6]
+ && !fixed_regs[7]
+ && !fixed_regs[8]
+ && !fixed_regs[9]
+ && !fixed_regs[10]
+ && !fixed_regs[11]
+ && !fixed_regs[12])
+ {
+ move_bytes = (bytes > 32) ? 32 : bytes;
+ emit_insn (gen_movstrsi_8reg (expand_block_move_mem (BLKmode, dest_reg, orig_dest),
+ expand_block_move_mem (BLKmode, src_reg, orig_src),
+ GEN_INT ((move_bytes == 32) ? 0 : move_bytes),
+ align_rtx));
+ }
+ else if (bytes > 16 /* move up to 24 bytes at a time */
+ && !fixed_regs[7]
+ && !fixed_regs[8]
+ && !fixed_regs[9]
+ && !fixed_regs[10]
+ && !fixed_regs[11]
+ && !fixed_regs[12])
+ {
+ move_bytes = (bytes > 24) ? 24 : bytes;
+ emit_insn (gen_movstrsi_6reg (expand_block_move_mem (BLKmode, dest_reg, orig_dest),
+ expand_block_move_mem (BLKmode, src_reg, orig_src),
+ GEN_INT (move_bytes),
+ align_rtx));
+ }
+ else if (bytes > 8 /* move up to 16 bytes at a time */
+ && !fixed_regs[9]
+ && !fixed_regs[10]
+ && !fixed_regs[11]
+ && !fixed_regs[12])
+ {
+ move_bytes = (bytes > 16) ? 16 : bytes;
+ emit_insn (gen_movstrsi_4reg (expand_block_move_mem (BLKmode, dest_reg, orig_dest),
+ expand_block_move_mem (BLKmode, src_reg, orig_src),
+ GEN_INT (move_bytes),
+ align_rtx));
+ }
+ else if (bytes > 4 && !TARGET_64BIT)
+ { /* move up to 8 bytes at a time */
+ move_bytes = (bytes > 8) ? 8 : bytes;
+ emit_insn (gen_movstrsi_2reg (expand_block_move_mem (BLKmode, dest_reg, orig_dest),
+ expand_block_move_mem (BLKmode, src_reg, orig_src),
+ GEN_INT (move_bytes),
+ align_rtx));
+ }
+ else if (bytes >= 4 && (align >= 4 || !STRICT_ALIGNMENT))
+ { /* move 4 bytes */
+ move_bytes = 4;
+ tmp_reg = gen_reg_rtx (SImode);
+ emit_move_insn (tmp_reg, expand_block_move_mem (SImode, src_reg, orig_src));
+ emit_move_insn (expand_block_move_mem (SImode, dest_reg, orig_dest), tmp_reg);
+ }
+ else if (bytes == 2 && (align >= 2 || !STRICT_ALIGNMENT))
+ { /* move 2 bytes */
+ move_bytes = 2;
+ tmp_reg = gen_reg_rtx (HImode);
+ emit_move_insn (tmp_reg, expand_block_move_mem (HImode, src_reg, orig_src));
+ emit_move_insn (expand_block_move_mem (HImode, dest_reg, orig_dest), tmp_reg);
+ }
+ else if (bytes == 1) /* move 1 byte */
+ {
+ move_bytes = 1;
+ tmp_reg = gen_reg_rtx (QImode);
+ emit_move_insn (tmp_reg, expand_block_move_mem (QImode, src_reg, orig_src));
+ emit_move_insn (expand_block_move_mem (QImode, dest_reg, orig_dest), tmp_reg);
+ }
+ else
+ { /* move up to 4 bytes at a time */
+ move_bytes = (bytes > 4) ? 4 : bytes;
+ emit_insn (gen_movstrsi_1reg (expand_block_move_mem (BLKmode, dest_reg, orig_dest),
+ expand_block_move_mem (BLKmode, src_reg, orig_src),
+ GEN_INT (move_bytes),
+ align_rtx));
+ }
+
+ if (bytes > move_bytes)
+ {
+ emit_insn (gen_addsi3 (src_reg, src_reg, GEN_INT (move_bytes)));
+ emit_insn (gen_addsi3 (dest_reg, dest_reg, GEN_INT (move_bytes)));
+ }
+ }
+ }
+
+ else /* string instructions not available */
+ {
+ num_reg = offset = 0;
+ for ( ; bytes > 0; (bytes -= move_bytes), (offset += move_bytes))
+ {
+ /* Calculate the correct offset for src/dest */
+ if (offset == 0)
+ {
+ src_addr = src_reg;
+ dest_addr = dest_reg;
+ }
+ else
+ {
+ src_addr = gen_rtx_PLUS (Pmode, src_reg, GEN_INT (offset));
+ dest_addr = gen_rtx_PLUS (Pmode, dest_reg, GEN_INT (offset));
+ }
+
+ /* Generate the appropriate load and store, saving the stores for later */
+ if (bytes >= 8 && TARGET_64BIT && (align >= 8 || !STRICT_ALIGNMENT))
+ {
+ move_bytes = 8;
+ tmp_reg = gen_reg_rtx (DImode);
+ emit_insn (gen_movdi (tmp_reg, expand_block_move_mem (DImode, src_addr, orig_src)));
+ stores[ num_reg++ ] = gen_movdi (expand_block_move_mem (DImode, dest_addr, orig_dest), tmp_reg);
+ }
+ else if (bytes >= 4 && (align >= 4 || !STRICT_ALIGNMENT))
+ {
+ move_bytes = 4;
+ tmp_reg = gen_reg_rtx (SImode);
+ emit_insn (gen_movsi (tmp_reg, expand_block_move_mem (SImode, src_addr, orig_src)));
+ stores[ num_reg++ ] = gen_movsi (expand_block_move_mem (SImode, dest_addr, orig_dest), tmp_reg);
+ }
+ else if (bytes >= 2 && (align >= 2 || !STRICT_ALIGNMENT))
+ {
+ move_bytes = 2;
+ tmp_reg = gen_reg_rtx (HImode);
+ emit_insn (gen_movsi (tmp_reg, expand_block_move_mem (HImode, src_addr, orig_src)));
+ stores[ num_reg++ ] = gen_movhi (expand_block_move_mem (HImode, dest_addr, orig_dest), tmp_reg);
+ }
+ else
+ {
+ move_bytes = 1;
+ tmp_reg = gen_reg_rtx (QImode);
+ emit_insn (gen_movsi (tmp_reg, expand_block_move_mem (QImode, src_addr, orig_src)));
+ stores[ num_reg++ ] = gen_movqi (expand_block_move_mem (QImode, dest_addr, orig_dest), tmp_reg);
+ }
+
+ if (num_reg >= MAX_MOVE_REG)
+ {
+ for (i = 0; i < num_reg; i++)
+ emit_insn (stores[i]);
+ num_reg = 0;
+ }
+ }
+
+ for (i = 0; i < num_reg; i++)
+ emit_insn (stores[i]);
+ }
+
+ return 1;
+}
+
+
+/* Return 1 if OP is a load multiple operation. It is known to be a
+ PARALLEL and the first section will be tested. */
+
+int
+load_multiple_operation (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ int count = XVECLEN (op, 0);
+ int dest_regno;
+ rtx src_addr;
+ int i;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
+ return 0;
+
+ dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
+ src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+
+ for (i = 1; i < count; i++)
+ {
+ rtx elt = XVECEXP (op, 0, i);
+
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_DEST (elt)) != REG
+ || GET_MODE (SET_DEST (elt)) != SImode
+ || REGNO (SET_DEST (elt)) != dest_regno + i
+ || GET_CODE (SET_SRC (elt)) != MEM
+ || GET_MODE (SET_SRC (elt)) != SImode
+ || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
+ || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
+ || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
+ || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Similar, but tests for store multiple. Here, the second vector element
+ is a CLOBBER. It will be tested later. */
+
+int
+store_multiple_operation (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ int count = XVECLEN (op, 0) - 1;
+ int src_regno;
+ rtx dest_addr;
+ int i;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
+ return 0;
+
+ src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
+ dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
+
+ for (i = 1; i < count; i++)
+ {
+ rtx elt = XVECEXP (op, 0, i + 1);
+
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_SRC (elt)) != REG
+ || GET_MODE (SET_SRC (elt)) != SImode
+ || REGNO (SET_SRC (elt)) != src_regno + i
+ || GET_CODE (SET_DEST (elt)) != MEM
+ || GET_MODE (SET_DEST (elt)) != SImode
+ || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
+ || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
+ || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
+ || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Return 1 if OP is a comparison operation that is valid for a branch insn.
+ We only check the opcode against the mode of the CC value here. */
+
+int
+branch_comparison_operator (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ enum rtx_code code = GET_CODE (op);
+ enum machine_mode cc_mode;
+
+ if (GET_RTX_CLASS (code) != '<')
+ return 0;
+
+ cc_mode = GET_MODE (XEXP (op, 0));
+ if (GET_MODE_CLASS (cc_mode) != MODE_CC)
+ return 0;
+
+ if ((code == GT || code == LT || code == GE || code == LE)
+ && cc_mode == CCUNSmode)
+ return 0;
+
+ if ((code == GTU || code == LTU || code == GEU || code == LEU)
+ && (cc_mode != CCUNSmode))
+ return 0;
+
+ return 1;
+}
+
+/* Return 1 if OP is a comparison operation that is valid for an scc insn.
+ We check the opcode against the mode of the CC value and disallow EQ or
+ NE comparisons for integers. */
+
+int
+scc_comparison_operator (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ enum rtx_code code = GET_CODE (op);
+ enum machine_mode cc_mode;
+
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return 0;
+
+ if (GET_RTX_CLASS (code) != '<')
+ return 0;
+
+ cc_mode = GET_MODE (XEXP (op, 0));
+ if (GET_MODE_CLASS (cc_mode) != MODE_CC)
+ return 0;
+
+ if (code == NE && cc_mode != CCFPmode)
+ return 0;
+
+ if ((code == GT || code == LT || code == GE || code == LE)
+ && cc_mode == CCUNSmode)
+ return 0;
+
+ if ((code == GTU || code == LTU || code == GEU || code == LEU)
+ && (cc_mode != CCUNSmode))
+ return 0;
+
+ if (cc_mode == CCEQmode && code != EQ && code != NE)
+ return 0;
+
+ return 1;
+}
+
+int
+trap_comparison_operator (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (mode != VOIDmode && mode != GET_MODE (op))
+ return 0;
+ return (GET_RTX_CLASS (GET_CODE (op)) == '<'
+ || GET_CODE (op) == EQ || GET_CODE (op) == NE);
+}
+
+/* Return 1 if ANDOP is a mask that has no bits on that are not in the
+ mask required to convert the result of a rotate insn into a shift
+ left insn of SHIFTOP bits. Both are known to be CONST_INT. */
+
+int
+includes_lshift_p (shiftop, andop)
+ register rtx shiftop;
+ register rtx andop;
+{
+ int shift_mask = (~0 << INTVAL (shiftop));
+
+ return (INTVAL (andop) & ~shift_mask) == 0;
+}
+
+/* Similar, but for right shift. */
+
+int
+includes_rshift_p (shiftop, andop)
+ register rtx shiftop;
+ register rtx andop;
+{
+ unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
+
+ shift_mask >>= INTVAL (shiftop);
+
+ return (INTVAL (andop) & ~ shift_mask) == 0;
+}
+
+/* Return 1 if REGNO (reg1) == REGNO (reg2) - 1 making them candidates
+ for lfq and stfq insns.
+
+ Note reg1 and reg2 *must* be hard registers. To be sure we will
+ abort if we are passed pseudo registers. */
+
+int
+registers_ok_for_quad_peep (reg1, reg2)
+ rtx reg1, reg2;
+{
+ /* We might have been passed a SUBREG. */
+ if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
+ return 0;
+
+ return (REGNO (reg1) == REGNO (reg2) - 1);
+}
+
+/* Return 1 if addr1 and addr2 are suitable for lfq or stfq insn. addr1 and
+ addr2 must be in consecutive memory locations (addr2 == addr1 + 8). */
+
+int
+addrs_ok_for_quad_peep (addr1, addr2)
+ register rtx addr1;
+ register rtx addr2;
+{
+ int reg1;
+ int offset1;
+
+ /* Extract an offset (if used) from the first addr. */
+ if (GET_CODE (addr1) == PLUS)
+ {
+ /* If not a REG, return zero. */
+ if (GET_CODE (XEXP (addr1, 0)) != REG)
+ return 0;
+ else
+ {
+ reg1 = REGNO (XEXP (addr1, 0));
+ /* The offset must be constant! */
+ if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
+ return 0;
+ offset1 = INTVAL (XEXP (addr1, 1));
+ }
+ }
+ else if (GET_CODE (addr1) != REG)
+ return 0;
+ else
+ {
+ reg1 = REGNO (addr1);
+ /* This was a simple (mem (reg)) expression. Offset is 0. */
+ offset1 = 0;
+ }
+
+ /* Make sure the second address is a (mem (plus (reg) (const_int). */
+ if (GET_CODE (addr2) != PLUS)
+ return 0;
+
+ if (GET_CODE (XEXP (addr2, 0)) != REG
+ || GET_CODE (XEXP (addr2, 1)) != CONST_INT)
+ return 0;
+
+ if (reg1 != REGNO (XEXP (addr2, 0)))
+ return 0;
+
+ /* The offset for the second addr must be 8 more than the first addr. */
+ if (INTVAL (XEXP (addr2, 1)) != offset1 + 8)
+ return 0;
+
+ /* All the tests passed. addr1 and addr2 are valid for lfq or stfq
+ instructions. */
+ return 1;
+}
+
+/* Return the register class of a scratch register needed to copy IN into
+ or out of a register in CLASS in MODE. If it can be done directly,
+ NO_REGS is returned. */
+
+enum reg_class
+secondary_reload_class (class, mode, in)
+ enum reg_class class;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ rtx in;
+{
+ int regno;
+
+ /* We can not copy a symbolic operand directly into anything other than
+ BASE_REGS for TARGET_ELF. So indicate that a register from BASE_REGS
+ is needed as an intermediate register. */
+ if (TARGET_ELF
+ && class != BASE_REGS
+ && (GET_CODE (in) == SYMBOL_REF
+ || GET_CODE (in) == HIGH
+ || GET_CODE (in) == LABEL_REF
+ || GET_CODE (in) == CONST))
+ return BASE_REGS;
+
+ if (GET_CODE (in) == REG)
+ {
+ regno = REGNO (in);
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ regno = true_regnum (in);
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ regno = -1;
+ }
+ }
+ else if (GET_CODE (in) == SUBREG)
+ {
+ regno = true_regnum (in);
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ regno = -1;
+ }
+ else
+ regno = -1;
+
+ /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
+ into anything. */
+ if (class == GENERAL_REGS || class == BASE_REGS
+ || (regno >= 0 && INT_REGNO_P (regno)))
+ return NO_REGS;
+
+ /* Constants, memory, and FP registers can go into FP registers. */
+ if ((regno == -1 || FP_REGNO_P (regno))
+ && (class == FLOAT_REGS || class == NON_SPECIAL_REGS))
+ return NO_REGS;
+
+ /* We can copy among the CR registers. */
+ if ((class == CR_REGS || class == CR0_REGS)
+ && regno >= 0 && CR_REGNO_P (regno))
+ return NO_REGS;
+
+ /* Otherwise, we need GENERAL_REGS. */
+ return GENERAL_REGS;
+}
+
+/* Given a comparison operation, return the bit number in CCR to test. We
+ know this is a valid comparison.
+
+ SCC_P is 1 if this is for an scc. That means that %D will have been
+ used instead of %C, so the bits will be in different places.
+
+ Return -1 if OP isn't a valid comparison for some reason. */
+
+int
+ccr_bit (op, scc_p)
+ register rtx op;
+ int scc_p;
+{
+ /* CYGNUS LOCAL -- meissner/branch prediction */
+ enum rtx_code code = GET_CODE (op);
+ enum machine_mode cc_mode;
+ int cc_regnum;
+ int base_bit;
+ rtx reg;
+
+ if (GET_RTX_CLASS (code) != '<')
+ return -1;
+
+ reg = XEXP (op, 0);
+
+ if (GET_CODE (reg) == EXPECT)
+ reg = XEXP (reg, 0);
+
+ if (GET_CODE (reg) != REG
+ || REGNO (reg) < 68
+ || REGNO (reg) > 75)
+ abort ();
+
+ cc_mode = GET_MODE (reg);
+ cc_regnum = REGNO (reg);
+ base_bit = 4 * (cc_regnum - 68);
+ /* END CYGNUS LOCAL -- meissner/branch prediction */
+
+ /* In CCEQmode cases we have made sure that the result is always in the
+ third bit of the CR field. */
+
+ if (cc_mode == CCEQmode)
+ return base_bit + 3;
+
+ switch (code)
+ {
+ case NE:
+ return scc_p ? base_bit + 3 : base_bit + 2;
+ case EQ:
+ return base_bit + 2;
+ case GT: case GTU:
+ return base_bit + 1;
+ case LT: case LTU:
+ return base_bit;
+
+ case GE: case GEU:
+ /* If floating-point, we will have done a cror to put the bit in the
+ unordered position. So test that bit. For integer, this is ! LT
+ unless this is an scc insn. */
+ return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit;
+
+ case LE: case LEU:
+ return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit + 1;
+
+ default:
+ abort ();
+ }
+}
+
+/* Return the GOT register, creating it if needed. */
+
+struct rtx_def *
+rs6000_got_register (value)
+ rtx value;
+{
+ if (!current_function_uses_pic_offset_table || !pic_offset_table_rtx)
+ {
+ if (reload_in_progress || reload_completed)
+ fatal_insn ("internal error -- needed new GOT register during reload phase to load:", value);
+
+ current_function_uses_pic_offset_table = 1;
+ pic_offset_table_rtx = gen_rtx_REG (Pmode, GOT_TOC_REGNUM);
+ }
+
+ return pic_offset_table_rtx;
+}
+
+
+/* Replace all occurrences of register FROM with an new pseudo register in an insn X.
+ Store the pseudo register used in REG.
+ This is only safe during FINALIZE_PIC, since the registers haven't been setup
+ yet. */
+
+static rtx
+rs6000_replace_regno (x, from, reg)
+ rtx x;
+ int from;
+ rtx *reg;
+{
+ register int i, j;
+ register char *fmt;
+
+ /* Allow this function to make replacements in EXPR_LISTs. */
+ if (!x)
+ return x;
+
+ switch (GET_CODE (x))
+ {
+ case SCRATCH:
+ case PC:
+ case CC0:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return x;
+
+ case REG:
+ if (REGNO (x) == from)
+ {
+ if (! *reg)
+ *reg = pic_offset_table_rtx = gen_reg_rtx (Pmode);
+
+ return *reg;
+ }
+
+ return x;
+
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ XEXP (x, i) = rs6000_replace_regno (XEXP (x, i), from, reg);
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ XVECEXP (x, i, j) = rs6000_replace_regno (XVECEXP (x, i, j), from, reg);
+ }
+
+ return x;
+}
+
+
+/* By generating position-independent code, when two different
+ programs (A and B) share a common library (libC.a), the text of
+ the library can be shared whether or not the library is linked at
+ the same address for both programs. In some of these
+ environments, position-independent code requires not only the use
+ of different addressing modes, but also special code to enable the
+ use of these addressing modes.
+
+ The `FINALIZE_PIC' macro serves as a hook to emit these special
+ codes once the function is being compiled into assembly code, but
+ not before. (It is not done before, because in the case of
+ compiling an inline function, it would lead to multiple PIC
+ prologues being included in functions which used inline functions
+ and were compiled to assembly language.) */
+
+void
+rs6000_finalize_pic ()
+{
+ /* Loop through all of the insns, replacing the special GOT_TOC_REGNUM
+ with an appropriate pseudo register. If we find we need GOT/TOC,
+ add the appropriate init code. */
+ if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS))
+ {
+ rtx insn = get_insns ();
+ rtx reg = NULL_RTX;
+ rtx first_insn;
+ rtx last_insn = NULL_RTX;
+
+ if (GET_CODE (insn) == NOTE)
+ insn = next_nonnote_insn (insn);
+
+ first_insn = insn;
+ for ( ; insn != NULL_RTX; insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ PATTERN (insn) = rs6000_replace_regno (PATTERN (insn),
+ GOT_TOC_REGNUM,
+ &reg);
+
+ if (REG_NOTES (insn))
+ REG_NOTES (insn) = rs6000_replace_regno (REG_NOTES (insn),
+ GOT_TOC_REGNUM,
+ &reg);
+ }
+
+ if (GET_CODE (insn) != NOTE)
+ last_insn = insn;
+ }
+
+ if (reg)
+ {
+ rtx init = gen_init_v4_pic (reg);
+ emit_insn_before (init, first_insn);
+ if (!optimize && last_insn)
+ emit_insn_after (gen_rtx_USE (VOIDmode, reg), last_insn);
+ }
+ }
+}
+
+
+/* Search for any occurrence of the GOT_TOC register marker that should
+ have been eliminated, but may have crept back in. */
+
+void
+rs6000_reorg (insn)
+ rtx insn;
+{
+ if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS))
+ {
+ rtx got_reg = gen_rtx_REG (Pmode, GOT_TOC_REGNUM);
+ for ( ; insn != NULL_RTX; insn = NEXT_INSN (insn))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && reg_mentioned_p (got_reg, PATTERN (insn)))
+ fatal_insn ("GOT/TOC register marker not removed:", PATTERN (insn));
+ }
+}
+
+
+/* Define the structure for the machine field in struct function. */
+struct machine_function
+{
+ int sysv_varargs_p;
+ int save_toc_p;
+ int fpmem_size;
+ int fpmem_offset;
+ rtx pic_offset_table_rtx;
+};
+
+/* Functions to save and restore rs6000_fpmem_size.
+ These will be called, via pointer variables,
+ from push_function_context and pop_function_context. */
+
+void
+rs6000_save_machine_status (p)
+ struct function *p;
+{
+ struct machine_function *machine =
+ (struct machine_function *) xmalloc (sizeof (struct machine_function));
+
+ p->machine = machine;
+ machine->sysv_varargs_p = rs6000_sysv_varargs_p;
+ machine->fpmem_size = rs6000_fpmem_size;
+ machine->fpmem_offset = rs6000_fpmem_offset;
+ machine->pic_offset_table_rtx = pic_offset_table_rtx;
+}
+
+void
+rs6000_restore_machine_status (p)
+ struct function *p;
+{
+ struct machine_function *machine = p->machine;
+
+ rs6000_sysv_varargs_p = machine->sysv_varargs_p;
+ rs6000_fpmem_size = machine->fpmem_size;
+ rs6000_fpmem_offset = machine->fpmem_offset;
+ pic_offset_table_rtx = machine->pic_offset_table_rtx;
+
+ free (machine);
+ p->machine = (struct machine_function *)0;
+}
+
+/* Do anything needed before RTL is emitted for each function. */
+
+void
+rs6000_init_expanders ()
+{
+ /* Reset varargs and save TOC indicator */
+ rs6000_sysv_varargs_p = 0;
+ rs6000_fpmem_size = 0;
+ rs6000_fpmem_offset = 0;
+ pic_offset_table_rtx = (rtx)0;
+
+ /* Arrange to save and restore machine status around nested functions. */
+ save_machine_status = rs6000_save_machine_status;
+ restore_machine_status = rs6000_restore_machine_status;
+}
+
+
+/* Print an operand. Recognize special options, documented below. */
+
+#if TARGET_ELF
+#define SMALL_DATA_RELOC ((rs6000_sdata == SDATA_EABI) ? "sda21" : "sdarel")
+#define SMALL_DATA_REG ((rs6000_sdata == SDATA_EABI) ? 0 : 13)
+#else
+#define SMALL_DATA_RELOC "sda21"
+#define SMALL_DATA_REG 0
+#endif
+
+void
+print_operand (file, x, code)
+ FILE *file;
+ rtx x;
+ char code;
+{
+ int i;
+ /* CYGNUS LOCAL -- meissner/branch prediction */
+ int succeed;
+ /* END CYGNUS LOCAL -- meissner/branch prediction */
+ HOST_WIDE_INT val;
+
+ /* These macros test for integers and extract the low-order bits. */
+#define INT_P(X) \
+((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE) \
+ && GET_MODE (X) == VOIDmode)
+
+#define INT_LOWPART(X) \
+ (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
+
+ switch (code)
+ {
+ case '.':
+ /* Write out an instruction after the call which may be replaced
+ with glue code by the loader. This depends on the AIX version. */
+ asm_fprintf (file, RS6000_CALL_GLUE);
+ return;
+
+ case '*':
+ /* Write the register number of the TOC register. */
+ fputs (TARGET_MINIMAL_TOC ? reg_names[30] : reg_names[2], file);
+ return;
+
+ case '$':
+ /* Write out either a '.' or '$' for the current location, depending
+ on whether this is Solaris or not. */
+ putc ((DEFAULT_ABI == ABI_SOLARIS) ? '.' : '$', file);
+ return;
+
+ case 'A':
+ /* If X is a constant integer whose low-order 5 bits are zero,
+ write 'l'. Otherwise, write 'r'. This is a kludge to fix a bug
+ in the AIX assembler where "sri" with a zero shift count
+ write a trash instruction. */
+ if (GET_CODE (x) == CONST_INT && (INTVAL (x) & 31) == 0)
+ putc ('l', file);
+ else
+ putc ('r', file);
+ return;
+
+ case 'b':
+ /* Low-order 16 bits of constant, unsigned. */
+ if (! INT_P (x))
+ output_operand_lossage ("invalid %%b value");
+
+ fprintf (file, "%d", INT_LOWPART (x) & 0xffff);
+ return;
+
+ case 'B':
+ /* If the low-order bit is zero, write 'r'; otherwise, write 'l'
+ for 64-bit mask direction. */
+ putc (((INT_LOWPART(x) & 1) == 0 ? 'r' : 'l'), file);
+ return;
+
+ case 'C':
+ /* This is an optional cror needed for LE or GE floating-point
+ comparisons. Otherwise write nothing. */
+ if ((GET_CODE (x) == LE || GET_CODE (x) == GE)
+ && GET_MODE (XEXP (x, 0)) == CCFPmode)
+ {
+ int base_bit = 4 * (REGNO (XEXP (x, 0)) - 68);
+
+ fprintf (file, "cror %d,%d,%d\n\t", base_bit + 3,
+ base_bit + 2, base_bit + (GET_CODE (x) == GE));
+ }
+ return;
+
+ case 'D':
+ /* Similar, except that this is for an scc, so we must be able to
+ encode the test in a single bit that is one. We do the above
+ for any LE, GE, GEU, or LEU and invert the bit for NE. */
+ if (GET_CODE (x) == LE || GET_CODE (x) == GE
+ || GET_CODE (x) == LEU || GET_CODE (x) == GEU)
+ {
+ int base_bit = 4 * (REGNO (XEXP (x, 0)) - 68);
+
+ fprintf (file, "cror %d,%d,%d\n\t", base_bit + 3,
+ base_bit + 2,
+ base_bit + (GET_CODE (x) == GE || GET_CODE (x) == GEU));
+ }
+
+ else if (GET_CODE (x) == NE)
+ {
+ int base_bit = 4 * (REGNO (XEXP (x, 0)) - 68);
+
+ fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 3,
+ base_bit + 2, base_bit + 2);
+ }
+ return;
+
+ case 'E':
+ /* X is a CR register. Print the number of the third bit of the CR */
+ if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
+ output_operand_lossage ("invalid %%E value");
+
+ fprintf(file, "%d", 4 * (REGNO (x) - 68) + 3);
+ return;
+
+ case 'f':
+ /* X is a CR register. Print the shift count needed to move it
+ to the high-order four bits. */
+ if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
+ output_operand_lossage ("invalid %%f value");
+ else
+ fprintf (file, "%d", 4 * (REGNO (x) - 68));
+ return;
+
+ case 'F':
+ /* Similar, but print the count for the rotate in the opposite
+ direction. */
+ if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
+ output_operand_lossage ("invalid %%F value");
+ else
+ fprintf (file, "%d", 32 - 4 * (REGNO (x) - 68));
+ return;
+
+ case 'G':
+ /* X is a constant integer. If it is negative, print "m",
+ otherwise print "z". This is to make a aze or ame insn. */
+ if (GET_CODE (x) != CONST_INT)
+ output_operand_lossage ("invalid %%G value");
+ else if (INTVAL (x) >= 0)
+ putc ('z', file);
+ else
+ putc ('m', file);
+ return;
+
+ case 'h':
+ /* If constant, output low-order five bits. Otherwise,
+ write normally. */
+ if (INT_P (x))
+ fprintf (file, "%d", INT_LOWPART (x) & 31);
+ else
+ print_operand (file, x, 0);
+ return;
+
+ case 'H':
+ /* If constant, output low-order six bits. Otherwise,
+ write normally. */
+ if (INT_P (x))
+ fprintf (file, "%d", INT_LOWPART (x) & 63);
+ else
+ print_operand (file, x, 0);
+ return;
+
+ case 'I':
+ /* Print `i' if this is a constant, else nothing. */
+ if (INT_P (x))
+ putc ('i', file);
+ return;
+
+ case 'j':
+ /* Write the bit number in CCR for jump. */
+ i = ccr_bit (x, 0);
+ if (i == -1)
+ output_operand_lossage ("invalid %%j code");
+ else
+ fprintf (file, "%d", i);
+ return;
+
+ case 'J':
+ /* Similar, but add one for shift count in rlinm for scc and pass
+ scc flag to `ccr_bit'. */
+ i = ccr_bit (x, 1);
+ if (i == -1)
+ output_operand_lossage ("invalid %%J code");
+ else
+ /* If we want bit 31, write a shift count of zero, not 32. */
+ fprintf (file, "%d", i == 31 ? 0 : i + 1);
+ return;
+
+ case 'k':
+ /* X must be a constant. Write the 1's complement of the
+ constant. */
+ if (! INT_P (x))
+ output_operand_lossage ("invalid %%k value");
+
+ fprintf (file, "%d", ~ INT_LOWPART (x));
+ return;
+
+ case 'L':
+ /* Write second word of DImode or DFmode reference. Works on register
+ or non-indexed memory only. */
+ if (GET_CODE (x) == REG)
+ fprintf (file, "%s", reg_names[REGNO (x) + 1]);
+ else if (GET_CODE (x) == MEM)
+ {
+ /* Handle possible auto-increment. Since it is pre-increment and
+ we have already done it, we can just use an offset of word. */
+ if (GET_CODE (XEXP (x, 0)) == PRE_INC
+ || GET_CODE (XEXP (x, 0)) == PRE_DEC)
+ output_address (plus_constant (XEXP (XEXP (x, 0), 0),
+ UNITS_PER_WORD));
+ else
+ output_address (plus_constant (XEXP (x, 0), UNITS_PER_WORD));
+ if (small_data_operand (x, GET_MODE (x)))
+ fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
+ reg_names[SMALL_DATA_REG]);
+ }
+ return;
+
+ case 'm':
+ /* MB value for a mask operand. */
+ if (! mask_operand (x, VOIDmode))
+ output_operand_lossage ("invalid %%m value");
+
+ val = INT_LOWPART (x);
+
+ /* If the high bit is set and the low bit is not, the value is zero.
+ If the high bit is zero, the value is the first 1 bit we find from
+ the left. */
+ if ((val & 0x80000000) && ((val & 1) == 0))
+ {
+ putc ('0', file);
+ return;
+ }
+ else if ((val & 0x80000000) == 0)
+ {
+ for (i = 1; i < 32; i++)
+ if ((val <<= 1) & 0x80000000)
+ break;
+ fprintf (file, "%d", i);
+ return;
+ }
+
+ /* Otherwise, look for the first 0 bit from the right. The result is its
+ number plus 1. We know the low-order bit is one. */
+ for (i = 0; i < 32; i++)
+ if (((val >>= 1) & 1) == 0)
+ break;
+
+ /* If we ended in ...01, i would be 0. The correct value is 31, so
+ we want 31 - i. */
+ fprintf (file, "%d", 31 - i);
+ return;
+
+ case 'M':
+ /* ME value for a mask operand. */
+ if (! mask_operand (x, VOIDmode))
+ output_operand_lossage ("invalid %%M value");
+
+ val = INT_LOWPART (x);
+
+ /* If the low bit is set and the high bit is not, the value is 31.
+ If the low bit is zero, the value is the first 1 bit we find from
+ the right. */
+ if ((val & 1) && ((val & 0x80000000) == 0))
+ {
+ fputs ("31", file);
+ return;
+ }
+ else if ((val & 1) == 0)
+ {
+ for (i = 0; i < 32; i++)
+ if ((val >>= 1) & 1)
+ break;
+
+ /* If we had ....10, i would be 0. The result should be
+ 30, so we need 30 - i. */
+ fprintf (file, "%d", 30 - i);
+ return;
+ }
+
+ /* Otherwise, look for the first 0 bit from the left. The result is its
+ number minus 1. We know the high-order bit is one. */
+ for (i = 0; i < 32; i++)
+ if (((val <<= 1) & 0x80000000) == 0)
+ break;
+
+ fprintf (file, "%d", i);
+ return;
+
+ case 'N':
+ /* Write the number of elements in the vector times 4. */
+ if (GET_CODE (x) != PARALLEL)
+ output_operand_lossage ("invalid %%N value");
+
+ fprintf (file, "%d", XVECLEN (x, 0) * 4);
+ return;
+
+ case 'O':
+ /* Similar, but subtract 1 first. */
+ if (GET_CODE (x) != PARALLEL)
+ output_operand_lossage ("invalid %%O value");
+
+ fprintf (file, "%d", (XVECLEN (x, 0) - 1) * 4);
+ return;
+
+ case 'p':
+ /* X is a CONST_INT that is a power of two. Output the logarithm. */
+ if (! INT_P (x)
+ || (i = exact_log2 (INT_LOWPART (x))) < 0)
+ output_operand_lossage ("invalid %%p value");
+
+ fprintf (file, "%d", i);
+ return;
+
+ case 'P':
+ /* The operand must be an indirect memory reference. The result
+ is the register number. */
+ if (GET_CODE (x) != MEM || GET_CODE (XEXP (x, 0)) != REG
+ || REGNO (XEXP (x, 0)) >= 32)
+ output_operand_lossage ("invalid %%P value");
+
+ fprintf (file, "%d", REGNO (XEXP (x, 0)));
+ return;
+
+ /* CYGNUS LOCAL -- meissner/branch prediction */
+ case 'q':
+ case 'Q':
+ /* Write -/+ depending on whether a branch is expected to succeed */
+ succeed = (code == 'Q');
+ if (x != const0_rtx)
+ succeed = !succeed;
+
+ putc ((succeed) ? '+' : '-', file);
+ return;
+ /* END CYGNUS LOCAL -- meissner/branch prediction */
+
+ case 'R':
+ /* X is a CR register. Print the mask for `mtcrf'. */
+ if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
+ output_operand_lossage ("invalid %%R value");
+ else
+ fprintf (file, "%d", 128 >> (REGNO (x) - 68));
+ return;
+
+ case 's':
+ /* Low 5 bits of 32 - value */
+ if (! INT_P (x))
+ output_operand_lossage ("invalid %%s value");
+
+ fprintf (file, "%d", (32 - INT_LOWPART (x)) & 31);
+ return;
+
+ case 'S':
+ /* PowerPC64 mask position. All 0's and all 1's are excluded.
+ CONST_INT 32-bit mask is considered sign-extended so any
+ transition must occur within the CONST_INT, not on the boundary. */
+ if (! mask64_operand (x, VOIDmode))
+ output_operand_lossage ("invalid %%S value");
+
+ val = INT_LOWPART (x);
+
+ if (val & 1) /* Clear Left */
+ {
+ for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
+ if (!((val >>= 1) & 1))
+ break;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+ if (GET_CODE (x) == CONST_DOUBLE && i == 32)
+ {
+ val = CONST_DOUBLE_HIGH (x);
+
+ if (val == 0)
+ --i;
+ else
+ for (i = 32; i < 64; i++)
+ if (!((val >>= 1) & 1))
+ break;
+ }
+#endif
+ /* i = index of last set bit from right
+ mask begins at 63 - i from left */
+ if (i > 63)
+ output_operand_lossage ("%%S computed all 1's mask");
+ fprintf (file, "%d", 63 - i);
+ return;
+ }
+ else /* Clear Right */
+ {
+ for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
+ if ((val >>= 1) & 1)
+ break;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+ if (GET_CODE (x) == CONST_DOUBLE && i == 32)
+ {
+ val = CONST_DOUBLE_HIGH (x);
+
+ if (val == (HOST_WIDE_INT) -1)
+ --i;
+ else
+ for (i = 32; i < 64; i++)
+ if ((val >>= 1) & 1)
+ break;
+ }
+#endif
+ /* i = index of last clear bit from right
+ mask ends at 62 - i from left */
+ if (i > 62)
+ output_operand_lossage ("%%S computed all 0's mask");
+ fprintf (file, "%d", 62 - i);
+ return;
+ }
+
+ case 't':
+ /* Write 12 if this jump operation will branch if true, 4 otherwise.
+ All floating-point operations except NE branch true and integer
+ EQ, LT, GT, LTU and GTU also branch true. */
+ if (GET_RTX_CLASS (GET_CODE (x)) != '<')
+ output_operand_lossage ("invalid %%t value");
+
+ else if ((GET_MODE (XEXP (x, 0)) == CCFPmode
+ && GET_CODE (x) != NE)
+ || GET_CODE (x) == EQ
+ || GET_CODE (x) == LT || GET_CODE (x) == GT
+ || GET_CODE (x) == LTU || GET_CODE (x) == GTU)
+ fputs ("12", file);
+ else
+ putc ('4', file);
+ return;
+
+ case 'T':
+ /* Opposite of 't': write 4 if this jump operation will branch if true,
+ 12 otherwise. */
+ if (GET_RTX_CLASS (GET_CODE (x)) != '<')
+ output_operand_lossage ("invalid %%T value");
+
+ else if ((GET_MODE (XEXP (x, 0)) == CCFPmode
+ && GET_CODE (x) != NE)
+ || GET_CODE (x) == EQ
+ || GET_CODE (x) == LT || GET_CODE (x) == GT
+ || GET_CODE (x) == LTU || GET_CODE (x) == GTU)
+ putc ('4', file);
+ else
+ fputs ("12", file);
+ return;
+
+ case 'u':
+ /* High-order 16 bits of constant for use in unsigned operand. */
+ if (! INT_P (x))
+ output_operand_lossage ("invalid %%u value");
+
+ fprintf (file, "0x%x", (INT_LOWPART (x) >> 16) & 0xffff);
+ return;
+
+ case 'v':
+ /* High-order 16 bits of constant for use in signed operand. */
+ if (! INT_P (x))
+ output_operand_lossage ("invalid %%v value");
+
+ {
+ int value = (INT_LOWPART (x) >> 16) & 0xffff;
+
+ /* Solaris assembler doesn't like lis 0,0x80000 */
+ if (DEFAULT_ABI == ABI_SOLARIS && (value & 0x8000) != 0)
+ fprintf (file, "%d", value | (~0 << 16));
+ else
+ fprintf (file, "0x%x", value);
+ return;
+ }
+
+ case 'U':
+ /* Print `u' if this has an auto-increment or auto-decrement. */
+ if (GET_CODE (x) == MEM
+ && (GET_CODE (XEXP (x, 0)) == PRE_INC
+ || GET_CODE (XEXP (x, 0)) == PRE_DEC))
+ putc ('u', file);
+ return;
+
+ case 'V':
+ /* Print the trap code for this operand. */
+ switch (GET_CODE (x))
+ {
+ case EQ:
+ fputs ("eq", file); /* 4 */
+ break;
+ case NE:
+ fputs ("ne", file); /* 24 */
+ break;
+ case LT:
+ fputs ("lt", file); /* 16 */
+ break;
+ case LE:
+ fputs ("le", file); /* 20 */
+ break;
+ case GT:
+ fputs ("gt", file); /* 8 */
+ break;
+ case GE:
+ fputs ("ge", file); /* 12 */
+ break;
+ case LTU:
+ fputs ("llt", file); /* 2 */
+ break;
+ case LEU:
+ fputs ("lle", file); /* 6 */
+ break;
+ case GTU:
+ fputs ("lgt", file); /* 1 */
+ break;
+ case GEU:
+ fputs ("lge", file); /* 5 */
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case 'w':
+ /* If constant, low-order 16 bits of constant, signed. Otherwise, write
+ normally. */
+ if (INT_P (x))
+ fprintf (file, "%d",
+ (INT_LOWPART (x) & 0xffff) - 2 * (INT_LOWPART (x) & 0x8000));
+ else
+ print_operand (file, x, 0);
+ return;
+
+ case 'W':
+ /* If constant, low-order 16 bits of constant, unsigned.
+ Otherwise, write normally. */
+ if (INT_P (x))
+ fprintf (file, "%d", INT_LOWPART (x) & 0xffff);
+ else
+ print_operand (file, x, 0);
+ return;
+
+ case 'X':
+ if (GET_CODE (x) == MEM
+ && LEGITIMATE_INDEXED_ADDRESS_P (XEXP (x, 0)))
+ putc ('x', file);
+ return;
+
+ case 'Y':
+ /* Like 'L', for third word of TImode */
+ if (GET_CODE (x) == REG)
+ fprintf (file, "%s", reg_names[REGNO (x) + 2]);
+ else if (GET_CODE (x) == MEM)
+ {
+ if (GET_CODE (XEXP (x, 0)) == PRE_INC
+ || GET_CODE (XEXP (x, 0)) == PRE_DEC)
+ output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
+ else
+ output_address (plus_constant (XEXP (x, 0), 8));
+ if (small_data_operand (x, GET_MODE (x)))
+ fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
+ reg_names[SMALL_DATA_REG]);
+ }
+ return;
+
+ case 'z':
+ /* X is a SYMBOL_REF. Write out the name preceded by a
+ period and without any trailing data in brackets. Used for function
+ names. If we are configured for System V (or the embedded ABI) on
+ the PowerPC, do not emit the period, since those systems do not use
+ TOCs and the like. */
+ if (GET_CODE (x) != SYMBOL_REF)
+ abort ();
+
+ if (XSTR (x, 0)[0] != '.')
+ {
+ switch (DEFAULT_ABI)
+ {
+ default:
+ abort ();
+
+ case ABI_AIX:
+ putc ('.', file);
+ break;
+
+ case ABI_V4:
+ case ABI_AIX_NODESC:
+ case ABI_SOLARIS:
+ break;
+
+ case ABI_NT:
+ fputs ("..", file);
+ break;
+ }
+ }
+ RS6000_OUTPUT_BASENAME (file, XSTR (x, 0));
+ return;
+
+ case 'Z':
+ /* Like 'L', for last word of TImode. */
+ if (GET_CODE (x) == REG)
+ fprintf (file, "%s", reg_names[REGNO (x) + 3]);
+ else if (GET_CODE (x) == MEM)
+ {
+ if (GET_CODE (XEXP (x, 0)) == PRE_INC
+ || GET_CODE (XEXP (x, 0)) == PRE_DEC)
+ output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
+ else
+ output_address (plus_constant (XEXP (x, 0), 12));
+ if (small_data_operand (x, GET_MODE (x)))
+ fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
+ reg_names[SMALL_DATA_REG]);
+ }
+ return;
+
+ case 0:
+ if (GET_CODE (x) == REG)
+ fprintf (file, "%s", reg_names[REGNO (x)]);
+ else if (GET_CODE (x) == MEM)
+ {
+ /* We need to handle PRE_INC and PRE_DEC here, since we need to
+ know the width from the mode. */
+ if (GET_CODE (XEXP (x, 0)) == PRE_INC)
+ fprintf (file, "%d(%d)", GET_MODE_SIZE (GET_MODE (x)),
+ REGNO (XEXP (XEXP (x, 0), 0)));
+ else if (GET_CODE (XEXP (x, 0)) == PRE_DEC)
+ fprintf (file, "%d(%d)", - GET_MODE_SIZE (GET_MODE (x)),
+ REGNO (XEXP (XEXP (x, 0), 0)));
+ else
+ output_address (XEXP (x, 0));
+ }
+ else
+ output_addr_const (file, x);
+ return;
+
+ default:
+ output_operand_lossage ("invalid %%xn code");
+ }
+}
+
+/* Print the address of an operand. */
+
+void
+print_operand_address (file, x)
+ FILE *file;
+ register rtx x;
+{
+ if (GET_CODE (x) == REG)
+ fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
+ else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST || GET_CODE (x) == LABEL_REF)
+ {
+ output_addr_const (file, x);
+ if (small_data_operand (x, GET_MODE (x)))
+ fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
+ reg_names[SMALL_DATA_REG]);
+
+#ifdef TARGET_NO_TOC
+ else if (TARGET_NO_TOC)
+ ;
+#endif
+ else
+ fprintf (file, "(%s)", reg_names[ TARGET_MINIMAL_TOC ? 30 : 2 ]);
+ }
+ else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
+ {
+ if (REGNO (XEXP (x, 0)) == 0)
+ fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ],
+ reg_names[ REGNO (XEXP (x, 0)) ]);
+ else
+ fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 0)) ],
+ reg_names[ REGNO (XEXP (x, 1)) ]);
+ }
+ else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ fprintf (file, "%d(%s)", INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
+ else if (TARGET_ELF && !TARGET_64BIT && GET_CODE (x) == LO_SUM
+ && GET_CODE (XEXP (x, 0)) == REG && CONSTANT_P (XEXP (x, 1)))
+ {
+ output_addr_const (file, XEXP (x, 1));
+ fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
+ }
+ else
+ abort ();
+}
+
+/* This page contains routines that are used to determine what the function
+ prologue and epilogue code will do and write them out. */
+
+/* Return the first fixed-point register that is required to be saved. 32 if
+ none. */
+
+int
+first_reg_to_save ()
+{
+ int first_reg;
+
+ /* Find lowest numbered live register. */
+ for (first_reg = 13; first_reg <= 31; first_reg++)
+ if (regs_ever_live[first_reg])
+ break;
+
+ /* If profiling, then we must save/restore every register that contains
+ a parameter before/after the .__mcount call. Use registers from 30 down
+ to 23 to do this. Don't use the frame pointer in reg 31.
+
+ For now, save enough room for all of the parameter registers. */
+ if (DEFAULT_ABI == ABI_AIX && profile_flag)
+ if (first_reg > 23)
+ first_reg = 23;
+
+ return first_reg;
+}
+
+/* Similar, for FP regs. */
+
+int
+first_fp_reg_to_save ()
+{
+ int first_reg;
+
+ /* Find lowest numbered live register. */
+ for (first_reg = 14 + 32; first_reg <= 63; first_reg++)
+ if (regs_ever_live[first_reg])
+ break;
+
+ return first_reg;
+}
+
+/* Return non-zero if this function makes calls. */
+
+int
+rs6000_makes_calls ()
+{
+ rtx insn;
+
+ /* If we are profiling, we will be making a call to __mcount.
+ Under the System V ABI's, we store the LR directly, so
+ we don't need to do it here. */
+ if (DEFAULT_ABI == ABI_AIX && profile_flag)
+ return 1;
+
+ for (insn = get_insns (); insn; insn = next_insn (insn))
+ if (GET_CODE (insn) == CALL_INSN)
+ return 1;
+
+ return 0;
+}
+
+
+/* Calculate the stack information for the current function. This is
+ complicated by having two separate calling sequences, the AIX calling
+ sequence and the V.4 calling sequence.
+
+ AIX stack frames look like:
+ 32-bit 64-bit
+ SP----> +---------------------------------------+
+ | back chain to caller | 0 0
+ +---------------------------------------+
+ | saved CR | 4 8 (8-11)
+ +---------------------------------------+
+ | saved LR | 8 16
+ +---------------------------------------+
+ | reserved for compilers | 12 24
+ +---------------------------------------+
+ | reserved for binders | 16 32
+ +---------------------------------------+
+ | saved TOC pointer | 20 40
+ +---------------------------------------+
+ | Parameter save area (P) | 24 48
+ +---------------------------------------+
+ | Alloca space (A) | 24+P etc.
+ +---------------------------------------+
+ | Local variable space (L) | 24+P+A
+ +---------------------------------------+
+ | Float/int conversion temporary (X) | 24+P+A+L
+ +---------------------------------------+
+ | Save area for GP registers (G) | 24+P+A+X+L
+ +---------------------------------------+
+ | Save area for FP registers (F) | 24+P+A+X+L+G
+ +---------------------------------------+
+ old SP->| back chain to caller's caller |
+ +---------------------------------------+
+
+ The required alignment for AIX configurations is two words (i.e., 8
+ or 16 bytes).
+
+
+ V.4 stack frames look like:
+
+ SP----> +---------------------------------------+
+ | back chain to caller | 0
+ +---------------------------------------+
+ | caller's saved LR | 4
+ +---------------------------------------+
+ | Parameter save area (P) | 8
+ +---------------------------------------+
+ | Alloca space (A) | 8+P
+ +---------------------------------------+
+ | Varargs save area (V) | 8+P+A
+ +---------------------------------------+
+ | Local variable space (L) | 8+P+A+V
+ +---------------------------------------+
+ | Float/int conversion temporary (X) | 8+P+A+V+L
+ +---------------------------------------+
+ | saved CR (C) | 8+P+A+V+L+X
+ +---------------------------------------+
+ | Save area for GP registers (G) | 8+P+A+V+L+X+C
+ +---------------------------------------+
+ | Save area for FP registers (F) | 8+P+A+V+L+X+C+G
+ +---------------------------------------+
+ old SP->| back chain to caller's caller |
+ +---------------------------------------+
+
+ The required alignment for V.4 is 16 bytes, or 8 bytes if -meabi is
+ given. (But note below and in sysv4.h that we require only 8 and
+ may round up the size of our stack frame anyways. The historical
+ reason is early versions of powerpc-linux which didn't properly
+ align the stack at program startup. A happy side-effect is that
+ -mno-eabi libraries can be used with -meabi programs.)
+
+
+ A PowerPC Windows/NT frame looks like:
+
+ SP----> +---------------------------------------+
+ | back chain to caller | 0
+ +---------------------------------------+
+ | reserved | 4
+ +---------------------------------------+
+ | reserved | 8
+ +---------------------------------------+
+ | reserved | 12
+ +---------------------------------------+
+ | reserved | 16
+ +---------------------------------------+
+ | reserved | 20
+ +---------------------------------------+
+ | Parameter save area (P) | 24
+ +---------------------------------------+
+ | Alloca space (A) | 24+P
+ +---------------------------------------+
+ | Local variable space (L) | 24+P+A
+ +---------------------------------------+
+ | Float/int conversion temporary (X) | 24+P+A+L
+ +---------------------------------------+
+ | Save area for FP registers (F) | 24+P+A+L+X
+ +---------------------------------------+
+ | Possible alignment area (Y) | 24+P+A+L+X+F
+ +---------------------------------------+
+ | Save area for GP registers (G) | 24+P+A+L+X+F+Y
+ +---------------------------------------+
+ | Save area for CR (C) | 24+P+A+L+X+F+Y+G
+ +---------------------------------------+
+ | Save area for TOC (T) | 24+P+A+L+X+F+Y+G+C
+ +---------------------------------------+
+ | Save area for LR (R) | 24+P+A+L+X+F+Y+G+C+T
+ +---------------------------------------+
+ old SP->| back chain to caller's caller |
+ +---------------------------------------+
+
+ For NT, there is no specific order to save the registers, but in
+ order to support __builtin_return_address, the save area for the
+ link register needs to be in a known place, so we use -4 off of the
+ old SP. To support calls through pointers, we also allocate a
+ fixed slot to store the TOC, -8 off the old SP.
+
+ The required alignment for NT is 16 bytes.
+
+
+ The EABI configuration defaults to the V.4 layout, unless
+ -mcall-aix is used, in which case the AIX layout is used. However,
+ the stack alignment requirements may differ. If -mno-eabi is not
+ given, the required stack alignment is 8 bytes; if -mno-eabi is
+ given, the required alignment is 16 bytes. (But see V.4 comment
+ above.) */
+
+#ifndef ABI_STACK_BOUNDARY
+#define ABI_STACK_BOUNDARY STACK_BOUNDARY
+#endif
+
+rs6000_stack_t *
+rs6000_stack_info ()
+{
+ static rs6000_stack_t info, zero_info;
+ rs6000_stack_t *info_ptr = &info;
+ int reg_size = TARGET_32BIT ? 4 : 8;
+ enum rs6000_abi abi;
+ int total_raw_size;
+
+ /* Zero all fields portably */
+ info = zero_info;
+
+ /* Select which calling sequence */
+ info_ptr->abi = abi = DEFAULT_ABI;
+
+ /* Calculate which registers need to be saved & save area size */
+ info_ptr->first_gp_reg_save = first_reg_to_save ();
+ info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
+
+ info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
+ info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
+
+ /* Does this function call anything? */
+ info_ptr->calls_p = rs6000_makes_calls ();
+
+ /* Allocate space to save the toc. */
+ if (abi == ABI_NT && info_ptr->calls_p)
+ {
+ info_ptr->toc_save_p = 1;
+ info_ptr->toc_size = reg_size;
+ }
+
+ /* Does this machine need the float/int conversion area? */
+ info_ptr->fpmem_p = regs_ever_live[FPMEM_REGNUM];
+
+ /* If this is main and we need to call a function to set things up,
+ save main's arguments around the call. */
+#ifdef TARGET_EABI
+ if (TARGET_EABI)
+#endif
+ {
+ if (strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), "main") == 0
+ && DECL_CONTEXT (current_function_decl) == NULL_TREE)
+ {
+ info_ptr->main_p = 1;
+
+#ifdef NAME__MAIN
+ info_ptr->calls_p = 1;
+
+ if (DECL_ARGUMENTS (current_function_decl))
+ {
+ int i;
+ tree arg;
+
+ info_ptr->main_save_p = 1;
+ info_ptr->main_size = 0;
+
+ for ((i = 0), (arg = DECL_ARGUMENTS (current_function_decl));
+ arg != NULL_TREE && i < 8;
+ (arg = TREE_CHAIN (arg)), i++)
+ {
+ info_ptr->main_size += reg_size;
+ }
+ }
+#endif
+ }
+ }
+
+ /* Determine if we need to save the link register */
+ if (regs_ever_live[65]
+ || (DEFAULT_ABI == ABI_AIX && profile_flag)
+#ifdef TARGET_RELOCATABLE
+ || (TARGET_RELOCATABLE && (get_pool_size () != 0))
+#endif
+ || (info_ptr->first_fp_reg_save != 64
+ && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
+ || (abi == ABI_V4 && current_function_calls_alloca)
+ || (abi == ABI_SOLARIS && current_function_calls_alloca)
+ || info_ptr->calls_p)
+ {
+ info_ptr->lr_save_p = 1;
+ regs_ever_live[65] = 1;
+ if (abi == ABI_NT)
+ info_ptr->lr_size = reg_size;
+ }
+
+ /* Determine if we need to save the condition code registers */
+ if (regs_ever_live[70] || regs_ever_live[71] || regs_ever_live[72])
+ {
+ info_ptr->cr_save_p = 1;
+ if (abi == ABI_V4 || abi == ABI_NT || abi == ABI_SOLARIS)
+ info_ptr->cr_size = reg_size;
+ }
+
+ /* Determine various sizes */
+ info_ptr->reg_size = reg_size;
+ info_ptr->fixed_size = RS6000_SAVE_AREA;
+ info_ptr->varargs_size = RS6000_VARARGS_AREA;
+ info_ptr->vars_size = RS6000_ALIGN (get_frame_size (), 8);
+ info_ptr->parm_size = RS6000_ALIGN (current_function_outgoing_args_size, 8);
+ info_ptr->fpmem_size = (info_ptr->fpmem_p) ? 8 : 0;
+ info_ptr->save_size = RS6000_ALIGN (info_ptr->fp_size
+ + info_ptr->gp_size
+ + info_ptr->cr_size
+ + info_ptr->lr_size
+ + info_ptr->toc_size
+ + info_ptr->main_size, 8);
+
+ /* Calculate the offsets */
+ switch (abi)
+ {
+ case ABI_NONE:
+ default:
+ abort ();
+
+ case ABI_AIX:
+ case ABI_AIX_NODESC:
+ info_ptr->fp_save_offset = - info_ptr->fp_size;
+ info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_size;
+ info_ptr->main_save_offset = info_ptr->gp_save_offset - info_ptr->main_size;
+ info_ptr->cr_save_offset = reg_size; /* first word when 64-bit. */
+ info_ptr->lr_save_offset = 2*reg_size;
+ break;
+
+ case ABI_V4:
+ case ABI_SOLARIS:
+ info_ptr->fp_save_offset = - info_ptr->fp_size;
+ info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_size;
+ info_ptr->cr_save_offset = info_ptr->gp_save_offset - info_ptr->cr_size;
+ info_ptr->toc_save_offset = info_ptr->cr_save_offset - info_ptr->toc_size;
+ info_ptr->main_save_offset = info_ptr->toc_save_offset - info_ptr->main_size;
+ info_ptr->lr_save_offset = reg_size;
+ break;
+
+ case ABI_NT:
+ info_ptr->lr_save_offset = -reg_size;
+ info_ptr->toc_save_offset = info_ptr->lr_save_offset - info_ptr->lr_size;
+ info_ptr->cr_save_offset = info_ptr->toc_save_offset - info_ptr->toc_size;
+ info_ptr->gp_save_offset = info_ptr->cr_save_offset - info_ptr->cr_size - info_ptr->gp_size + reg_size;
+ info_ptr->fp_save_offset = info_ptr->gp_save_offset - info_ptr->fp_size;
+ if (info_ptr->fp_size && ((- info_ptr->fp_save_offset) % 8) != 0)
+ info_ptr->fp_save_offset -= reg_size;
+
+ info_ptr->main_save_offset = info_ptr->fp_save_offset - info_ptr->main_size;
+ break;
+ }
+
+ /* Ensure that fpmem_offset will be aligned to an 8-byte boundary. */
+ if (info_ptr->fpmem_p
+ && (info_ptr->main_save_offset - info_ptr->fpmem_size) % 8)
+ info_ptr->fpmem_size += reg_size;
+
+ total_raw_size = (info_ptr->vars_size
+ + info_ptr->parm_size
+ + info_ptr->fpmem_size
+ + info_ptr->save_size
+ + info_ptr->varargs_size
+ + info_ptr->fixed_size);
+
+ info_ptr->total_size = RS6000_ALIGN (total_raw_size, ABI_STACK_BOUNDARY / BITS_PER_UNIT);
+
+ /* Determine if we need to allocate any stack frame:
+
+ For AIX we need to push the stack if a frame pointer is needed (because
+ the stack might be dynamically adjusted), if we are debugging, if we
+ make calls, or if the sum of fp_save, gp_save, fpmem, and local variables
+ are more than the space needed to save all non-volatile registers:
+ 32-bit: 18*8 + 19*4 = 220 or 64-bit: 18*8 + 19*8 = 296
+
+ For V.4 we don't have the stack cushion that AIX uses, but assume that
+ the debugger can handle stackless frames. */
+
+ if (info_ptr->calls_p)
+ info_ptr->push_p = 1;
+
+ else if (abi == ABI_V4 || abi == ABI_NT || abi == ABI_SOLARIS)
+ info_ptr->push_p = (total_raw_size > info_ptr->fixed_size
+ || (abi == ABI_NT ? info_ptr->lr_save_p
+ : info_ptr->calls_p));
+
+ else
+ info_ptr->push_p = (frame_pointer_needed
+ || write_symbols != NO_DEBUG
+ || ((total_raw_size - info_ptr->fixed_size)
+ > (TARGET_32BIT ? 220 : 296)));
+
+ if (info_ptr->fpmem_p)
+ {
+ info_ptr->fpmem_offset = info_ptr->main_save_offset - info_ptr->fpmem_size;
+ rs6000_fpmem_size = info_ptr->fpmem_size;
+ rs6000_fpmem_offset = (info_ptr->push_p
+ ? info_ptr->total_size + info_ptr->fpmem_offset
+ : info_ptr->fpmem_offset);
+ }
+ else
+ info_ptr->fpmem_offset = 0;
+
+ /* Zero offsets if we're not saving those registers */
+ if (info_ptr->fp_size == 0)
+ info_ptr->fp_save_offset = 0;
+
+ if (info_ptr->gp_size == 0)
+ info_ptr->gp_save_offset = 0;
+
+ if (!info_ptr->lr_save_p)
+ info_ptr->lr_save_offset = 0;
+
+ if (!info_ptr->cr_save_p)
+ info_ptr->cr_save_offset = 0;
+
+ if (!info_ptr->toc_save_p)
+ info_ptr->toc_save_offset = 0;
+
+ if (!info_ptr->main_save_p)
+ info_ptr->main_save_offset = 0;
+
+ return info_ptr;
+}
+
+void
+debug_stack_info (info)
+ rs6000_stack_t *info;
+{
+ char *abi_string;
+
+ if (!info)
+ info = rs6000_stack_info ();
+
+ fprintf (stderr, "\nStack information for function %s:\n",
+ ((current_function_decl && DECL_NAME (current_function_decl))
+ ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
+ : "<unknown>"));
+
+ switch (info->abi)
+ {
+ default: abi_string = "Unknown"; break;
+ case ABI_NONE: abi_string = "NONE"; break;
+ case ABI_AIX: abi_string = "AIX"; break;
+ case ABI_AIX_NODESC: abi_string = "AIX"; break;
+ case ABI_V4: abi_string = "V.4"; break;
+ case ABI_SOLARIS: abi_string = "Solaris"; break;
+ case ABI_NT: abi_string = "NT"; break;
+ }
+
+ fprintf (stderr, "\tABI = %5s\n", abi_string);
+
+ if (info->first_gp_reg_save != 32)
+ fprintf (stderr, "\tfirst_gp_reg_save = %5d\n", info->first_gp_reg_save);
+
+ if (info->first_fp_reg_save != 64)
+ fprintf (stderr, "\tfirst_fp_reg_save = %5d\n", info->first_fp_reg_save);
+
+ if (info->lr_save_p)
+ fprintf (stderr, "\tlr_save_p = %5d\n", info->lr_save_p);
+
+ if (info->cr_save_p)
+ fprintf (stderr, "\tcr_save_p = %5d\n", info->cr_save_p);
+
+ if (info->toc_save_p)
+ fprintf (stderr, "\ttoc_save_p = %5d\n", info->toc_save_p);
+
+ if (info->push_p)
+ fprintf (stderr, "\tpush_p = %5d\n", info->push_p);
+
+ if (info->calls_p)
+ fprintf (stderr, "\tcalls_p = %5d\n", info->calls_p);
+
+ if (info->main_p)
+ fprintf (stderr, "\tmain_p = %5d\n", info->main_p);
+
+ if (info->main_save_p)
+ fprintf (stderr, "\tmain_save_p = %5d\n", info->main_save_p);
+
+ if (info->fpmem_p)
+ fprintf (stderr, "\tfpmem_p = %5d\n", info->fpmem_p);
+
+ if (info->gp_save_offset)
+ fprintf (stderr, "\tgp_save_offset = %5d\n", info->gp_save_offset);
+
+ if (info->fp_save_offset)
+ fprintf (stderr, "\tfp_save_offset = %5d\n", info->fp_save_offset);
+
+ if (info->lr_save_offset)
+ fprintf (stderr, "\tlr_save_offset = %5d\n", info->lr_save_offset);
+
+ if (info->cr_save_offset)
+ fprintf (stderr, "\tcr_save_offset = %5d\n", info->cr_save_offset);
+
+ if (info->toc_save_offset)
+ fprintf (stderr, "\ttoc_save_offset = %5d\n", info->toc_save_offset);
+
+ if (info->varargs_save_offset)
+ fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
+
+ if (info->main_save_offset)
+ fprintf (stderr, "\tmain_save_offset = %5d\n", info->main_save_offset);
+
+ if (info->fpmem_offset)
+ fprintf (stderr, "\tfpmem_offset = %5d\n", info->fpmem_offset);
+
+ if (info->total_size)
+ fprintf (stderr, "\ttotal_size = %5d\n", info->total_size);
+
+ if (info->varargs_size)
+ fprintf (stderr, "\tvarargs_size = %5d\n", info->varargs_size);
+
+ if (info->vars_size)
+ fprintf (stderr, "\tvars_size = %5d\n", info->vars_size);
+
+ if (info->parm_size)
+ fprintf (stderr, "\tparm_size = %5d\n", info->parm_size);
+
+ if (info->fpmem_size)
+ fprintf (stderr, "\tfpmem_size = %5d\n", info->fpmem_size);
+
+ if (info->fixed_size)
+ fprintf (stderr, "\tfixed_size = %5d\n", info->fixed_size);
+
+ if (info->gp_size)
+ fprintf (stderr, "\tgp_size = %5d\n", info->gp_size);
+
+ if (info->fp_size)
+ fprintf (stderr, "\tfp_size = %5d\n", info->fp_size);
+
+ if (info->lr_size)
+ fprintf (stderr, "\tlr_size = %5d\n", info->cr_size);
+
+ if (info->cr_size)
+ fprintf (stderr, "\tcr_size = %5d\n", info->cr_size);
+
+ if (info->toc_size)
+ fprintf (stderr, "\ttoc_size = %5d\n", info->toc_size);
+
+ if (info->main_size)
+ fprintf (stderr, "\tmain_size = %5d\n", info->main_size);
+
+ if (info->save_size)
+ fprintf (stderr, "\tsave_size = %5d\n", info->save_size);
+
+ if (info->reg_size != 4)
+ fprintf (stderr, "\treg_size = %5d\n", info->reg_size);
+
+ fprintf (stderr, "\n");
+}
+
+
+/* CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling */
+#if 0
+/* END CYGNUS LOCAL */
+
+/* Write out an instruction to load the TOC_TABLE address into register 30.
+ This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is
+ a constant pool. */
+
+void
+rs6000_output_load_toc_table (file, reg)
+ FILE *file;
+ int reg;
+{
+ char buf[256];
+
+#ifdef USING_SVR4_H
+ if (TARGET_RELOCATABLE)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
+ fprintf (file, "\tbl ");
+ assemble_name (file, buf);
+ fprintf (file, "\n");
+
+ /* possibly create the toc section */
+ if (!toc_initialized)
+ {
+ toc_section ();
+ function_section (current_function_decl);
+ }
+
+ /* If not first call in this function, we need to put the
+ different between .LCTOC1 and the address we get to right
+ after the bl. It will mess up disassembling the instructions
+ but that can't be helped. We will later need to bias the
+ address before loading. */
+ if (rs6000_pic_func_labelno != rs6000_pic_labelno)
+ {
+ char *init_ptr = TARGET_32BIT ? ".long" : ".quad";
+ char *buf_ptr;
+
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LCL", rs6000_pic_labelno);
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
+ STRIP_NAME_ENCODING (buf_ptr, buf);
+ fprintf (file, "\t%s %s-", init_ptr, buf_ptr);
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
+ fprintf (file, "%s\n", buf_ptr);
+ }
+
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LCF", rs6000_pic_labelno);
+ fprintf (file, "\tmflr %s\n", reg_names[reg]);
+
+ if (rs6000_pic_func_labelno != rs6000_pic_labelno)
+ asm_fprintf(file, "\t{cal|la} %s,%d(%s)\n", reg_names[reg],
+ (TARGET_32BIT ? 4 : 8), reg_names[reg]);
+
+ asm_fprintf (file, (TARGET_32BIT) ? "\t{l|lwz} %s,(" : "\tld %s,(",
+ reg_names[0]);
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
+ assemble_name (file, buf);
+ fputs ("-", file);
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
+ assemble_name (file, buf);
+ fprintf (file, ")(%s)\n", reg_names[reg]);
+ asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
+ reg_names[reg], reg_names[0], reg_names[reg]);
+ rs6000_pic_labelno++;
+ }
+ else if (!TARGET_64BIT)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
+ asm_fprintf (file, "\t{liu|lis} %s,", reg_names[reg]);
+ assemble_name (file, buf);
+ fputs ("@ha\n", file);
+ asm_fprintf (file, "\t{cal|la} %s,", reg_names[reg]);
+ assemble_name (file, buf);
+ asm_fprintf (file, "@l(%s)\n", reg_names[reg]);
+ }
+ else
+ abort ();
+
+#else /* !USING_SVR4_H */
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 0);
+ asm_fprintf (file, TARGET_32BIT ? "\t{l|lwz} %s," : "\tld %s,",
+ reg_names[reg]);
+ assemble_name (file, buf);
+ asm_fprintf (file, "(%s)\n", reg_names[2]);
+#endif /* USING_SVR4_H */
+}
+
+
+/* Emit the correct code for allocating stack space. If COPY_R12, make sure a copy
+ of the old frame is left in r12. */
+
+void
+rs6000_allocate_stack_space (file, size, copy_r12)
+ FILE *file;
+ int size;
+ int copy_r12;
+{
+ int neg_size = -size;
+ if (TARGET_UPDATE)
+ {
+ if (size < 32767)
+ asm_fprintf (file,
+ (TARGET_32BIT) ? "\t{stu|stwu} %s,%d(%s)\n" : "\tstdu %s,%d(%s)\n",
+ reg_names[1], neg_size, reg_names[1]);
+ else
+ {
+ if (copy_r12)
+ fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]);
+
+ asm_fprintf (file, "\t{liu|lis} %s,%d\n\t{oril|ori} %s,%s,%d\n",
+ reg_names[0], (neg_size >> 16) & 0xffff,
+ reg_names[0], reg_names[0], neg_size & 0xffff);
+ asm_fprintf (file,
+ (TARGET_32BIT) ? "\t{stux|stwux} %s,%s,%s\n" : "\tstdux %s,%s,%s\n",
+ reg_names[1], reg_names[1], reg_names[0]);
+ }
+ }
+ else
+ {
+ fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]);
+ if (size < 32767)
+ asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
+ reg_names[1], neg_size, reg_names[1]);
+ else
+ {
+ asm_fprintf (file, "\t{liu|lis} %s,%d\n\t{oril|ori} %s,%s,%d\n",
+ reg_names[0], (neg_size >> 16) & 0xffff,
+ reg_names[0], reg_names[0], neg_size & 0xffff);
+ asm_fprintf (file, "\t{cax|add} %s,%s,%s\n", reg_names[1],
+ reg_names[0], reg_names[1]);
+ }
+
+ asm_fprintf (file,
+ (TARGET_32BIT) ? "\t{st|stw} %s,0(%s)\n" : "\tstd %s,0(%s)\n",
+ reg_names[12], reg_names[1]);
+ }
+}
+
+
+/* Write function prologue. */
+void
+output_prolog (file, size)
+ FILE *file;
+ int size ATTRIBUTE_UNUSED;
+{
+ rs6000_stack_t *info = rs6000_stack_info ();
+ int reg_size = info->reg_size;
+ char *store_reg;
+ char *load_reg;
+ int sp_reg = 1;
+ int sp_offset = 0;
+
+ if (TARGET_32BIT)
+ {
+ store_reg = "\t{st|stw} %s,%d(%s)\n";
+ load_reg = "\t{l|lwz} %s,%d(%s)\n";
+ }
+ else
+ {
+ store_reg = "\tstd %s,%d(%s)\n";
+ load_reg = "\tlld %s,%d(%s)\n";
+ }
+
+ if (TARGET_DEBUG_STACK)
+ debug_stack_info (info);
+
+ /* Write .extern for any function we will call to save and restore fp
+ values. */
+ if (info->first_fp_reg_save < 64 && !FP_SAVE_INLINE (info->first_fp_reg_save))
+ fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n",
+ SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX,
+ RESTORE_FP_PREFIX, info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
+
+ /* Write .extern for truncation routines, if needed. */
+ if (rs6000_trunc_used && ! trunc_defined)
+ {
+ fprintf (file, "\t.extern .%s\n\t.extern .%s\n",
+ RS6000_ITRUNC, RS6000_UITRUNC);
+ trunc_defined = 1;
+ }
+
+ /* Write .extern for AIX common mode routines, if needed. */
+ if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
+ {
+ fputs ("\t.extern __mulh\n", file);
+ fputs ("\t.extern __mull\n", file);
+ fputs ("\t.extern __divss\n", file);
+ fputs ("\t.extern __divus\n", file);
+ fputs ("\t.extern __quoss\n", file);
+ fputs ("\t.extern __quous\n", file);
+ common_mode_defined = 1;
+ }
+
+ /* For V.4, update stack before we do any saving and set back pointer. */
+ if (info->push_p && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS))
+ {
+ if (info->total_size < 32767)
+ sp_offset = info->total_size;
+ else
+ sp_reg = 12;
+ rs6000_allocate_stack_space (file, info->total_size, sp_reg == 12);
+ }
+
+ /* If we use the link register, get it into r0. */
+ if (info->lr_save_p)
+ asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
+
+ /* If we need to save CR, put it into r12. */
+ if (info->cr_save_p && sp_reg != 12)
+ asm_fprintf (file, "\tmfcr %s\n", reg_names[12]);
+
+ /* Do any required saving of fpr's. If only one or two to save, do it
+ ourself. Otherwise, call function. Note that since they are statically
+ linked, we do not need a nop following them. */
+ if (FP_SAVE_INLINE (info->first_fp_reg_save))
+ {
+ int regno = info->first_fp_reg_save;
+ int loc = info->fp_save_offset + sp_offset;
+
+ for ( ; regno < 64; regno++, loc += 8)
+ asm_fprintf (file, "\tstfd %s,%d(%s)\n", reg_names[regno], loc, reg_names[sp_reg]);
+ }
+ else if (info->first_fp_reg_save != 64)
+ asm_fprintf (file, "\tbl %s%d%s\n", SAVE_FP_PREFIX,
+ info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
+
+ /* Now save gpr's. */
+ if (! TARGET_MULTIPLE || info->first_gp_reg_save == 31 || TARGET_64BIT)
+ {
+ int regno = info->first_gp_reg_save;
+ int loc = info->gp_save_offset + sp_offset;
+
+ for ( ; regno < 32; regno++, loc += reg_size)
+ asm_fprintf (file, store_reg, reg_names[regno], loc, reg_names[sp_reg]);
+ }
+
+ else if (info->first_gp_reg_save != 32)
+ asm_fprintf (file, "\t{stm|stmw} %s,%d(%s)\n",
+ reg_names[info->first_gp_reg_save],
+ info->gp_save_offset + sp_offset,
+ reg_names[sp_reg]);
+
+ /* Save main's arguments if we need to call a function */
+#ifdef NAME__MAIN
+ if (info->main_save_p)
+ {
+ int regno;
+ int loc = info->main_save_offset + sp_offset;
+ int size = info->main_size;
+
+ for (regno = 3; size > 0; regno++, loc += reg_size, size -= reg_size)
+ asm_fprintf (file, store_reg, reg_names[regno], loc, reg_names[sp_reg]);
+ }
+#endif
+
+ /* Save lr if we used it. */
+ if (info->lr_save_p)
+ asm_fprintf (file, store_reg, reg_names[0], info->lr_save_offset + sp_offset,
+ reg_names[sp_reg]);
+
+ /* Save CR if we use any that must be preserved. */
+ if (info->cr_save_p)
+ {
+ if (sp_reg == 12) /* If r12 is used to hold the original sp, copy cr now */
+ {
+ asm_fprintf (file, "\tmfcr %s\n", reg_names[0]);
+ asm_fprintf (file, store_reg, reg_names[0],
+ info->cr_save_offset + sp_offset,
+ reg_names[sp_reg]);
+ }
+ else
+ asm_fprintf (file, store_reg, reg_names[12], info->cr_save_offset + sp_offset,
+ reg_names[sp_reg]);
+ }
+
+ /* NT needs us to probe the stack frame every 4k pages for large frames, so
+ do it here. */
+ if (DEFAULT_ABI == ABI_NT && info->total_size > 4096)
+ {
+ if (info->total_size < 32768)
+ {
+ int probe_offset = 4096;
+ while (probe_offset < info->total_size)
+ {
+ asm_fprintf (file, "\t{l|lwz} %s,%d(%s)\n", reg_names[0], -probe_offset, reg_names[1]);
+ probe_offset += 4096;
+ }
+ }
+ else
+ {
+ int probe_iterations = info->total_size / 4096;
+ static int probe_labelno = 0;
+ char buf[256];
+
+ if (probe_iterations < 32768)
+ asm_fprintf (file, "\tli %s,%d\n", reg_names[12], probe_iterations);
+ else
+ {
+ asm_fprintf (file, "\tlis %s,%d\n", reg_names[12], probe_iterations >> 16);
+ if (probe_iterations & 0xffff)
+ asm_fprintf (file, "\tori %s,%s,%d\n", reg_names[12], reg_names[12],
+ probe_iterations & 0xffff);
+ }
+ asm_fprintf (file, "\tmtctr %s\n", reg_names[12]);
+ asm_fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]);
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LCprobe", probe_labelno);
+ asm_fprintf (file, "\t{lu|lwzu} %s,-4096(%s)\n", reg_names[0], reg_names[12]);
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCprobe", probe_labelno++);
+ fputs ("\tbdnz ", file);
+ assemble_name (file, buf);
+ fputs ("\n", file);
+ }
+ }
+
+ /* Update stack and set back pointer unless this is V.4, which was done previously */
+ if (info->push_p && DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
+ rs6000_allocate_stack_space (file, info->total_size, FALSE);
+
+ /* Set frame pointer, if needed. */
+ if (frame_pointer_needed)
+ asm_fprintf (file, "\tmr %s,%s\n", reg_names[31], reg_names[1]);
+
+#ifdef NAME__MAIN
+ /* If we need to call a function to set things up for main, do so now
+ before dealing with the TOC. */
+ if (info->main_p)
+ {
+ char *prefix = "";
+
+ switch (DEFAULT_ABI)
+ {
+ case ABI_AIX: prefix = "."; break;
+ case ABI_NT: prefix = ".."; break;
+ }
+
+ fprintf (file, "\tbl %s%s\n", prefix, NAME__MAIN);
+#ifdef RS6000_CALL_GLUE2
+ fprintf (file, "\t%s%s%s\n", RS6000_CALL_GLUE2, prefix, NAME_MAIN);
+#else
+#ifdef RS6000_CALL_GLUE
+ if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ fprintf (file, "\t%s\n", RS6000_CALL_GLUE);
+#endif
+#endif
+
+ if (info->main_save_p)
+ {
+ int regno;
+ int loc;
+ int size = info->main_size;
+
+ if (info->total_size < 32767)
+ {
+ loc = info->total_size + info->main_save_offset;
+ for (regno = 3; size > 0; regno++, size -= reg_size, loc += reg_size)
+ asm_fprintf (file, load_reg, reg_names[regno], loc, reg_names[1]);
+ }
+ else
+ {
+ int neg_size = info->main_save_offset - info->total_size;
+ loc = 0;
+ asm_fprintf (file, "\t{liu|lis} %s,%d\n\t{oril|ori} %s,%s,%d\n",
+ reg_names[0], (neg_size >> 16) & 0xffff,
+ reg_names[0], reg_names[0], neg_size & 0xffff);
+
+ asm_fprintf (file, "\t{sf|subf} %s,%s,%s\n", reg_names[0], reg_names[0],
+ reg_names[1]);
+
+ for (regno = 3; size > 0; regno++, size -= reg_size, loc += reg_size)
+ asm_fprintf (file, load_reg, reg_names[regno], loc, reg_names[0]);
+ }
+ }
+ }
+#endif
+
+
+ /* If TARGET_MINIMAL_TOC, and the constant pool is needed, then load the
+ TOC_TABLE address into register 30. */
+ if (TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
+ {
+#ifdef USING_SVR4_H
+ if (!profile_flag)
+ rs6000_pic_func_labelno = rs6000_pic_labelno;
+#endif
+ rs6000_output_load_toc_table (file, 30);
+ }
+
+ if (DEFAULT_ABI == ABI_NT)
+ {
+ assemble_name (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
+ fputs (".b:\n", file);
+ }
+}
+
+/* Write function epilogue. */
+
+void
+output_epilog (file, size)
+ FILE *file;
+ int size ATTRIBUTE_UNUSED;
+{
+ rs6000_stack_t *info = rs6000_stack_info ();
+ char *load_reg = (TARGET_32BIT) ? "\t{l|lwz} %s,%d(%s)\n" : "\tld %s,%d(%s)\n";
+ rtx insn = get_last_insn ();
+ int sp_reg = 1;
+ int sp_offset = 0;
+
+ /* If the last insn was a BARRIER, we don't have to write anything except
+ the trace table. */
+ if (GET_CODE (insn) == NOTE)
+ insn = prev_nonnote_insn (insn);
+ if (insn == 0 || GET_CODE (insn) != BARRIER)
+ {
+ /* If we have a frame pointer, a call to alloca, or a large stack
+ frame, restore the old stack pointer using the backchain. Otherwise,
+ we know what size to update it with. */
+ if (frame_pointer_needed || current_function_calls_alloca
+ || info->total_size > 32767)
+ {
+ /* Under V.4, don't reset the stack pointer until after we're done
+ loading the saved registers. */
+ if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ sp_reg = 11;
+
+ asm_fprintf (file, load_reg, reg_names[sp_reg], 0, reg_names[1]);
+ }
+ else if (info->push_p)
+ {
+ if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ sp_offset = info->total_size;
+ else
+ asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
+ reg_names[1], info->total_size, reg_names[1]);
+ }
+
+ /* Get the old lr if we saved it. */
+ if (info->lr_save_p)
+ asm_fprintf (file, load_reg, reg_names[0], info->lr_save_offset + sp_offset, reg_names[sp_reg]);
+
+ /* Get the old cr if we saved it. */
+ if (info->cr_save_p)
+ asm_fprintf (file, load_reg, reg_names[12], info->cr_save_offset + sp_offset, reg_names[sp_reg]);
+
+ /* Set LR here to try to overlap restores below. */
+ if (info->lr_save_p)
+ asm_fprintf (file, "\tmtlr %s\n", reg_names[0]);
+
+ /* Restore gpr's. */
+ if (! TARGET_MULTIPLE || info->first_gp_reg_save == 31 || TARGET_64BIT)
+ {
+ int regno = info->first_gp_reg_save;
+ int loc = info->gp_save_offset + sp_offset;
+ int reg_size = (TARGET_32BIT) ? 4 : 8;
+
+ for ( ; regno < 32; regno++, loc += reg_size)
+ asm_fprintf (file, load_reg, reg_names[regno], loc, reg_names[sp_reg]);
+ }
+
+ else if (info->first_gp_reg_save != 32)
+ asm_fprintf (file, "\t{lm|lmw} %s,%d(%s)\n",
+ reg_names[info->first_gp_reg_save],
+ info->gp_save_offset + sp_offset,
+ reg_names[sp_reg]);
+
+ /* Restore fpr's if we can do it without calling a function. */
+ if (FP_SAVE_INLINE (info->first_fp_reg_save))
+ {
+ int regno = info->first_fp_reg_save;
+ int loc = info->fp_save_offset + sp_offset;
+
+ for ( ; regno < 64; regno++, loc += 8)
+ asm_fprintf (file, "\tlfd %s,%d(%s)\n", reg_names[regno], loc, reg_names[sp_reg]);
+ }
+
+ /* If we saved cr, restore it here. Just those of cr2, cr3, and cr4
+ that were used. */
+ if (info->cr_save_p)
+ asm_fprintf (file, "\tmtcrf %d,%s\n",
+ (regs_ever_live[70] != 0) * 0x20
+ + (regs_ever_live[71] != 0) * 0x10
+ + (regs_ever_live[72] != 0) * 0x8, reg_names[12]);
+
+ /* If this is V.4, unwind the stack pointer after all of the loads
+ have been done */
+ if (sp_offset != 0)
+ asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
+ reg_names[1], sp_offset, reg_names[1]);
+ else if (sp_reg != 1)
+ asm_fprintf (file, "\tmr %s,%s\n", reg_names[1], reg_names[sp_reg]);
+
+ /* If we have to restore more than two FP registers, branch to the
+ restore function. It will return to our caller. */
+ if (info->first_fp_reg_save != 64 && !FP_SAVE_INLINE (info->first_fp_reg_save))
+ asm_fprintf (file, "\tb %s%d%s\n", RESTORE_FP_PREFIX,
+ info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
+ else
+ asm_fprintf (file, "\t{br|blr}\n");
+ }
+
+ /* Output a traceback table here. See /usr/include/sys/debug.h for info
+ on its format.
+
+ We don't output a traceback table if -finhibit-size-directive was
+ used. The documentation for -finhibit-size-directive reads
+ ``don't output a @code{.size} assembler directive, or anything
+ else that would cause trouble if the function is split in the
+ middle, and the two halves are placed at locations far apart in
+ memory.'' The traceback table has this property, since it
+ includes the offset from the start of the function to the
+ traceback table itself.
+
+ System V.4 Powerpc's (and the embedded ABI derived from it) use a
+ different traceback table. */
+ if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive)
+ {
+ char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+ int fixed_parms, float_parms, parm_info;
+ int i;
+
+ while (*fname == '.') /* V.4 encodes . in the name */
+ fname++;
+
+ /* Need label immediately before tbtab, so we can compute its offset
+ from the function start. */
+ if (*fname == '*')
+ ++fname;
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+ ASM_OUTPUT_LABEL (file, fname);
+
+ /* The .tbtab pseudo-op can only be used for the first eight
+ expressions, since it can't handle the possibly variable
+ length fields that follow. However, if you omit the optional
+ fields, the assembler outputs zeros for all optional fields
+ anyways, giving each variable length field is minimum length
+ (as defined in sys/debug.h). Thus we can not use the .tbtab
+ pseudo-op at all. */
+
+ /* An all-zero word flags the start of the tbtab, for debuggers
+ that have to find it by searching forward from the entry
+ point or from the current pc. */
+ fputs ("\t.long 0\n", file);
+
+ /* Tbtab format type. Use format type 0. */
+ fputs ("\t.byte 0,", file);
+
+ /* Language type. Unfortunately, there doesn't seem to be any
+ official way to get this info, so we use language_string. C
+ is 0. C++ is 9. No number defined for Obj-C, so use the
+ value for C for now. There is no official value for Java,
+ although IBM appears to be using 13. There is no official value
+ for Chill, so we've choosen 44 pseudo-randomly. */
+ if (! strcmp (language_string, "GNU C")
+ || ! strcmp (language_string, "GNU Obj-C"))
+ i = 0;
+ else if (! strcmp (language_string, "GNU F77"))
+ i = 1;
+ else if (! strcmp (language_string, "GNU Ada"))
+ i = 3;
+ else if (! strcmp (language_string, "GNU Pascal"))
+ i = 2;
+ else if (! strcmp (language_string, "GNU C++"))
+ i = 9;
+ else if (! strcmp (language_string, "GNU Java"))
+ i = 13;
+ else if (! strcmp (language_string, "GNU CHILL"))
+ i = 44;
+ else
+ abort ();
+ fprintf (file, "%d,", i);
+
+ /* 8 single bit fields: global linkage (not set for C extern linkage,
+ apparently a PL/I convention?), out-of-line epilogue/prologue, offset
+ from start of procedure stored in tbtab, internal function, function
+ has controlled storage, function has no toc, function uses fp,
+ function logs/aborts fp operations. */
+ /* Assume that fp operations are used if any fp reg must be saved. */
+ fprintf (file, "%d,", (1 << 5) | ((info->first_fp_reg_save != 64) << 1));
+
+ /* 6 bitfields: function is interrupt handler, name present in
+ proc table, function calls alloca, on condition directives
+ (controls stack walks, 3 bits), saves condition reg, saves
+ link reg. */
+ /* The `function calls alloca' bit seems to be set whenever reg 31 is
+ set up as a frame pointer, even when there is no alloca call. */
+ fprintf (file, "%d,",
+ ((1 << 6) | (frame_pointer_needed << 5)
+ | (info->cr_save_p << 1) | (info->lr_save_p)));
+
+ /* 3 bitfields: saves backchain, spare bit, number of fpr saved
+ (6 bits). */
+ fprintf (file, "%d,",
+ (info->push_p << 7) | (64 - info->first_fp_reg_save));
+
+ /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits). */
+ fprintf (file, "%d,", (32 - first_reg_to_save ()));
+
+ {
+ /* Compute the parameter info from the function decl argument
+ list. */
+ tree decl;
+ int next_parm_info_bit;
+
+ next_parm_info_bit = 31;
+ parm_info = 0;
+ fixed_parms = 0;
+ float_parms = 0;
+
+ for (decl = DECL_ARGUMENTS (current_function_decl);
+ decl; decl = TREE_CHAIN (decl))
+ {
+ rtx parameter = DECL_INCOMING_RTL (decl);
+ enum machine_mode mode = GET_MODE (parameter);
+
+ if (GET_CODE (parameter) == REG)
+ {
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+ {
+ int bits;
+
+ float_parms++;
+
+ if (mode == SFmode)
+ bits = 0x2;
+ else if (mode == DFmode)
+ bits = 0x3;
+ else
+ abort ();
+
+ /* If only one bit will fit, don't or in this entry. */
+ if (next_parm_info_bit > 0)
+ parm_info |= (bits << (next_parm_info_bit - 1));
+ next_parm_info_bit -= 2;
+ }
+ else
+ {
+ fixed_parms += ((GET_MODE_SIZE (mode)
+ + (UNITS_PER_WORD - 1))
+ / UNITS_PER_WORD);
+ next_parm_info_bit -= 1;
+ }
+ }
+ }
+ }
+
+ /* Number of fixed point parameters. */
+ /* This is actually the number of words of fixed point parameters; thus
+ an 8 byte struct counts as 2; and thus the maximum value is 8. */
+ fprintf (file, "%d,", fixed_parms);
+
+ /* 2 bitfields: number of floating point parameters (7 bits), parameters
+ all on stack. */
+ /* This is actually the number of fp registers that hold parameters;
+ and thus the maximum value is 13. */
+ /* Set parameters on stack bit if parameters are not in their original
+ registers, regardless of whether they are on the stack? Xlc
+ seems to set the bit when not optimizing. */
+ fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
+
+ /* Optional fields follow. Some are variable length. */
+
+ /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
+ 11 double float. */
+ /* There is an entry for each parameter in a register, in the order that
+ they occur in the parameter list. Any intervening arguments on the
+ stack are ignored. If the list overflows a long (max possible length
+ 34 bits) then completely leave off all elements that don't fit. */
+ /* Only emit this long if there was at least one parameter. */
+ if (fixed_parms || float_parms)
+ fprintf (file, "\t.long %d\n", parm_info);
+
+ /* Offset from start of code to tb table. */
+ fputs ("\t.long ", file);
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+ RS6000_OUTPUT_BASENAME (file, fname);
+ fputs ("-.", file);
+ RS6000_OUTPUT_BASENAME (file, fname);
+ putc ('\n', file);
+
+ /* Interrupt handler mask. */
+ /* Omit this long, since we never set the interrupt handler bit
+ above. */
+
+ /* Number of CTL (controlled storage) anchors. */
+ /* Omit this long, since the has_ctl bit is never set above. */
+
+ /* Displacement into stack of each CTL anchor. */
+ /* Omit this list of longs, because there are no CTL anchors. */
+
+ /* Length of function name. */
+ fprintf (file, "\t.short %d\n", (int) strlen (fname));
+
+ /* Function name. */
+ assemble_string (fname, strlen (fname));
+
+ /* Register for alloca automatic storage; this is always reg 31.
+ Only emit this if the alloca bit was set above. */
+ if (frame_pointer_needed)
+ fputs ("\t.byte 31\n", file);
+ }
+
+ if (DEFAULT_ABI == ABI_NT)
+ {
+ RS6000_OUTPUT_BASENAME (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
+ fputs (".e:\nFE_MOT_RESVD..", file);
+ RS6000_OUTPUT_BASENAME (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
+ fputs (":\n", file);
+ }
+}
+
+/* CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling */
+#endif
+
+/* This part (from CYGNUS LOCAL to CYGNUS local) contains code needed
+ for scheduling of prologue and epilogue. The part is based on the
+ analogous functions above. Now it works only for EABI. The code
+ contains new code for RTL generation and old code for assembler
+ output (for output prologue/epilogue for other ABI besides EABI).
+ So now this implementation is different from MIPS one. When RTL
+ generation for all other ABI is written, the assembler code output
+ (and code above between #if 0 and #endif) can be removed and the
+ implementation will become analogous to MIPS/ARM one. The code for
+ RTL generation for the following ABI must be finished and tested
+ for this (please pay attention onto 64 bit targets too):
+
+ ABI_AIX, ABI_AIX_NODESC
+ ABI_NT, ABI_SOLARIS (did they die???)
+
+*/
+
+/* Write out an assembler instruction (if !RTX_FLAG) otherwise RTL
+ insns to load the TOC_TABLE address into register 30. This is only
+ necessary when TARGET_TOC, TARGET_MINIMAL_TOC, and there is a
+ constant pool. */
+
+void
+rs6000_output_load_toc_table (file, reg, rtx_flag)
+ FILE *file;
+ int reg;
+ int rtx_flag;
+{
+ char buf[256];
+ rtx insn;
+ enum machine_mode reg_mode = (TARGET_32BIT) ? SImode : DImode;
+
+#ifdef USING_SVR4_H
+ if (TARGET_RELOCATABLE)
+ {
+ if (rtx_flag)
+ {
+ if (reg != 30)
+ abort;
+ insn = emit_call_insn
+ (TARGET_32BIT
+ ? gen_loadsi_svr4_relocatable_toc (gen_rtx
+ (REG, reg_mode, 0))
+ : gen_loaddi_svr4_relocatable_toc (gen_rtx
+ (REG, reg_mode, 0)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ return;
+ }
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
+ fprintf (file, "\tbl ");
+ assemble_name (file, buf);
+ fprintf (file, "\n");
+
+ /* possibly create the toc section */
+ if (!toc_initialized)
+ {
+ toc_section ();
+ function_section (current_function_decl);
+ }
+
+ /* If not first call in this function, we need to put the
+ different between .LCTOC1 and the address we get to right
+ after the bl. It will mess up disassembling the instructions
+ but that can't be helped. We will later need to bias the
+ address before loading. */
+ if (rs6000_pic_func_labelno != rs6000_pic_labelno)
+ {
+ char *init_ptr = TARGET_32BIT ? ".long" : ".quad";
+ char *buf_ptr;
+
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LCL", rs6000_pic_labelno);
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
+ STRIP_NAME_ENCODING (buf_ptr, buf);
+ fprintf (file, "\t%s %s-", init_ptr, buf_ptr);
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
+ fprintf (file, "%s\n", buf_ptr);
+ }
+
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LCF", rs6000_pic_labelno);
+ fprintf (file, "\tmflr %s\n", reg_names[reg]);
+
+ if (rs6000_pic_func_labelno != rs6000_pic_labelno)
+ asm_fprintf(file, "\t{cal|la} %s,%d(%s)\n", reg_names[reg],
+ (TARGET_32BIT ? 4 : 8), reg_names[reg]);
+
+ asm_fprintf (file, (TARGET_32BIT) ? "\t{l|lwz} %s,(" : "\tld %s,(",
+ reg_names[0]);
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
+ assemble_name (file, buf);
+ fputs ("-", file);
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
+ assemble_name (file, buf);
+ fprintf (file, ")(%s)\n", reg_names[reg]);
+ asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
+ reg_names[reg], reg_names[0], reg_names[reg]);
+ rs6000_pic_labelno++;
+ }
+ else if (!TARGET_64BIT)
+ {
+ if (rtx_flag)
+ {
+ if (reg != 30)
+ abort;
+ insn = emit_insn (gen_loadsi_svr4_toc ());
+ RTX_FRAME_RELATED_P (insn) = 1;
+ return;
+ }
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
+ asm_fprintf (file, "\t{liu|lis} %s,", reg_names[reg]);
+ assemble_name (file, buf);
+ fputs ("@ha\n", file);
+ asm_fprintf (file, "\t{cal|la} %s,", reg_names[reg]);
+ assemble_name (file, buf);
+ asm_fprintf (file, "@l(%s)\n", reg_names[reg]);
+ }
+ else
+ abort ();
+
+#else /* !USING_SVR4_H */
+ if (rtx_flag)
+ {
+ if (reg != 30)
+ abort ();
+ insn
+ = emit_insn (TARGET_32BIT
+ ? gen_loadsi_nonsvr4_toc (gen_rtx (REG, reg_mode, 2))
+ : gen_loaddi_nonsvr4_toc (gen_rtx (REG, reg_mode, 2)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ return;
+ }
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 0);
+ asm_fprintf (file, TARGET_32BIT ? "\t{l|lwz} %s," : "\tld %s,",
+ reg_names[reg]);
+ assemble_name (file, buf);
+ asm_fprintf (file, "(%s)\n", reg_names[2]);
+#endif /* USING_SVR4_H */
+}
+
+
+
+/* Emit the correct code for allocating stack space. If COPY_R12,
+ make sure a copy of the old frame is left in r12. We generate RTX
+ instead of assembler code when RTX_FLAG is true. */
+static void
+rs6000_allocate_stack_space (file, size, copy_r12, rtx_flag)
+ FILE *file;
+ int size;
+ int copy_r12;
+ int rtx_flag;
+{
+ int neg_size = -size;
+ rtx insn;
+ enum machine_mode reg_mode = (TARGET_32BIT) ? SImode : DImode;
+
+ if (TARGET_UPDATE)
+ {
+ if (size < 32767)
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file,
+ (TARGET_32BIT)
+ ? "\t{stu|stwu} %s,%d(%s)\n" : "\tstdu %s,%d(%s)\n",
+ reg_names[1], neg_size, reg_names[1]);
+ else if (rtx_flag)
+ {
+ rtx incr = GEN_INT (neg_size);
+
+ if (TARGET_32BIT)
+ insn = emit_insn (gen_movsi_update (stack_pointer_rtx,
+ stack_pointer_rtx, incr,
+ stack_pointer_rtx));
+ else
+ insn = emit_insn (gen_movdi_update (stack_pointer_rtx,
+ stack_pointer_rtx, incr,
+ stack_pointer_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else
+ {
+ if (copy_r12)
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]);
+ else if (rtx_flag)
+ {
+ rtx r12_rtx = gen_rtx (REG, Pmode, 12);
+
+ insn = emit_move_insn (r12_rtx, stack_pointer_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ {
+ asm_fprintf (file, "\t{liu|lis} %s,%d\n\t{oril|ori} %s,%s,%d\n",
+ reg_names[0], (neg_size >> 16) & 0xffff,
+ reg_names[0], reg_names[0], neg_size & 0xffff);
+ asm_fprintf (file,
+ (TARGET_32BIT)
+ ? "\t{stux|stwux} %s,%s,%s\n"
+ : "\tstdux %s,%s,%s\n",
+ reg_names[1], reg_names[1], reg_names[0]);
+ }
+ else if (rtx_flag)
+ {
+ rtx r0_rtx = gen_rtx (REG, reg_mode, 0);
+ rtx const_int_rtx;
+
+ const_int_rtx = GEN_INT (((neg_size >> 16) & 0xffff) << 16);
+ insn = emit_insn (gen_rtx (SET, VOIDmode,
+ r0_rtx, const_int_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ const_int_rtx = GEN_INT (neg_size & 0xffff);
+ insn = emit_insn (TARGET_32BIT
+ ? gen_iorsi3 (r0_rtx, r0_rtx, const_int_rtx)
+ : gen_iordi3 (r0_rtx, r0_rtx, const_int_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ insn = emit_insn (TARGET_32BIT
+ ? gen_movsi_update (stack_pointer_rtx,
+ stack_pointer_rtx, r0_rtx,
+ stack_pointer_rtx)
+ : gen_movdi_update (stack_pointer_rtx,
+ stack_pointer_rtx, r0_rtx,
+ stack_pointer_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+ else
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]);
+ else if (rtx_flag)
+ {
+ rtx r12_rtx = gen_rtx (REG, Pmode, 12);
+
+ insn = emit_move_insn (r12_rtx, stack_pointer_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ if (size < 32767)
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
+ reg_names[1], neg_size, reg_names[1]);
+ else if (rtx_flag)
+ {
+ rtx reg_rtx = gen_rtx (REG, reg_mode, 1);
+
+ insn = emit_insn (gen_addsi3 (reg_rtx, reg_rtx,
+ GEN_INT (neg_size)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ {
+ asm_fprintf (file,
+ "\t{liu|lis} %s,%d\n\t{oril|ori} %s,%s,%d\n",
+ reg_names[0], (neg_size >> 16) & 0xffff,
+ reg_names[0], reg_names[0], neg_size & 0xffff);
+ }
+ else if (rtx_flag)
+ {
+ rtx r0_rtx = gen_rtx (REG, reg_mode, 0);
+ rtx const_int_rtx;
+
+ const_int_rtx = GEN_INT (((neg_size >> 16) & 0xffff) << 16);
+ insn = emit_insn (gen_rtx (SET, VOIDmode, r0_rtx,
+ const_int_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ const_int_rtx = GEN_INT (neg_size & 0xffff);
+ insn = emit_insn (TARGET_32BIT
+ ? gen_iorsi3 (r0_rtx, r0_rtx, const_int_rtx)
+ : gen_iordi3 (r0_rtx, r0_rtx, const_int_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\t{cax|add} %s,%s,%s\n", reg_names[1],
+ reg_names[0], reg_names[1]);
+ else if (rtx_flag)
+ {
+ rtx r0_rtx = gen_rtx (REG, reg_mode, 0);
+ rtx r1_rtx = gen_rtx (REG, reg_mode, 1);
+
+ insn = emit_insn (TARGET_32BIT
+ ? gen_addsi3 (r1_rtx, r0_rtx, r1_rtx)
+ : gen_adddi3 (r1_rtx, r0_rtx, r1_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file,
+ (TARGET_32BIT)
+ ? "\t{st|stw} %s,0(%s)\n" : "\tstd %s,0(%s)\n",
+ reg_names[12], reg_names[1]);
+ else if (rtx_flag)
+ {
+ rtx r12_rtx = gen_rtx (REG, reg_mode, 12);
+ rtx r1_rtx = gen_rtx (REG, Pmode, 1);
+
+ insn = emit_move_insn (gen_rtx (MEM, reg_mode, r1_rtx), r12_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+}
+
+
+/* Write function prologue. The function is called twice with two
+ different values of RTX_FLAG. Generate or not rtl or assembler
+ code is depended from value of TARGET_SCHED_PROLOG. */
+
+static void
+rs6000_prolog (file, rtx_flag, info)
+ FILE *file;
+ int rtx_flag;
+ rs6000_stack_t *info;
+{
+ int reg_size = info->reg_size;
+ char *store_reg;
+ char *load_reg;
+ int sp_reg = 1;
+ int sp_offset = 0;
+ enum machine_mode reg_mode;
+ rtx insn;
+ rtx sp_reg_rtx = stack_pointer_rtx;
+
+ if (TARGET_32BIT)
+ {
+ store_reg = "\t{st|stw} %s,%d(%s)\n";
+ load_reg = "\t{l|lwz} %s,%d(%s)\n";
+ reg_mode = SImode;
+ }
+ else
+ {
+ store_reg = "\tstd %s,%d(%s)\n";
+ load_reg = "\tlld %s,%d(%s)\n";
+ reg_mode = DImode;
+ }
+
+ if (TARGET_DEBUG_STACK)
+ debug_stack_info (info);
+
+ /* Write .extern for any function we will call to save and restore fp
+ values. */
+ if (!rtx_flag && info->first_fp_reg_save < 64
+ && !FP_SAVE_INLINE (info->first_fp_reg_save))
+ fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n",
+ SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX,
+ RESTORE_FP_PREFIX, info->first_fp_reg_save - 32,
+ RESTORE_FP_SUFFIX);
+
+ /* Write .extern for truncation routines, if needed. */
+ if (!rtx_flag && rs6000_trunc_used && ! trunc_defined)
+ {
+ fprintf (file, "\t.extern .%s\n\t.extern .%s\n",
+ RS6000_ITRUNC, RS6000_UITRUNC);
+ trunc_defined = 1;
+ }
+
+ /* Write .extern for AIX common mode routines, if needed. */
+ if (!rtx_flag && !TARGET_POWER && !TARGET_POWERPC && !common_mode_defined)
+ {
+ fputs ("\t.extern __mulh\n", file);
+ fputs ("\t.extern __mull\n", file);
+ fputs ("\t.extern __divss\n", file);
+ fputs ("\t.extern __divus\n", file);
+ fputs ("\t.extern __quoss\n", file);
+ fputs ("\t.extern __quous\n", file);
+ common_mode_defined = 1;
+ }
+
+ /* For V.4, update stack before we do any saving and set back pointer. */
+ if (info->push_p && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS))
+ {
+ if (info->total_size < 32767)
+ sp_offset = info->total_size;
+ else
+ {
+ sp_reg = 12;
+ sp_reg_rtx = gen_rtx (REG, Pmode, 12);
+ }
+ rs6000_allocate_stack_space (file, info->total_size, sp_reg == 12,
+ rtx_flag);
+ }
+
+ /* If we use the link register, get it into r0. */
+ if (info->lr_save_p)
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, Pmode, 0),
+ gen_rtx (REG, Pmode, 65));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ /* If we need to save CR, put it into r12. */
+ if (info->cr_save_p && sp_reg != 12)
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\tmfcr %s\n", reg_names[12]);
+ else if (rtx_flag)
+ {
+ insn = emit_insn (TARGET_32BIT
+ ? gen_movesi_from_cr (gen_rtx (REG, reg_mode, 12))
+ : gen_movedi_from_cr (gen_rtx
+ (REG, reg_mode, 12)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ /* Do any required saving of fpr's. If only one or two to save, do it
+ ourself. Otherwise, call function. Note that since they are statically
+ linked, we do not need a nop following them. */
+ if (FP_SAVE_INLINE (info->first_fp_reg_save))
+ {
+ int regno = info->first_fp_reg_save;
+ int loc = info->fp_save_offset + sp_offset;
+
+ for ( ; regno < 64; regno++, loc += 8)
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\tstfd %s,%d(%s)\n",
+ reg_names[regno], loc, reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx
+ (MEM, DFmode,
+ gen_rtx (PLUS, Pmode,
+ sp_reg_rtx, GEN_INT (loc))),
+ gen_rtx (REG, DFmode, regno));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else if (info->first_fp_reg_save != 64)
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\tbl %s%d%s\n", SAVE_FP_PREFIX,
+ info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
+ else if (rtx_flag)
+ {
+ static char label [100];
+
+ sprintf (label, "%s%d%s", SAVE_FP_PREFIX,
+ info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
+ insn = emit_jump_insn (gen_jump (gen_rtx (SYMBOL_REF, Pmode,
+ label)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ /* Now save gpr's. */
+ if (! TARGET_MULTIPLE || info->first_gp_reg_save == 31 || TARGET_64BIT)
+ {
+ int regno = info->first_gp_reg_save;
+ int loc = info->gp_save_offset + sp_offset;
+
+ for ( ; regno < 32; regno++, loc += reg_size)
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, store_reg,
+ reg_names[regno], loc, reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode, sp_reg_rtx,
+ GEN_INT (loc))),
+ gen_rtx (REG, reg_mode, regno));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else if (info->first_gp_reg_save != 32)
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\t{stm|stmw} %s,%d(%s)\n",
+ reg_names[info->first_gp_reg_save],
+ info->gp_save_offset + sp_offset,
+ reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ int loc;
+ int regno;
+
+ for (loc = info->gp_save_offset + sp_offset,
+ regno = info->first_gp_reg_save;
+ regno <= 31;
+ regno++, loc += reg_size)
+ {
+ insn = emit_move_insn (gen_rtx (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ sp_reg_rtx,
+ GEN_INT (loc))),
+ gen_rtx (REG, reg_mode, regno));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+ /* Save main's arguments if we need to call a function */
+#ifdef NAME__MAIN
+ if (info->main_save_p)
+ {
+ int regno;
+ int loc = info->main_save_offset + sp_offset;
+ int size = info->main_size;
+
+ for (regno = 3; size > 0; regno++, loc += reg_size, size -= reg_size)
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, store_reg,
+ reg_names[regno], loc, reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode, sp_reg_rtx,
+ GEN_INT (loc))),
+ gen_rtx (REG, reg_mode, regno));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+#endif
+
+ /* Save lr if we used it. */
+ if (info->lr_save_p)
+ {
+ int loc = info->lr_save_offset + sp_offset;
+
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, store_reg, reg_names[0], loc, reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode, sp_reg_rtx,
+ GEN_INT (loc))),
+ gen_rtx (REG, reg_mode, 0));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ /* Save CR if we use any that must be preserved. */
+ if (info->cr_save_p)
+ {
+ int loc = info->cr_save_offset + sp_offset;
+
+ if (sp_reg == 12)
+ /* If r12 is used to hold the original sp, copy cr now */
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ {
+ asm_fprintf (file, "\tmfcr %s\n", reg_names[0]);
+ asm_fprintf (file, store_reg, reg_names[0],
+ loc, reg_names[sp_reg]);
+ }
+ else if (rtx_flag)
+ {
+ insn = emit_insn (TARGET_32BIT
+ ? gen_movesi_from_cr (gen_rtx
+ (REG, reg_mode, 0))
+ : gen_movedi_from_cr (gen_rtx
+ (REG, reg_mode, 0)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ insn = emit_move_insn (gen_rtx (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ sp_reg_rtx,
+ GEN_INT (loc))),
+ gen_rtx (REG, reg_mode, 0));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+
+ asm_fprintf (file, store_reg, reg_names[12],
+ loc, reg_names[sp_reg]);
+
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ sp_reg_rtx,
+ GEN_INT (loc))),
+ gen_rtx (REG, reg_mode, 12));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+
+ /* NT needs us to probe the stack frame every 4k pages for large frames, so
+ do it here. */
+ if (DEFAULT_ABI == ABI_NT && info->total_size > 4096)
+ {
+ if (info->total_size < 32768)
+ {
+ int probe_offset = 4096;
+ while (probe_offset < info->total_size)
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\t{l|lwz} %s,%d(%s)\n",
+ reg_names[0], -probe_offset, reg_names[1]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, 0),
+ gen_rtx
+ (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (-probe_offset))));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ probe_offset += 4096;
+ }
+ }
+ else
+ {
+ int probe_iterations = info->total_size / 4096;
+ static int probe_labelno = 0;
+ char buf[256];
+ rtx r12_rtx = gen_rtx (REG, reg_mode, 12);
+ rtx r0_rtx = gen_rtx (REG, reg_mode, 0);
+
+ if (probe_iterations < 32768)
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\tli %s,%d\n",
+ reg_names[12], probe_iterations);
+ else if (rtx_flag)
+ {
+ insn
+ = emit_insn (TARGET_32BIT
+ ? gen_addsi3 (r12_rtx, r0_rtx,
+ GEN_INT (probe_iterations))
+ : gen_adddi3 (r12_rtx, r0_rtx,
+ GEN_INT (probe_iterations)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\tlis %s,%d\n",
+ reg_names[12], probe_iterations >> 16);
+ else if (rtx_flag)
+ {
+ insn = emit_insn (TARGET_32BIT
+ ? gen_addsi3 (r12_rtx, r0_rtx,
+ GEN_INT ((probe_iterations
+ >> 16) << 16))
+ : gen_adddi3 (r12_rtx, r0_rtx,
+ GEN_INT ((probe_iterations
+ >> 16) << 16)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ if (probe_iterations & 0xffff)
+ {
+ rtx const_int_rtx;
+
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\tori %s,%s,%d\n", reg_names[12],
+ reg_names[12], probe_iterations & 0xffff);
+ else if (rtx_flag)
+ {
+ const_int_rtx = GEN_INT (probe_iterations & 0xffff);
+
+ insn = emit_insn (TARGET_32BIT
+ ? gen_iorsi3 (r12_rtx, r12_rtx,
+ const_int_rtx)
+ : gen_iordi3 (r12_rtx, r12_rtx,
+ const_int_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ {
+ asm_fprintf (file, "\tmtctr %s\n", reg_names[12]);
+ asm_fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]);
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LCprobe", probe_labelno);
+ asm_fprintf (file, "\t{lu|lwzu} %s,-4096(%s)\n",
+ reg_names[0], reg_names[12]);
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCprobe", probe_labelno++);
+ fputs ("\tbdnz ", file);
+ assemble_name (file, buf);
+ fputs ("\n", file);
+ }
+ else if (rtx_flag)
+ {
+ abort (); /* ??? vmakarov: Not implemented yet (ABI_NT). */
+ }
+ }
+ }
+
+ /* Update stack and set back pointer unless this is V.4, which was
+ done previously */
+ if (info->push_p && DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
+ rs6000_allocate_stack_space (file, info->total_size, FALSE, rtx_flag);
+
+ /* Set frame pointer, if needed. */
+ if (frame_pointer_needed)
+ {
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, "\tmr %s,%s\n", reg_names[31], reg_names[1]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, 31),
+ gen_rtx (REG, reg_mode, 1));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+#ifdef NAME__MAIN
+ /* If we need to call a function to set things up for main, do so now
+ before dealing with the TOC. */
+ if (info->main_p)
+ {
+ char *prefix = "";
+
+ switch (DEFAULT_ABI)
+ {
+ case ABI_AIX: prefix = "."; break;
+ case ABI_NT: prefix = ".."; break;
+ }
+
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ {
+ fprintf (file, "\tbl %s%s\n", prefix, NAME__MAIN);
+#ifdef RS6000_CALL_GLUE2
+ fprintf (file, "\t%s%s%s\n", RS6000_CALL_GLUE2, prefix, NAME_MAIN);
+#else
+#ifdef RS6000_CALL_GLUE
+ if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ fprintf (file, "\t%s\n", RS6000_CALL_GLUE);
+#endif
+#endif
+ }
+ else if (rtx_flag)
+ {
+ static char name [100];
+
+ sprintf (name, "%s%s", prefix, NAME__MAIN);
+ insn = emit_call_insn (gen_rtx
+ (PARALLEL, VOIDmode,
+ gen_rtvec
+ (3,
+ gen_rtx (CALL, VOIDmode,
+ gen_rtx (MEM, FUNCTION_MODE,
+ gen_rtx (SYMBOL_REF,
+ Pmode, name)),
+ const0_rtx),
+ gen_rtx (USE, VOIDmode, const0_rtx),
+ gen_rtx (CLOBBER, VOIDmode,
+ gen_rtx (REG, reg_mode, 65)))));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ if (info->main_save_p)
+ {
+ int regno;
+ int loc;
+ int size = info->main_size;
+
+ if (info->total_size < 32767)
+ {
+ loc = info->total_size + info->main_save_offset;
+ for (regno = 3;
+ size > 0;
+ regno++, size -= reg_size, loc += reg_size)
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, load_reg,
+ reg_names[regno], loc, reg_names[1]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, regno),
+ gen_rtx
+ (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (loc))));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else
+ {
+ int neg_size = info->main_save_offset - info->total_size;
+ loc = 0;
+
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ {
+ asm_fprintf (file,
+ "\t{liu|lis} %s,%d\n\t{oril|ori} %s,%s,%d\n",
+ reg_names[0], (neg_size >> 16) & 0xffff,
+ reg_names[0], reg_names[0], neg_size & 0xffff);
+ asm_fprintf (file, "\t{sf|subf} %s,%s,%s\n",
+ reg_names[0], reg_names[0], reg_names[1]);
+ }
+ else if (rtx_flag)
+ {
+ rtx r0_rtx = gen_rtx (REG, reg_mode, 0);
+ rtx const_int_rtx;
+
+ const_int_rtx = GEN_INT (((neg_size >> 16) & 0xffff) << 16);
+ insn = emit_insn (gen_rtx (SET, VOIDmode, r0_rtx,
+ const_int_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ const_int_rtx = GEN_INT (neg_size & 0xffff);
+ insn = emit_insn (TARGET_32BIT
+ ? gen_iorsi3 (r0_rtx, r0_rtx,
+ const_int_rtx)
+ : gen_iordi3 (r0_rtx, r0_rtx,
+ const_int_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ insn = emit_insn (gen_rtx (MINUS, reg_mode,
+ r0_rtx,
+ gen_rtx (REG, reg_mode, 1),
+ r0_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ for (regno = 3;
+ size > 0;
+ regno++, size -= reg_size, loc += reg_size)
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ asm_fprintf (file, load_reg,
+ reg_names[regno], loc, reg_names[0]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, regno),
+ gen_rtx
+ (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ gen_rtx (REG, reg_mode,
+ 0),
+ GEN_INT (loc))));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+ }
+#endif
+
+
+ /* If TARGET_MINIMAL_TOC, and the constant pool is needed, then load the
+ TOC_TABLE address into register 30. */
+ if (TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
+ {
+#ifdef USING_SVR4_H
+ if (!profile_flag)
+ rs6000_pic_func_labelno = rs6000_pic_labelno;
+#endif
+ /* There is no oportuntity to optimize loading toc table --
+ linear dependecies. */
+ if (!rtx_flag && !TARGET_SCHED_PROLOG)
+ rs6000_output_load_toc_table (file, 30, FALSE);
+ else if (rtx_flag)
+ rs6000_output_load_toc_table (file, 30, TRUE);
+ }
+
+ if (DEFAULT_ABI == ABI_NT)
+ {
+ assemble_name (file,
+ XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
+ fputs (".b:\n", file);
+ }
+}
+
+/* Write function epilogue. The function is called twice with two
+ different values of RTX_FLAG. Generate or not rtl or assembler
+ code is depended from value of TARGET_SCHED_PROLOG. */
+
+static void
+rs6000_epilog (file, rtx_flag, info)
+ FILE *file;
+ int rtx_flag;
+ rs6000_stack_t *info;
+{
+ char *load_reg = ((TARGET_32BIT) ?
+ "\t{l|lwz} %s,%d(%s)\n" : "\tld %s,%d(%s)\n");
+ enum machine_mode reg_mode = (TARGET_32BIT) ? SImode : DImode;
+ rtx insn = get_last_insn ();
+ int sp_reg = 1;
+ rtx sp_reg_rtx = gen_rtx (REG, reg_mode, 1);
+ int sp_offset = 0;
+
+ /* If the last insn was a BARRIER, we don't have to write anything except
+ the trace table. */
+ if (insn != 0 && GET_CODE (insn) == NOTE)
+ insn = prev_nonnote_insn (insn);
+ if (insn == 0 || GET_CODE (insn) != BARRIER)
+ {
+ /* If we have a frame pointer, a call to alloca, or a large stack
+ frame, restore the old stack pointer using the backchain. Otherwise,
+ we know what size to update it with. */
+ if (frame_pointer_needed || current_function_calls_alloca
+ || info->total_size > 32767)
+ {
+ /* Under V.4, don't reset the stack pointer until after we're done
+ loading the saved registers. */
+ if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ {
+ sp_reg = 11;
+ sp_reg_rtx = gen_rtx (REG, reg_mode, 11);
+ }
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, load_reg, reg_names[sp_reg], 0, reg_names[1]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (sp_reg_rtx,
+ gen_rtx
+ (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ gen_rtx (REG, reg_mode, 1),
+ const0_rtx)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else if (info->push_p)
+ {
+ if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ sp_offset = info->total_size;
+ else
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
+ reg_names[1], info->total_size, reg_names[1]);
+ else if (rtx_flag)
+ {
+ rtx reg_rtx = gen_rtx (REG, reg_mode, 1);
+
+ insn
+ = emit_insn (TARGET_32BIT
+ ? gen_addsi3 (reg_rtx, reg_rtx,
+ GEN_INT (info->total_size))
+ : gen_adddi3 (reg_rtx, reg_rtx,
+ GEN_INT (info->total_size)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+
+ /* Get the old lr if we saved it. */
+ if (info->lr_save_p)
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, load_reg, reg_names[0],
+ info->lr_save_offset + sp_offset, reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, 0),
+ gen_rtx
+ (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ sp_reg_rtx,
+ GEN_INT (info->lr_save_offset
+ + sp_offset))));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ /* Get the old cr if we saved it. */
+ if (info->cr_save_p)
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, load_reg, reg_names[12],
+ info->cr_save_offset + sp_offset, reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, 12),
+ gen_rtx
+ (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ sp_reg_rtx,
+ GEN_INT (info->cr_save_offset
+ + sp_offset))));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ /* Set LR here to try to overlap restores below. */
+ if (info->lr_save_p)
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\tmtlr %s\n", reg_names[0]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, 65),
+ gen_rtx (REG, reg_mode, 0));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ /* Restore gpr's. */
+ if (! TARGET_MULTIPLE || info->first_gp_reg_save == 31 || TARGET_64BIT)
+ {
+ int regno = info->first_gp_reg_save;
+ int loc = info->gp_save_offset + sp_offset;
+ int reg_size = (TARGET_32BIT) ? 4 : 8;
+
+ for ( ; regno < 32; regno++, loc += reg_size)
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, load_reg,
+ reg_names[regno], loc, reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, regno),
+ gen_rtx
+ (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ sp_reg_rtx, GEN_INT (loc))));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else if (info->first_gp_reg_save != 32)
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\t{lm|lmw} %s,%d(%s)\n",
+ reg_names[info->first_gp_reg_save],
+ info->gp_save_offset + sp_offset,
+ reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ int loc;
+ int regno;
+ int reg_size = (TARGET_32BIT) ? 4 : 8;
+
+ for (loc = info->gp_save_offset + sp_offset,
+ regno = info->first_gp_reg_save;
+ regno <= 31;
+ regno++, loc += reg_size)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, regno),
+ gen_rtx (MEM, reg_mode,
+ gen_rtx (PLUS, Pmode,
+ sp_reg_rtx,
+ GEN_INT (loc))));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+
+ /* Restore fpr's if we can do it without calling a function. */
+ if (FP_SAVE_INLINE (info->first_fp_reg_save))
+ {
+ int regno = info->first_fp_reg_save;
+ int loc = info->fp_save_offset + sp_offset;
+
+ for ( ; regno < 64; regno++, loc += 8)
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\tlfd %s,%d(%s)\n",
+ reg_names[regno], loc, reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, DFmode, regno),
+ gen_rtx
+ (MEM, DFmode,
+ gen_rtx (PLUS, Pmode,
+ sp_reg_rtx, GEN_INT (loc))));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ /* If we saved cr, restore it here. Just those of cr2, cr3, and cr4
+ that were used. */
+ if (info->cr_save_p)
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\tmtcrf %d,%s\n",
+ (regs_ever_live[70] != 0) * 0x20
+ + (regs_ever_live[71] != 0) * 0x10
+ + (regs_ever_live[72] != 0) * 0x8, reg_names[12]);
+ else if (rtx_flag)
+ {
+ rtx r12_rtx = gen_rtx (REG, reg_mode, 12);
+
+ insn = emit_insn (TARGET_32BIT
+ ? gen_movesi_to_cr (r12_rtx)
+ : gen_movedi_to_cr (r12_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+
+ /* If this is V.4, unwind the stack pointer after all of the loads
+ have been done */
+ if (sp_offset != 0)
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n",
+ reg_names[1], sp_offset, reg_names[1]);
+ else if (rtx_flag)
+ {
+ rtx reg_rtx = gen_rtx (REG, reg_mode, 1);
+
+ insn = emit_insn (TARGET_32BIT
+ ? gen_addsi3 (reg_rtx, reg_rtx,
+ GEN_INT (sp_offset))
+ : gen_adddi3 (reg_rtx, reg_rtx,
+ GEN_INT (sp_offset)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else if (sp_reg != 1)
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\tmr %s,%s\n",
+ reg_names[1], reg_names[sp_reg]);
+ else if (rtx_flag)
+ {
+ insn = emit_move_insn (gen_rtx (REG, reg_mode, 1), sp_reg_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ /* If we have to restore more than two FP registers, branch to the
+ restore function. It will return to our caller. */
+ if (info->first_fp_reg_save != 64
+ && !FP_SAVE_INLINE (info->first_fp_reg_save))
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\tb %s%d%s\n", RESTORE_FP_PREFIX,
+ info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
+ else if (rtx_flag)
+ {
+ static char label [100];
+
+ sprintf (label, "%s%d%s", RESTORE_FP_PREFIX,
+ info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
+ insn = emit_jump_insn (gen_jump (gen_rtx (SYMBOL_REF, Pmode,
+ label)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ else
+ {
+ if (!rtx_flag && !TARGET_SCHED_EPILOG)
+ asm_fprintf (file, "\t{br|blr}\n");
+ else if (rtx_flag)
+ {
+ insn = emit_jump_insn (gen_indirect_jump
+ (gen_rtx (REG, reg_mode, 65)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+
+ /* Output a traceback table here. See /usr/include/sys/debug.h for info
+ on its format.
+
+ We don't output a traceback table if -finhibit-size-directive was
+ used. The documentation for -finhibit-size-directive reads
+ ``don't output a @code{.size} assembler directive, or anything
+ else that would cause trouble if the function is split in the
+ middle, and the two halves are placed at locations far apart in
+ memory.'' The traceback table has this property, since it
+ includes the offset from the start of the function to the
+ traceback table itself.
+
+ System V.4 Powerpc's (and the embedded ABI derived from it) use a
+ different traceback table. */
+ if (!rtx_flag && DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive)
+ {
+ char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+ int fixed_parms, float_parms, parm_info;
+ int i;
+
+ while (*fname == '.') /* V.4 encodes . in the name */
+ fname++;
+
+ /* Need label immediately before tbtab, so we can compute its offset
+ from the function start. */
+ if (*fname == '*')
+ ++fname;
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+ ASM_OUTPUT_LABEL (file, fname);
+
+ /* The .tbtab pseudo-op can only be used for the first eight
+ expressions, since it can't handle the possibly variable
+ length fields that follow. However, if you omit the optional
+ fields, the assembler outputs zeros for all optional fields
+ anyways, giving each variable length field is minimum length
+ (as defined in sys/debug.h). Thus we can not use the .tbtab
+ pseudo-op at all. */
+
+ /* An all-zero word flags the start of the tbtab, for debuggers
+ that have to find it by searching forward from the entry
+ point or from the current pc. */
+ fputs ("\t.long 0\n", file);
+
+ /* Tbtab format type. Use format type 0. */
+ fputs ("\t.byte 0,", file);
+
+ /* Language type. Unfortunately, there doesn't seem to be any
+ official way to get this info, so we use language_string. C
+ is 0. C++ is 9. No number defined for Obj-C, so use the
+ value for C for now. There is no official value for Java,
+ although IBM appears to be using 13. There is no official value
+ for Chill, so we've choosen 44 pseudo-randomly. */
+ if (! strcmp (language_string, "GNU C")
+ || ! strcmp (language_string, "GNU Obj-C"))
+ i = 0;
+ else if (! strcmp (language_string, "GNU F77"))
+ i = 1;
+ else if (! strcmp (language_string, "GNU Ada"))
+ i = 3;
+ else if (! strcmp (language_string, "GNU Pascal"))
+ i = 2;
+ else if (! strcmp (language_string, "GNU C++"))
+ i = 9;
+ else if (! strcmp (language_string, "GNU Java"))
+ i = 13;
+ else if (! strcmp (language_string, "GNU CHILL"))
+ i = 44;
+ else
+ abort ();
+ fprintf (file, "%d,", i);
+
+ /* 8 single bit fields: global linkage (not set for C extern linkage,
+ apparently a PL/I convention?), out-of-line epilogue/prologue, offset
+ from start of procedure stored in tbtab, internal function, function
+ has controlled storage, function has no toc, function uses fp,
+ function logs/aborts fp operations. */
+ /* Assume that fp operations are used if any fp reg must be saved. */
+ fprintf (file, "%d,",
+ (1 << 5) | ((info->first_fp_reg_save != 64) << 1));
+
+ /* 6 bitfields: function is interrupt handler, name present in
+ proc table, function calls alloca, on condition directives
+ (controls stack walks, 3 bits), saves condition reg, saves
+ link reg. */
+ /* The `function calls alloca' bit seems to be set whenever reg 31 is
+ set up as a frame pointer, even when there is no alloca call. */
+ fprintf (file, "%d,",
+ ((1 << 6) | (frame_pointer_needed << 5)
+ | (info->cr_save_p << 1) | (info->lr_save_p)));
+
+ /* 3 bitfields: saves backchain, spare bit, number of fpr saved
+ (6 bits). */
+ fprintf (file, "%d,",
+ (info->push_p << 7) | (64 - info->first_fp_reg_save));
+
+ /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits). */
+ fprintf (file, "%d,", (32 - first_reg_to_save ()));
+
+ {
+ /* Compute the parameter info from the function decl argument
+ list. */
+ tree decl;
+ int next_parm_info_bit;
+
+ next_parm_info_bit = 31;
+ parm_info = 0;
+ fixed_parms = 0;
+ float_parms = 0;
+
+ for (decl = DECL_ARGUMENTS (current_function_decl);
+ decl; decl = TREE_CHAIN (decl))
+ {
+ rtx parameter = DECL_INCOMING_RTL (decl);
+ enum machine_mode mode = GET_MODE (parameter);
+
+ if (GET_CODE (parameter) == REG)
+ {
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+ {
+ int bits;
+
+ float_parms++;
+
+ if (mode == SFmode)
+ bits = 0x2;
+ else if (mode == DFmode)
+ bits = 0x3;
+ else
+ abort ();
+
+ /* If only one bit will fit, don't or in this entry. */
+ if (next_parm_info_bit > 0)
+ parm_info |= (bits << (next_parm_info_bit - 1));
+ next_parm_info_bit -= 2;
+ }
+ else
+ {
+ fixed_parms += ((GET_MODE_SIZE (mode)
+ + (UNITS_PER_WORD - 1))
+ / UNITS_PER_WORD);
+ next_parm_info_bit -= 1;
+ }
+ }
+ }
+ }
+
+ /* Number of fixed point parameters. */
+ /* This is actually the number of words of fixed point parameters; thus
+ an 8 byte struct counts as 2; and thus the maximum value is 8. */
+ fprintf (file, "%d,", fixed_parms);
+
+ /* 2 bitfields: number of floating point parameters (7 bits), parameters
+ all on stack. */
+ /* This is actually the number of fp registers that hold parameters;
+ and thus the maximum value is 13. */
+ /* Set parameters on stack bit if parameters are not in their original
+ registers, regardless of whether they are on the stack? Xlc
+ seems to set the bit when not optimizing. */
+ fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
+
+ /* Optional fields follow. Some are variable length. */
+
+ /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
+ 11 double float. */
+ /* There is an entry for each parameter in a register, in the order that
+ they occur in the parameter list. Any intervening arguments on the
+ stack are ignored. If the list overflows a long (max possible length
+ 34 bits) then completely leave off all elements that don't fit. */
+ /* Only emit this long if there was at least one parameter. */
+ if (fixed_parms || float_parms)
+ fprintf (file, "\t.long %d\n", parm_info);
+
+ /* Offset from start of code to tb table. */
+ fputs ("\t.long ", file);
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+ RS6000_OUTPUT_BASENAME (file, fname);
+ fputs ("-.", file);
+ RS6000_OUTPUT_BASENAME (file, fname);
+ putc ('\n', file);
+
+ /* Interrupt handler mask. */
+ /* Omit this long, since we never set the interrupt handler bit
+ above. */
+
+ /* Number of CTL (controlled storage) anchors. */
+ /* Omit this long, since the has_ctl bit is never set above. */
+
+ /* Displacement into stack of each CTL anchor. */
+ /* Omit this list of longs, because there are no CTL anchors. */
+
+ /* Length of function name. */
+ fprintf (file, "\t.short %d\n", (int) strlen (fname));
+
+ /* Function name. */
+ assemble_string (fname, strlen (fname));
+
+ /* Register for alloca automatic storage; this is always reg 31.
+ Only emit this if the alloca bit was set above. */
+ if (frame_pointer_needed)
+ fputs ("\t.byte 31\n", file);
+ }
+
+ if (!rtx_flag && DEFAULT_ABI == ABI_NT)
+ {
+ RS6000_OUTPUT_BASENAME
+ (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
+ fputs (".e:\nFE_MOT_RESVD..", file);
+ RS6000_OUTPUT_BASENAME
+ (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
+ fputs (":\n", file);
+ }
+}
+
+
+
+
+/* Write function prologue. */
+void
+output_prolog (file, size)
+ FILE *file;
+ int size;
+{
+ rs6000_prolog (file, FALSE, rs6000_stack_info ());
+}
+
+/* Write function epilogue. */
+
+void
+output_epilog (file, size)
+ FILE *file;
+ int size;
+{
+ rs6000_epilog (file, FALSE, rs6000_stack_info ());
+}
+
+/* END CYGNUS LOCAL */
+
+
+/* A C compound statement that outputs the assembler code for a thunk function,
+ used to implement C++ virtual function calls with multiple inheritance. The
+ thunk acts as a wrapper around a virtual function, adjusting the implicit
+ object parameter before handing control off to the real function.
+
+ First, emit code to add the integer DELTA to the location that contains the
+ incoming first argument. Assume that this argument contains a pointer, and
+ is the one used to pass the `this' pointer in C++. This is the incoming
+ argument *before* the function prologue, e.g. `%o0' on a sparc. The
+ addition must preserve the values of all other incoming arguments.
+
+ After the addition, emit code to jump to FUNCTION, which is a
+ `FUNCTION_DECL'. This is a direct pure jump, not a call, and does not touch
+ the return address. Hence returning from FUNCTION will return to whoever
+ called the current `thunk'.
+
+ The effect must be as if FUNCTION had been called directly with the adjusted
+ first argument. This macro is responsible for emitting all of the code for
+ a thunk function; `FUNCTION_PROLOGUE' and `FUNCTION_EPILOGUE' are not
+ invoked.
+
+ The THUNK_FNDECL is redundant. (DELTA and FUNCTION have already been
+ extracted from it.) It might possibly be useful on some targets, but
+ probably not.
+
+ If you do not define this macro, the target-independent code in the C++
+ frontend will generate a less efficient heavyweight thunk that calls
+ FUNCTION instead of jumping to it. The generic approach does not support
+ varargs. */
+
+void
+output_mi_thunk (file, thunk_fndecl, delta, function)
+ FILE *file;
+ tree thunk_fndecl;
+ int delta;
+ tree function;
+{
+ char *this_reg = reg_names[ aggregate_value_p (TREE_TYPE (TREE_TYPE (function))) ? 4 : 3 ];
+ char *r0 = reg_names[0];
+ char *sp = reg_names[1];
+ char *toc = reg_names[2];
+ char *schain = reg_names[11];
+ char *r12 = reg_names[12];
+ char *prefix;
+ char *fname;
+ char buf[512];
+ static int labelno = 0;
+
+ /* Small constants that can be done by one add instruction */
+ if (delta >= -32768 && delta <= 32767)
+ {
+ if (!TARGET_NEW_MNEMONICS)
+ fprintf (file, "\tcal %s,%d(%s)\n", this_reg, delta, this_reg);
+ else
+ fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, delta);
+ }
+
+ /* Large constants that can be done by one addis instruction */
+ else if ((delta & 0xffff) == 0 && num_insns_constant_wide (delta) == 1)
+ asm_fprintf (file, "\t{cau|addis} %s,%s,%d\n", this_reg, this_reg,
+ delta >> 16);
+
+ /* 32-bit constants that can be done by an add and addis instruction. */
+ else if (TARGET_32BIT || num_insns_constant_wide (delta) == 1)
+ {
+ /* Break into two pieces, propigating the sign bit from the low word to
+ the upper word. */
+ int delta_high = delta >> 16;
+ int delta_low = delta & 0xffff;
+ if ((delta_low & 0x8000) != 0)
+ {
+ delta_high++;
+ delta_low = (delta_low ^ 0x8000) - 0x8000; /* sign extend */
+ }
+
+ asm_fprintf (file, "\t{cau|addis} %s,%s,%d\n", this_reg, this_reg,
+ delta_high);
+
+ if (!TARGET_NEW_MNEMONICS)
+ fprintf (file, "\tcal %s,%d(%s)\n", this_reg, delta_low, this_reg);
+ else
+ fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, delta_low);
+ }
+
+ /* 64-bit constants, fixme */
+ else
+ abort ();
+
+ /* Get the prefix in front of the names. */
+ switch (DEFAULT_ABI)
+ {
+ default:
+ abort ();
+
+ case ABI_AIX:
+ prefix = ".";
+ break;
+
+ case ABI_V4:
+ case ABI_AIX_NODESC:
+ case ABI_SOLARIS:
+ prefix = "";
+ break;
+
+ case ABI_NT:
+ prefix = "..";
+ break;
+ }
+
+ /* If the function is compiled in this module, jump to it directly.
+ Otherwise, load up its address and jump to it. */
+
+ fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
+#if 1
+ /* For now, just emit a branch always, until we can figure out better when we
+ need to load the address into the count register and emit the slower bctr
+ instruction. */
+ fprintf (file, "\tb %s", prefix);
+ assemble_name (file, fname);
+ fprintf (file, "\n");
+
+#else
+ if (current_file_function_operand (XEXP (DECL_RTL (function), 0))
+ && !lookup_attribute ("longcall", TYPE_ATTRIBUTES (TREE_TYPE (function))))
+ {
+ fprintf (file, "\tb %s", prefix);
+ assemble_name (file, fname);
+ fprintf (file, "\n");
+ }
+
+ else
+ {
+ switch (DEFAULT_ABI)
+ {
+ default:
+ case ABI_NT:
+ abort ();
+
+ case ABI_AIX:
+ /* Set up a TOC entry for the function. */
+ ASM_GENERATE_INTERNAL_LABEL (buf, "Lthunk", labelno);
+ toc_section ();
+ ASM_OUTPUT_INTERNAL_LABEL (file, "Lthunk", labelno);
+ labelno++;
+
+ /* Note, MINIMAL_TOC doesn't make sense in the case of a thunk, since
+ there will be only one TOC entry for this function. */
+ fputs ("\t.tc\t", file);
+ assemble_name (file, buf);
+ fputs ("[TC],", file);
+ assemble_name (file, buf);
+ putc ('\n', file);
+ text_section ();
+ asm_fprintf (file, (TARGET_32BIT) ? "\t{l|lwz} %s," : "\tld %s", r12);
+ assemble_name (file, buf);
+ asm_fprintf (file, "(%s)\n", reg_names[2]);
+ asm_fprintf (file,
+ (TARGET_32BIT) ? "\t{l|lwz} %s,0(%s)\n" : "\tld %s,0(%s)\n",
+ r0, r12);
+
+ asm_fprintf (file,
+ (TARGET_32BIT) ? "\t{l|lwz} %s,4(%s)\n" : "\tld %s,8(%s)\n",
+ toc, r12);
+
+ asm_fprintf (file, "\tmtctr %s\n", r0);
+ asm_fprintf (file,
+ (TARGET_32BIT) ? "\t{l|lwz} %s,8(%s)\n" : "\tld %s,16(%s)\n",
+ schain, r12);
+
+ asm_fprintf (file, "\tbctr\n");
+ break;
+
+ /* Don't use r11, that contains the static chain, just use r0/r12. */
+ case ABI_V4:
+ case ABI_AIX_NODESC:
+ case ABI_SOLARIS:
+ if (flag_pic == 1)
+ {
+ fprintf (file, "\tmflr %s\n", r0);
+ fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
+ asm_fprintf (file, "\tmflr %s\n", r12);
+ asm_fprintf (file, "\tmtlr %s\n", r0);
+ asm_fprintf (file, "\t{l|lwz} %s,", r0);
+ assemble_name (file, fname);
+ asm_fprintf (file, "@got(%s)\n", r12);
+ asm_fprintf (file, "\tmtctr %s\n", r0);
+ asm_fprintf (file, "\tbctr\n");
+ }
+#if TARGET_ELF
+ else if (flag_pic > 1 || TARGET_RELOCATABLE)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (buf, "Lthunk", labelno);
+ labelno++;
+ fprintf (file, "\tmflr %s\n", r0);
+ asm_fprintf (file, "\t{st|stw} %s,4(%s)\n", r0, sp);
+ rs6000_pic_func_labelno = rs6000_pic_labelno;
+ rs6000_output_load_toc_table (file, 12
+/* CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling */
+ , FALSE
+/* END CYGNUS LOCAL */
+ );
+ asm_fprintf (file, "\t{l|lwz} %s,", r0);
+ assemble_name (file, buf);
+ asm_fprintf (file, "(%s)\n", r12);
+ asm_fprintf (file, "\t{l|lwz} %s,4(%s)\n", r12, sp);
+ asm_fprintf (file, "\tmtlr %s\n", r12);
+ asm_fprintf (file, "\tmtctr %s\n", r0);
+ asm_fprintf (file, "\tbctr\n");
+ asm_fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
+ assemble_name (file, buf);
+ fputs (" = .-.LCTOC1\n", file);
+ fputs ("\t.long ", file);
+ assemble_name (file, fname);
+ fputs ("\n\t.previous\n", file);
+ }
+#endif /* TARGET_ELF */
+
+ else
+ {
+ asm_fprintf (file, "\t{liu|lis} %s,", r12);
+ assemble_name (file, fname);
+ asm_fprintf (file, "@ha\n");
+ asm_fprintf (file, "\t{cal|la} %s,", r12);
+ assemble_name (file, fname);
+ asm_fprintf (file, "@l(%s)\n", r12);
+ asm_fprintf (file, "\tmtctr %s\n", r12);
+ asm_fprintf (file, "\tbctr\n");
+ }
+
+ break;
+ }
+ }
+#endif /* #if 0 out code to use bctr for far away jumps */
+}
+
+
+/* Output a TOC entry. We derive the entry name from what is
+ being written. */
+
+void
+output_toc (file, x, labelno)
+ FILE *file;
+ rtx x;
+ int labelno;
+{
+ char buf[256];
+ char *name = buf;
+ char *real_name;
+ rtx base = x;
+ int offset = 0;
+
+ if (TARGET_NO_TOC)
+ abort ();
+
+ /* if we're going to put a double constant in the TOC, make sure it's
+ aligned properly when strict alignment is on. */
+ if (GET_CODE (x) == CONST_DOUBLE
+ && STRICT_ALIGNMENT
+ && GET_MODE (x) == DFmode
+ && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)) {
+ ASM_OUTPUT_ALIGN (file, 3);
+ }
+
+
+ if (TARGET_ELF && TARGET_MINIMAL_TOC)
+ {
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
+ fprintf (file, "%d = .-", labelno);
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LCTOC");
+ fputs ("1\n", file);
+ }
+ else
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LC", labelno);
+
+ /* Handle FP constants specially. Note that if we have a minimal
+ TOC, things we put here aren't actually in the TOC, so we can allow
+ FP constants. */
+ if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode
+ && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC))
+ {
+ REAL_VALUE_TYPE rv;
+ long k[2];
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
+ if (TARGET_64BIT)
+ {
+ if (TARGET_MINIMAL_TOC)
+ fprintf (file, "\t.llong 0x%lx%08lx\n", k[0], k[1]);
+ else
+ fprintf (file, "\t.tc FD_%lx_%lx[TC],0x%lx%08lx\n",
+ k[0], k[1], k[0] & 0xffffffff, k[1] & 0xffffffff);
+ return;
+ }
+ else
+ {
+ if (TARGET_MINIMAL_TOC)
+ fprintf (file, "\t.long %ld\n\t.long %ld\n", k[0], k[1]);
+ else
+ fprintf (file, "\t.tc FD_%lx_%lx[TC],%ld,%ld\n",
+ k[0], k[1], k[0], k[1]);
+ return;
+ }
+ }
+ else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode
+ && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC))
+ {
+ REAL_VALUE_TYPE rv;
+ long l;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+
+ if (TARGET_MINIMAL_TOC)
+ fprintf (file, TARGET_32BIT ? "\t.long %ld\n" : "\t.llong %ld\n", l);
+ else
+ fprintf (file, "\t.tc FS_%lx[TC],%ld\n", l, l);
+ return;
+ }
+ else if (GET_MODE (x) == DImode
+ && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
+ && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC))
+ {
+ HOST_WIDE_INT low;
+ HOST_WIDE_INT high;
+
+ if (GET_CODE (x) == CONST_DOUBLE)
+ {
+ low = CONST_DOUBLE_LOW (x);
+ high = CONST_DOUBLE_HIGH (x);
+ }
+ else
+#if HOST_BITS_PER_WIDE_INT == 32
+ {
+ low = INTVAL (x);
+ high = (low < 0) ? ~0 : 0;
+ }
+#else
+ {
+ low = INTVAL (x) & 0xffffffff;
+ high = (HOST_WIDE_INT) INTVAL (x) >> 32;
+ }
+#endif
+
+ if (TARGET_64BIT)
+ {
+ if (TARGET_MINIMAL_TOC)
+ fprintf (file, "\t.llong 0x%lx%08lx\n", (long)high, (long)low);
+ else
+ fprintf (file, "\t.tc ID_%lx_%lx[TC],0x%lx%08lx\n",
+ (long)high, (long)low, (long)high, (long)low);
+ return;
+ }
+ else
+ {
+ if (TARGET_MINIMAL_TOC)
+ fprintf (file, "\t.long %ld\n\t.long %ld\n",
+ (long)high, (long)low);
+ else
+ fprintf (file, "\t.tc ID_%lx_%lx[TC],%ld,%ld\n",
+ (long)high, (long)low, (long)high, (long)low);
+ return;
+ }
+ }
+
+ if (GET_CODE (x) == CONST)
+ {
+ base = XEXP (XEXP (x, 0), 0);
+ offset = INTVAL (XEXP (XEXP (x, 0), 1));
+ }
+
+ if (GET_CODE (base) == SYMBOL_REF)
+ name = XSTR (base, 0);
+ else if (GET_CODE (base) == LABEL_REF)
+ ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (base, 0)));
+ else if (GET_CODE (base) == CODE_LABEL)
+ ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (base));
+ else
+ abort ();
+
+ STRIP_NAME_ENCODING (real_name, name);
+ if (TARGET_MINIMAL_TOC)
+ fputs (TARGET_32BIT ? "\t.long " : "\t.llong ", file);
+ else
+ {
+ fprintf (file, "\t.tc %s", real_name);
+
+ if (offset < 0)
+ fprintf (file, ".N%d", - offset);
+ else if (offset)
+ fprintf (file, ".P%d", offset);
+
+ fputs ("[TC],", file);
+ }
+
+ /* Currently C++ toc references to vtables can be emitted before it
+ is decided whether the vtable is public or private. If this is
+ the case, then the linker will eventually complain that there is
+ a TOC reference to an unknown section. Thus, for vtables only,
+ we emit the TOC reference to reference the symbol and not the
+ section. */
+ if (!strncmp ("_vt.", name, 4))
+ {
+ RS6000_OUTPUT_BASENAME (file, name);
+ if (offset < 0)
+ fprintf (file, "%d", offset);
+ else if (offset > 0)
+ fprintf (file, "+%d", offset);
+ }
+ else
+ output_addr_const (file, x);
+ putc ('\n', file);
+}
+
+/* Output an assembler pseudo-op to write an ASCII string of N characters
+ starting at P to FILE.
+
+ On the RS/6000, we have to do this using the .byte operation and
+ write out special characters outside the quoted string.
+ Also, the assembler is broken; very long strings are truncated,
+ so we must artificially break them up early. */
+
+void
+output_ascii (file, p, n)
+ FILE *file;
+ char *p;
+ int n;
+{
+ char c;
+ int i, count_string;
+ char *for_string = "\t.byte \"";
+ char *for_decimal = "\t.byte ";
+ char *to_close = NULL;
+
+ count_string = 0;
+ for (i = 0; i < n; i++)
+ {
+ c = *p++;
+ if (c >= ' ' && c < 0177)
+ {
+ if (for_string)
+ fputs (for_string, file);
+ putc (c, file);
+
+ /* Write two quotes to get one. */
+ if (c == '"')
+ {
+ putc (c, file);
+ ++count_string;
+ }
+
+ for_string = NULL;
+ for_decimal = "\"\n\t.byte ";
+ to_close = "\"\n";
+ ++count_string;
+
+ if (count_string >= 512)
+ {
+ fputs (to_close, file);
+
+ for_string = "\t.byte \"";
+ for_decimal = "\t.byte ";
+ to_close = NULL;
+ count_string = 0;
+ }
+ }
+ else
+ {
+ if (for_decimal)
+ fputs (for_decimal, file);
+ fprintf (file, "%d", c);
+
+ for_string = "\n\t.byte \"";
+ for_decimal = ", ";
+ to_close = "\n";
+ count_string = 0;
+ }
+ }
+
+ /* Now close the string if we have written one. Then end the line. */
+ if (to_close)
+ fprintf (file, to_close);
+}
+
+/* Generate a unique section name for FILENAME for a section type
+ represented by SECTION_DESC. Output goes into BUF.
+
+ SECTION_DESC can be any string, as long as it is different for each
+ possible section type.
+
+ We name the section in the same manner as xlc. The name begins with an
+ underscore followed by the filename (after stripping any leading directory
+ names) with the last period replaced by the string SECTION_DESC. If
+ FILENAME does not contain a period, SECTION_DESC is appended to the end of
+ the name. */
+
+void
+rs6000_gen_section_name (buf, filename, section_desc)
+ char **buf;
+ char *filename;
+ char *section_desc;
+{
+ char *q, *after_last_slash, *last_period;
+ char *p;
+ int len;
+
+ after_last_slash = filename;
+ for (q = filename; *q; q++)
+ {
+ if (*q == '/')
+ after_last_slash = q + 1;
+ else if (*q == '.')
+ last_period = q;
+ }
+
+ len = strlen (after_last_slash) + strlen (section_desc) + 2;
+ *buf = (char *) permalloc (len);
+
+ p = *buf;
+ *p++ = '_';
+
+ for (q = after_last_slash; *q; q++)
+ {
+ if (q == last_period)
+ {
+ strcpy (p, section_desc);
+ p += strlen (section_desc);
+ }
+
+ else if (ISALNUM (*q))
+ *p++ = *q;
+ }
+
+ if (last_period == 0)
+ strcpy (p, section_desc);
+ else
+ *p = '\0';
+}
+
+/* Write function profiler code. */
+
+void
+output_function_profiler (file, labelno)
+ FILE *file;
+ int labelno;
+{
+ /* The last used parameter register. */
+ int last_parm_reg;
+ int i, j;
+ char buf[100];
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
+ switch (DEFAULT_ABI)
+ {
+ default:
+ abort ();
+
+ case ABI_V4:
+ case ABI_SOLARIS:
+ case ABI_AIX_NODESC:
+ fprintf (file, "\tmflr %s\n", reg_names[0]);
+ if (flag_pic == 1)
+ {
+ fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
+ asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+ reg_names[0], reg_names[1]);
+ asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
+ asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
+ assemble_name (file, buf);
+ asm_fprintf (file, "@got(%s)\n", reg_names[12]);
+ }
+#if TARGET_ELF
+ else if (flag_pic > 1 || TARGET_RELOCATABLE)
+ {
+ asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+ reg_names[0], reg_names[1]);
+ rs6000_pic_func_labelno = rs6000_pic_labelno;
+ rs6000_output_load_toc_table (file, 12
+/* CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling */
+ , FALSE
+/* END CYGNUS LOCAL */
+ );
+ asm_fprintf (file, "\t{l|lwz} %s,", reg_names[12]);
+ assemble_name (file, buf);
+ asm_fprintf (file, "X(%s)\n", reg_names[12]);
+ asm_fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
+ assemble_name (file, buf);
+ fputs ("X = .-.LCTOC1\n", file);
+ fputs ("\t.long ", file);
+ assemble_name (file, buf);
+ fputs ("\n\t.previous\n", file);
+ }
+#endif
+ else
+ {
+ asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
+ assemble_name (file, buf);
+ fputs ("@ha\n", file);
+ asm_fprintf (file, "\t{st|stw} %s,4(%s)\n", reg_names[0], reg_names[1]);
+ asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
+ assemble_name (file, buf);
+ asm_fprintf (file, "@l(%s)\n", reg_names[12]);
+ }
+
+ fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
+ break;
+
+ case ABI_AIX:
+ /* Set up a TOC entry for the profiler label. */
+ toc_section ();
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LPC", labelno);
+ if (TARGET_MINIMAL_TOC)
+ {
+ fputs (TARGET_32BIT ? "\t.long " : "\t.llong ", file);
+ assemble_name (file, buf);
+ putc ('\n', file);
+ }
+ else
+ {
+ fputs ("\t.tc\t", file);
+ assemble_name (file, buf);
+ fputs ("[TC],", file);
+ assemble_name (file, buf);
+ putc ('\n', file);
+ }
+ text_section ();
+
+ /* Figure out last used parameter register. The proper thing to do is
+ to walk incoming args of the function. A function might have live
+ parameter registers even if it has no incoming args. */
+
+ for (last_parm_reg = 10;
+ last_parm_reg > 2 && ! regs_ever_live [last_parm_reg];
+ last_parm_reg--)
+ ;
+
+ /* Save parameter registers in regs 23-30. Don't overwrite reg 31, since
+ it might be set up as the frame pointer. */
+
+ for (i = 3, j = 30; i <= last_parm_reg; i++, j--)
+ asm_fprintf (file, "\tmr %d,%d\n", j, i);
+
+ /* Load location address into r3, and call mcount. */
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LPC", labelno);
+ asm_fprintf (file, TARGET_32BIT ? "\t{l|lwz} %s," : "\tld %s,",
+ reg_names[3]);
+ assemble_name (file, buf);
+ asm_fprintf (file, "(%s)\n\tbl %s\n\t%s\n",
+ reg_names[2], RS6000_MCOUNT, RS6000_CALL_GLUE);
+
+ /* Restore parameter registers. */
+
+ for (i = 3, j = 30; i <= last_parm_reg; i++, j--)
+ asm_fprintf (file, "\tmr %d,%d\n", i, j);
+ break;
+ }
+}
+
+/* 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. */
+
+int
+rs6000_adjust_cost (insn, link, dep_insn, cost)
+ rtx insn;
+ rtx link;
+ rtx dep_insn ATTRIBUTE_UNUSED;
+ int cost;
+{
+ if (! recog_memoized (insn))
+ return 0;
+
+ if (REG_NOTE_KIND (link) != 0)
+ return 0;
+
+ if (REG_NOTE_KIND (link) == 0)
+ {
+ /* Data dependency; DEP_INSN writes a register that INSN reads some
+ cycles later. */
+
+ /* Tell the first scheduling pass about the latency between a mtctr
+ and bctr (and mtlr and br/blr). The first scheduling pass will not
+ know about this latency since the mtctr instruction, which has the
+ latency associated to it, will be generated by reload. */
+ if (get_attr_type (insn) == TYPE_JMPREG)
+ return TARGET_POWER ? 5 : 4;
+
+ /* Fall out to return default cost. */
+ }
+
+ return cost;
+}
+
+/* A C statement (sans semicolon) to update the integer scheduling priority
+ INSN_PRIORITY (INSN). Reduce the priority to execute the INSN earlier,
+ increase the priority to execute INSN later. Do not define this macro if
+ you do not need to adjust the scheduling priorities of insns. */
+
+int
+rs6000_adjust_priority (insn, priority)
+ rtx insn;
+ int priority;
+{
+ /* On machines (like the 750) which have asymetric integer units, where one
+ integer unit can do multiply and divides and the other can't, reduce the
+ priority of multiply/divide so it is scheduled before other integer
+ operationss. */
+
+#if 0
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ return priority;
+
+ if (GET_CODE (PATTERN (insn)) == USE)
+ return priority;
+
+ switch (rs6000_cpu_attr) {
+ case CPU_PPC750:
+ switch (get_attr_type (insn))
+ {
+ default:
+ break;
+
+ case TYPE_IMUL:
+ case TYPE_IDIV:
+ fprintf (stderr, "priority was %#x (%d) before adjustment\n", priority, priority);
+ if (priority >= 0 && priority < 0x01000000)
+ priority >>= 3;
+ break;
+ }
+ }
+#endif
+
+ return priority;
+}
+
+/* Return how many instructions the machine can issue per cycle */
+int get_issue_rate()
+{
+ switch (rs6000_cpu_attr) {
+ case CPU_RIOS1:
+ return 3; /* ? */
+ case CPU_RIOS2:
+ return 4;
+ case CPU_PPC601:
+ return 3; /* ? */
+ case CPU_PPC603:
+ return 2;
+ case CPU_PPC750:
+ return 2;
+ case CPU_PPC604:
+ return 4;
+ case CPU_PPC620:
+ return 4;
+ default:
+ return 1;
+ }
+}
+
+
+
+/* Output assembler code for a block containing the constant parts
+ of a trampoline, leaving space for the variable parts.
+
+ The trampoline should set the static chain pointer to value placed
+ into the trampoline and should branch to the specified routine. */
+
+void
+rs6000_trampoline_template (file)
+ FILE *file;
+{
+ char *sc = reg_names[STATIC_CHAIN_REGNUM];
+ char *r0 = reg_names[0];
+ char *r2 = reg_names[2];
+
+ switch (DEFAULT_ABI)
+ {
+ default:
+ abort ();
+
+ /* Under AIX, this is not code at all, but merely a data area,
+ since that is the way all functions are called. The first word is
+ the address of the function, the second word is the TOC pointer (r2),
+ and the third word is the static chain value. */
+ case ABI_AIX:
+ break;
+
+
+ /* V.4/eabi function pointers are just a single pointer, so we need to
+ do the full gory code to load up the static chain. */
+ case ABI_V4:
+ case ABI_SOLARIS:
+ case ABI_AIX_NODESC:
+ break;
+
+ /* NT function pointers point to a two word area (real address, TOC)
+ which unfortunately does not include a static chain field. So we
+ use the function field to point to ..LTRAMP1 and the toc field
+ to point to the whole table. */
+ case ABI_NT:
+ if (STATIC_CHAIN_REGNUM == 0
+ || STATIC_CHAIN_REGNUM == 2
+ || TARGET_64BIT
+ || !TARGET_NEW_MNEMONICS)
+ abort ();
+
+ fprintf (file, "\t.ualong 0\n"); /* offset 0 */
+ fprintf (file, "\t.ualong 0\n"); /* offset 4 */
+ fprintf (file, "\t.ualong 0\n"); /* offset 8 */
+ fprintf (file, "\t.ualong 0\n"); /* offset 12 */
+ fprintf (file, "\t.ualong 0\n"); /* offset 16 */
+ fprintf (file, "..LTRAMP1..0:\n"); /* offset 20 */
+ fprintf (file, "\tlwz %s,8(%s)\n", r0, r2); /* offset 24 */
+ fprintf (file, "\tlwz %s,12(%s)\n", sc, r2); /* offset 28 */
+ fprintf (file, "\tmtctr %s\n", r0); /* offset 32 */
+ fprintf (file, "\tlwz %s,16(%s)\n", r2, r2); /* offset 36 */
+ fprintf (file, "\tbctr\n"); /* offset 40 */
+ break;
+ }
+
+ return;
+}
+
+/* Length in units of the trampoline for entering a nested function. */
+
+int
+rs6000_trampoline_size ()
+{
+ int ret = 0;
+
+ switch (DEFAULT_ABI)
+ {
+ default:
+ abort ();
+
+ case ABI_AIX:
+ ret = (TARGET_32BIT) ? 12 : 24;
+ break;
+
+ case ABI_V4:
+ case ABI_SOLARIS:
+ case ABI_AIX_NODESC:
+ ret = (TARGET_32BIT) ? 40 : 48;
+ break;
+
+ case ABI_NT:
+ ret = 20;
+ break;
+ }
+
+ return ret;
+}
+
+/* Emit RTL insns to initialize the variable parts of a trampoline.
+ FNADDR is an RTX for the address of the function's pure code.
+ CXT is an RTX for the static chain value for the function. */
+
+void
+rs6000_initialize_trampoline (addr, fnaddr, cxt)
+ rtx addr;
+ rtx fnaddr;
+ rtx cxt;
+{
+ enum machine_mode pmode = Pmode;
+ int regsize = (TARGET_32BIT) ? 4 : 8;
+ rtx ctx_reg = force_reg (pmode, cxt);
+
+ switch (DEFAULT_ABI)
+ {
+ default:
+ abort ();
+
+/* Macros to shorten the code expansions below. */
+#define MEM_DEREF(addr) gen_rtx_MEM (pmode, memory_address (pmode, addr))
+#define MEM_PLUS(addr,offset) gen_rtx_MEM (pmode, memory_address (pmode, plus_constant (addr, offset)))
+
+ /* Under AIX, just build the 3 word function descriptor */
+ case ABI_AIX:
+ {
+ rtx fn_reg = gen_reg_rtx (pmode);
+ rtx toc_reg = gen_reg_rtx (pmode);
+ emit_move_insn (fn_reg, MEM_DEREF (fnaddr));
+ emit_move_insn (toc_reg, MEM_PLUS (fnaddr, 4));
+ emit_move_insn (MEM_DEREF (addr), fn_reg);
+ emit_move_insn (MEM_PLUS (addr, regsize), toc_reg);
+ emit_move_insn (MEM_PLUS (addr, 2*regsize), ctx_reg);
+ }
+ break;
+
+ /* Under V.4/eabi, call __trampoline_setup to do the real work. */
+ case ABI_V4:
+ case ABI_SOLARIS:
+ case ABI_AIX_NODESC:
+ emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
+ FALSE, VOIDmode, 4,
+ addr, pmode,
+ GEN_INT (rs6000_trampoline_size ()), SImode,
+ fnaddr, pmode,
+ ctx_reg, pmode);
+ break;
+
+ /* Under NT, update the first word to point to the ..LTRAMP1..0 header,
+ the second word will point to the whole trampoline, third-fifth words
+ will then have the real address, static chain, and toc value. */
+ case ABI_NT:
+ {
+ rtx tramp_reg = gen_reg_rtx (pmode);
+ rtx fn_reg = gen_reg_rtx (pmode);
+ rtx toc_reg = gen_reg_rtx (pmode);
+
+ emit_move_insn (tramp_reg, gen_rtx_SYMBOL_REF (pmode, "..LTRAMP1..0"));
+ addr = force_reg (pmode, addr);
+ emit_move_insn (fn_reg, MEM_DEREF (fnaddr));
+ emit_move_insn (toc_reg, MEM_PLUS (fnaddr, regsize));
+ emit_move_insn (MEM_DEREF (addr), tramp_reg);
+ emit_move_insn (MEM_PLUS (addr, regsize), addr);
+ emit_move_insn (MEM_PLUS (addr, 2*regsize), fn_reg);
+ emit_move_insn (MEM_PLUS (addr, 3*regsize), ctx_reg);
+ emit_move_insn (MEM_PLUS (addr, 4*regsize), gen_rtx_REG (pmode, 2));
+ }
+ break;
+ }
+
+ return;
+}
+
+
+/* If defined, a C expression whose value is nonzero if IDENTIFIER
+ with arguments ARGS is a valid machine specific attribute for DECL.
+ The attributes in ATTRIBUTES have previously been assigned to DECL. */
+
+int
+rs6000_valid_decl_attribute_p (decl, attributes, identifier, args)
+ tree decl ATTRIBUTE_UNUSED;
+ tree attributes ATTRIBUTE_UNUSED;
+ tree identifier ATTRIBUTE_UNUSED;
+ tree args ATTRIBUTE_UNUSED;
+{
+ return 0;
+}
+
+/* If defined, a C expression whose value is nonzero if IDENTIFIER
+ with arguments ARGS is a valid machine specific attribute for TYPE.
+ The attributes in ATTRIBUTES have previously been assigned to TYPE. */
+
+int
+rs6000_valid_type_attribute_p (type, attributes, identifier, args)
+ tree type;
+ tree attributes ATTRIBUTE_UNUSED;
+ tree identifier;
+ tree args;
+{
+ if (TREE_CODE (type) != FUNCTION_TYPE
+ && TREE_CODE (type) != FIELD_DECL
+ && TREE_CODE (type) != TYPE_DECL)
+ return 0;
+
+ /* Longcall attribute says that the function is not within 2**26 bytes
+ of the current function, and to do an indirect call. */
+ if (is_attribute_p ("longcall", identifier))
+ return (args == NULL_TREE);
+
+ if (DEFAULT_ABI == ABI_NT)
+ {
+ /* Stdcall attribute says callee is responsible for popping arguments
+ if they are not variable. */
+ if (is_attribute_p ("stdcall", identifier))
+ return (args == NULL_TREE);
+
+ /* Cdecl attribute says the callee is a normal C declaration */
+ if (is_attribute_p ("cdecl", identifier))
+ return (args == NULL_TREE);
+
+ /* Dllimport attribute says the caller is to call the function
+ indirectly through a __imp_<name> pointer. */
+ if (is_attribute_p ("dllimport", identifier))
+ return (args == NULL_TREE);
+
+ /* Dllexport attribute says the callee is to create a __imp_<name>
+ pointer. */
+ if (is_attribute_p ("dllexport", identifier))
+ return (args == NULL_TREE);
+
+ /* Exception attribute allows the user to specify 1-2 strings or identifiers
+ that will fill in the 3rd and 4th fields of the structured exception
+ table. */
+ if (is_attribute_p ("exception", identifier))
+ {
+ int i;
+
+ if (args == NULL_TREE)
+ return 0;
+
+ for (i = 0; i < 2 && args != NULL_TREE; i++)
+ {
+ tree this_arg = TREE_VALUE (args);
+ args = TREE_PURPOSE (args);
+
+ if (TREE_CODE (this_arg) != STRING_CST
+ && TREE_CODE (this_arg) != IDENTIFIER_NODE)
+ return 0;
+ }
+
+ return (args == NULL_TREE);
+ }
+ }
+
+ return 0;
+}
+
+/* If defined, a C expression whose value is zero if the attributes on
+ TYPE1 and TYPE2 are incompatible, one if they are compatible, and
+ two if they are nearly compatible (which causes a warning to be
+ generated). */
+
+int
+rs6000_comp_type_attributes (type1, type2)
+ tree type1 ATTRIBUTE_UNUSED;
+ tree type2 ATTRIBUTE_UNUSED;
+{
+ return 1;
+}
+
+/* If defined, a C statement that assigns default attributes to newly
+ defined TYPE. */
+
+void
+rs6000_set_default_type_attributes (type)
+ tree type ATTRIBUTE_UNUSED;
+{
+}
+
+/* Return a dll import reference corresponding to a call's SYMBOL_REF */
+struct rtx_def *
+rs6000_dll_import_ref (call_ref)
+ rtx call_ref;
+{
+ char *call_name;
+ int len;
+ char *p;
+ rtx reg1, reg2;
+ tree node;
+
+ if (GET_CODE (call_ref) != SYMBOL_REF)
+ abort ();
+
+ call_name = XSTR (call_ref, 0);
+ len = sizeof ("__imp_") + strlen (call_name);
+ p = alloca (len);
+ reg2 = gen_reg_rtx (Pmode);
+
+ strcpy (p, "__imp_");
+ strcat (p, call_name);
+ node = get_identifier (p);
+
+ reg1 = force_reg (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node)));
+ emit_move_insn (reg2, gen_rtx_MEM (Pmode, reg1));
+
+ return reg2;
+}
+
+/* Return a reference suitable for calling a function with the longcall attribute. */
+struct rtx_def *
+rs6000_longcall_ref (call_ref)
+ rtx call_ref;
+{
+ char *call_name;
+ tree node;
+
+ if (GET_CODE (call_ref) != SYMBOL_REF)
+ return call_ref;
+
+ /* System V adds '.' to the internal name, so skip them. */
+ call_name = XSTR (call_ref, 0);
+ if (*call_name == '.')
+ {
+ while (*call_name == '.')
+ call_name++;
+
+ node = get_identifier (call_name);
+ call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
+ }
+
+ return force_reg (Pmode, call_ref);
+}
+
+
+/* A C statement or statements to switch to the appropriate section
+ for output of RTX in mode MODE. You can assume that RTX is some
+ kind of constant in RTL. The argument MODE is redundant except in
+ the case of a `const_int' rtx. Select the section by calling
+ `text_section' or one of the alternatives for other sections.
+
+ Do not define this macro if you put all constants in the read-only
+ data section. */
+
+#ifdef USING_SVR4_H
+
+void
+rs6000_select_rtx_section (mode, x)
+ enum machine_mode mode;
+ rtx x;
+{
+ if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x))
+ toc_section ();
+ else
+ const_section ();
+}
+
+/* A C statement or statements to switch to the appropriate
+ section for output of DECL. DECL is either a `VAR_DECL' node
+ or a constant of some sort. RELOC indicates whether forming
+ the initial value of DECL requires link-time relocations. */
+
+void
+rs6000_select_section (decl, reloc)
+ tree decl;
+ int reloc;
+{
+ int size = int_size_in_bytes (TREE_TYPE (decl));
+
+ if (TREE_CODE (decl) == STRING_CST)
+ {
+ if (! flag_writable_strings)
+ const_section ();
+ else
+ data_section ();
+ }
+ else if (TREE_CODE (decl) == VAR_DECL)
+ {
+ if ((flag_pic && reloc)
+ || !TREE_READONLY (decl)
+ || TREE_SIDE_EFFECTS (decl)
+ || !DECL_INITIAL (decl)
+ || (DECL_INITIAL (decl) != error_mark_node
+ && !TREE_CONSTANT (DECL_INITIAL (decl))))
+ {
+ if (rs6000_sdata != SDATA_NONE && (size > 0) && (size <= g_switch_value))
+ sdata_section ();
+ else
+ data_section ();
+ }
+ else
+ {
+ if (rs6000_sdata != SDATA_NONE && (size > 0) && (size <= g_switch_value))
+ {
+ if (rs6000_sdata == SDATA_EABI)
+ sdata2_section ();
+ else
+ sdata_section (); /* System V doesn't have .sdata2/.sbss2 */
+ }
+ else
+ const_section ();
+ }
+ }
+ else
+ const_section ();
+}
+
+
+
+/* If we are referencing a function that is static or is known to be
+ in this file, make the SYMBOL_REF special. We can use this to indicate
+ that we can branch to this function without emitting a no-op after the
+ call. For real AIX and NT calling sequences, we also replace the
+ function name with the real name (1 or 2 leading .'s), rather than
+ the function descriptor name. This saves a lot of overriding code
+ to read the prefixes. */
+
+void
+rs6000_encode_section_info (decl)
+ tree decl;
+{
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ rtx sym_ref = XEXP (DECL_RTL (decl), 0);
+ if (TREE_ASM_WRITTEN (decl) || ! TREE_PUBLIC (decl))
+ SYMBOL_REF_FLAG (sym_ref) = 1;
+
+ if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ {
+ char *prefix = (DEFAULT_ABI == ABI_AIX) ? "." : "..";
+ char *str = permalloc (strlen (prefix) + 1
+ + strlen (XSTR (sym_ref, 0)));
+ strcpy (str, prefix);
+ strcat (str, XSTR (sym_ref, 0));
+ XSTR (sym_ref, 0) = str;
+ }
+ }
+ else if (rs6000_sdata != SDATA_NONE
+ && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && TREE_CODE (decl) == VAR_DECL)
+ {
+ int size = int_size_in_bytes (TREE_TYPE (decl));
+ tree section_name = DECL_SECTION_NAME (decl);
+ char *name = (char *)0;
+ int len = 0;
+
+ if (section_name)
+ {
+ if (TREE_CODE (section_name) == STRING_CST)
+ {
+ name = TREE_STRING_POINTER (section_name);
+ len = TREE_STRING_LENGTH (section_name);
+ }
+ else
+ abort ();
+ }
+
+ if ((size > 0 && size <= g_switch_value)
+ || (name
+ && ((len == sizeof (".sdata")-1 && strcmp (name, ".sdata") == 0)
+ || (len == sizeof (".sdata2")-1 && strcmp (name, ".sdata2") == 0)
+ || (len == sizeof (".sbss")-1 && strcmp (name, ".sbss") == 0)
+ || (len == sizeof (".sbss2")-1 && strcmp (name, ".sbss2") == 0)
+ || (len == sizeof (".PPC.EMB.sdata0")-1 && strcmp (name, ".PPC.EMB.sdata0") == 0)
+ || (len == sizeof (".PPC.EMB.sbss0")-1 && strcmp (name, ".PPC.EMB.sbss0") == 0))))
+ {
+ rtx sym_ref = XEXP (DECL_RTL (decl), 0);
+ char *str = permalloc (2 + strlen (XSTR (sym_ref, 0)));
+ strcpy (str, "@");
+ strcat (str, XSTR (sym_ref, 0));
+ XSTR (sym_ref, 0) = str;
+ }
+ }
+}
+
+#endif /* USING_SVR4_H */
+
+void
+rs6000_fatal_bad_address (op)
+ rtx op;
+{
+ fatal_insn ("bad address", op);
+}
+
+/* CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling */
+
+
+void
+rs6000_expand_prologue (void)
+{
+ rs6000_stack_t *info;
+
+ /* Trick is here. We need information about function but we have
+ started new insn sequence in `gen_prologue'. */
+ end_sequence ();
+ info = rs6000_stack_info ();
+ start_sequence ();
+ rs6000_prolog (NULL, TRUE, info);
+}
+
+void
+rs6000_expand_epilogue (void)
+{
+ rs6000_stack_t *info;
+
+ /* Trick is here. We need information about function but we have
+ started new insn sequence in `gen_epilogue'. */
+ end_sequence ();
+ info = rs6000_stack_info ();
+ start_sequence ();
+ rs6000_epilog (NULL, TRUE, info);
+}
+
+/* END CYGNUS LOCAL */
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
new file mode 100755
index 0000000..5890aaa
--- /dev/null
+++ b/gcc/config/rs6000/rs6000.h
@@ -0,0 +1,3403 @@
+/* Definitions of target machine for GNU compiler, for IBM RS/6000.
+ Copyright (C) 1992, 93-8, 1999 Free Software Foundation, Inc.
+ Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Note that some other tm.h files include this one and then override
+ many of the definitions that relate to assembler syntax. */
+
+
+/* Names to predefine in the preprocessor for this target machine. */
+
+#define CPP_PREDEFINES "-D_IBMR2 -D_POWER -D_AIX -D_AIX32 -D_LONG_LONG \
+-Asystem(unix) -Asystem(aix) -Acpu(rs6000) -Amachine(rs6000)"
+
+/* Print subsidiary information on the compiler version in use. */
+#define TARGET_VERSION ;
+
+/* Default string to use for cpu if not specified. */
+#ifndef TARGET_CPU_DEFAULT
+#define TARGET_CPU_DEFAULT ((char *)0)
+#endif
+
+/* Tell the assembler to assume that all undefined names are external.
+
+ Don't do this until the fixed IBM assembler is more generally available.
+ When this becomes permanently defined, the ASM_OUTPUT_EXTERNAL,
+ ASM_OUTPUT_EXTERNAL_LIBCALL, and RS6000_OUTPUT_BASENAME macros will no
+ longer be needed. Also, the extern declaration of mcount in ASM_FILE_START
+ will no longer be needed. */
+
+/* #define ASM_SPEC "-u %(asm_cpu)" */
+
+/* Define appropriate architecture macros for preprocessor depending on
+ target switches. */
+
+#define CPP_SPEC "%{posix: -D_POSIX_SOURCE} %(cpp_cpu)"
+
+/* Common CPP definitions used by CPP_SPEC among the various targets
+ for handling -mcpu=xxx switches. */
+#define CPP_CPU_SPEC \
+"%{!mcpu*: \
+ %{mpower: %{!mpower2: -D_ARCH_PWR}} \
+ %{mpower2: -D_ARCH_PWR2} \
+ %{mpowerpc*: -D_ARCH_PPC} \
+ %{mno-power: %{!mpowerpc*: -D_ARCH_COM}} \
+ %{!mno-power: %{!mpower2: %(cpp_default)}}} \
+%{mcpu=common: -D_ARCH_COM} \
+%{mcpu=power: -D_ARCH_PWR} \
+%{mcpu=power2: -D_ARCH_PWR2} \
+%{mcpu=powerpc: -D_ARCH_PPC} \
+%{mcpu=rios: -D_ARCH_PWR} \
+%{mcpu=rios1: -D_ARCH_PWR} \
+%{mcpu=rios2: -D_ARCH_PWR2} \
+%{mcpu=rsc: -D_ARCH_PWR} \
+%{mcpu=rsc1: -D_ARCH_PWR} \
+%{mcpu=401: -D_ARCH_PPC} \
+%{mcpu=403: -D_ARCH_PPC} \
+%{mcpu=505: -D_ARCH_PPC} \
+%{mcpu=601: -D_ARCH_PPC -D_ARCH_PWR} \
+%{mcpu=602: -D_ARCH_PPC} \
+%{mcpu=603: -D_ARCH_PPC} \
+%{mcpu=603e: -D_ARCH_PPC} \
+%{mcpu=ec603e: -D_ARCH_PPC} \
+%{mcpu=604: -D_ARCH_PPC} \
+%{mcpu=604e: -D_ARCH_PPC} \
+%{mcpu=620: -D_ARCH_PPC} \
+%{mcpu=740: -D_ARCH_PPC} \
+%{mcpu=750: -D_ARCH_PPC} \
+%{mcpu=801: -D_ARCH_PPC} \
+%{mcpu=821: -D_ARCH_PPC} \
+%{mcpu=823: -D_ARCH_PPC} \
+%{mcpu=860: -D_ARCH_PPC}"
+
+#ifndef CPP_DEFAULT_SPEC
+#define CPP_DEFAULT_SPEC "-D_ARCH_PWR"
+#endif
+
+#ifndef CPP_SYSV_SPEC
+#define CPP_SYSV_SPEC ""
+#endif
+
+#ifndef CPP_ENDIAN_SPEC
+#define CPP_ENDIAN_SPEC ""
+#endif
+
+#ifndef CPP_ENDIAN_DEFAULT_SPEC
+#define CPP_ENDIAN_DEFAULT_SPEC ""
+#endif
+
+#ifndef CPP_SYSV_DEFAULT_SPEC
+#define CPP_SYSV_DEFAULT_SPEC ""
+#endif
+
+/* Common ASM definitions used by ASM_SPEC among the various targets
+ for handling -mcpu=xxx switches. */
+#define ASM_CPU_SPEC \
+"%{!mcpu*: \
+ %{mpower: %{!mpower2: -mpwr}} \
+ %{mpower2: -mpwrx} \
+ %{mpowerpc*: -mppc} \
+ %{mno-power: %{!mpowerpc*: -mcom}} \
+ %{!mno-power: %{!mpower2: %(asm_default)}}} \
+%{mcpu=common: -mcom} \
+%{mcpu=power: -mpwr} \
+%{mcpu=power2: -mpwrx} \
+%{mcpu=powerpc: -mppc} \
+%{mcpu=rios: -mpwr} \
+%{mcpu=rios1: -mpwr} \
+%{mcpu=rios2: -mpwrx} \
+%{mcpu=rsc: -mpwr} \
+%{mcpu=rsc1: -mpwr} \
+%{mcpu=401: -mppc} \
+%{mcpu=403: -mppc} \
+%{mcpu=505: -mppc} \
+%{mcpu=601: -m601} \
+%{mcpu=602: -mppc} \
+%{mcpu=603: -mppc} \
+%{mcpu=603e: -mppc} \
+%{mcpu=ec603e: -mppc} \
+%{mcpu=604: -mppc} \
+%{mcpu=604e: -mppc} \
+%{mcpu=620: -mppc} \
+%{mcpu=740: -mppc} \
+%{mcpu=750: -mppc} \
+%{mcpu=821: -mppc} \
+%{mcpu=823: -mppc} \
+%{mcpu=860: -mppc}"
+
+#ifndef ASM_DEFAULT_SPEC
+#define ASM_DEFAULT_SPEC ""
+#endif
+
+/* This macro defines names of additional specifications to put in the specs
+ that can be used in various specifications like CC1_SPEC. Its definition
+ is an initializer with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ specification name, and a string constant that used by the GNU CC driver
+ program.
+
+ Do not define this macro if it does not need to do anything. */
+
+#ifndef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS
+#endif
+
+#define EXTRA_SPECS \
+ { "cpp_cpu", CPP_CPU_SPEC }, \
+ { "cpp_default", CPP_DEFAULT_SPEC }, \
+ { "cpp_sysv", CPP_SYSV_SPEC }, \
+ { "cpp_sysv_default", CPP_SYSV_DEFAULT_SPEC }, \
+ { "cpp_endian_default", CPP_ENDIAN_DEFAULT_SPEC }, \
+ { "cpp_endian", CPP_ENDIAN_SPEC }, \
+ { "asm_cpu", ASM_CPU_SPEC }, \
+ { "asm_default", ASM_DEFAULT_SPEC }, \
+ { "link_syscalls", LINK_SYSCALLS_SPEC }, \
+ { "link_libg", LINK_LIBG_SPEC }, \
+ SUBTARGET_EXTRA_SPECS
+
+/* Default location of syscalls.exp under AIX */
+#ifndef CROSS_COMPILE
+#define LINK_SYSCALLS_SPEC "-bI:/lib/syscalls.exp"
+#else
+#define LINK_SYSCALLS_SPEC ""
+#endif
+
+/* Default location of libg.exp under AIX */
+#ifndef CROSS_COMPILE
+#define LINK_LIBG_SPEC "-bexport:/usr/lib/libg.exp"
+#else
+#define LINK_LIBG_SPEC ""
+#endif
+
+/* Define the options for the binder: Start text at 512, align all segments
+ to 512 bytes, and warn if there is text relocation.
+
+ The -bhalt:4 option supposedly changes the level at which ld will abort,
+ but it also suppresses warnings about multiply defined symbols and is
+ used by the AIX cc command. So we use it here.
+
+ -bnodelcsect undoes a poor choice of default relating to multiply-defined
+ csects. See AIX documentation for more information about this.
+
+ -bM:SRE tells the linker that the output file is Shared REusable. Note
+ that to actually build a shared library you will also need to specify an
+ export list with the -Wl,-bE option. */
+
+#define LINK_SPEC "-T512 -H512 %{!r:-btextro} -bhalt:4 -bnodelcsect\
+ %{static:-bnso %(link_syscalls) } \
+ %{!shared:%{g*: %(link_libg) }} %{shared:-bM:SRE}"
+
+/* Profiled library versions are used by linking with special directories. */
+#define LIB_SPEC "%{pg:-L/lib/profiled -L/usr/lib/profiled}\
+ %{p:-L/lib/profiled -L/usr/lib/profiled} %{!shared:%{g*:-lg}} -lc"
+
+/* gcc must do the search itself to find libgcc.a, not use -l. */
+#define LIBGCC_SPEC "libgcc.a%s"
+
+/* Don't turn -B into -L if the argument specifies a relative file name. */
+#define RELATIVE_PREFIX_NOT_LINKDIR
+
+/* Architecture type. */
+
+extern int target_flags;
+
+/* Use POWER architecture instructions and MQ register. */
+#define MASK_POWER 0x00000001
+
+/* Use POWER2 extensions to POWER architecture. */
+#define MASK_POWER2 0x00000002
+
+/* Use PowerPC architecture instructions. */
+#define MASK_POWERPC 0x00000004
+
+/* Use PowerPC General Purpose group optional instructions, e.g. fsqrt. */
+#define MASK_PPC_GPOPT 0x00000008
+
+/* Use PowerPC Graphics group optional instructions, e.g. fsel. */
+#define MASK_PPC_GFXOPT 0x00000010
+
+/* Use PowerPC-64 architecture instructions. */
+#define MASK_POWERPC64 0x00000020
+
+/* Use revised mnemonic names defined for PowerPC architecture. */
+#define MASK_NEW_MNEMONICS 0x00000040
+
+/* Disable placing fp constants in the TOC; can be turned on when the
+ TOC overflows. */
+#define MASK_NO_FP_IN_TOC 0x00000080
+
+/* Disable placing symbol+offset constants in the TOC; can be turned on when
+ the TOC overflows. */
+#define MASK_NO_SUM_IN_TOC 0x00000100
+
+/* Output only one TOC entry per module. Normally linking fails if
+ there are more than 16K unique variables/constants in an executable. With
+ this option, linking fails only if there are more than 16K modules, or
+ if there are more than 16K unique variables/constant in a single module.
+
+ This is at the cost of having 2 extra loads and one extra store per
+ function, and one less allocable register. */
+#define MASK_MINIMAL_TOC 0x00000200
+
+/* Nonzero for the 64bit model: ints, longs, and pointers are 64 bits. */
+#define MASK_64BIT 0x00000400
+
+/* Disable use of FPRs. */
+#define MASK_SOFT_FLOAT 0x00000800
+
+/* Enable load/store multiple, even on powerpc */
+#define MASK_MULTIPLE 0x00001000
+#define MASK_MULTIPLE_SET 0x00002000
+
+/* Use string instructions for block moves */
+#define MASK_STRING 0x00004000
+#define MASK_STRING_SET 0x00008000
+
+/* Disable update form of load/store */
+#define MASK_NO_UPDATE 0x00010000
+
+/* Disable fused multiply/add operations */
+#define MASK_NO_FUSED_MADD 0x00020000
+
+/* CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling */
+/* Nonzero if we need to make scheduling prolog */
+#define MASK_SCHED_PROLOG (0x40000)
+/* Nonzero if we need to make scheduling epilog */
+#define MASK_SCHED_EPILOG (0x80000)
+/* END CYGNUS LOCAL */
+
+#define TARGET_POWER (target_flags & MASK_POWER)
+#define TARGET_POWER2 (target_flags & MASK_POWER2)
+#define TARGET_POWERPC (target_flags & MASK_POWERPC)
+#define TARGET_PPC_GPOPT (target_flags & MASK_PPC_GPOPT)
+#define TARGET_PPC_GFXOPT (target_flags & MASK_PPC_GFXOPT)
+#define TARGET_POWERPC64 (target_flags & MASK_POWERPC64)
+#define TARGET_NEW_MNEMONICS (target_flags & MASK_NEW_MNEMONICS)
+#define TARGET_NO_FP_IN_TOC (target_flags & MASK_NO_FP_IN_TOC)
+#define TARGET_NO_SUM_IN_TOC (target_flags & MASK_NO_SUM_IN_TOC)
+#define TARGET_MINIMAL_TOC (target_flags & MASK_MINIMAL_TOC)
+#define TARGET_64BIT (target_flags & MASK_64BIT)
+#define TARGET_SOFT_FLOAT (target_flags & MASK_SOFT_FLOAT)
+#define TARGET_MULTIPLE (target_flags & MASK_MULTIPLE)
+#define TARGET_MULTIPLE_SET (target_flags & MASK_MULTIPLE_SET)
+#define TARGET_STRING (target_flags & MASK_STRING)
+#define TARGET_STRING_SET (target_flags & MASK_STRING_SET)
+#define TARGET_NO_UPDATE (target_flags & MASK_NO_UPDATE)
+#define TARGET_NO_FUSED_MADD (target_flags & MASK_NO_FUSED_MADD)
+
+#define TARGET_32BIT (! TARGET_64BIT)
+#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT)
+#define TARGET_UPDATE (! TARGET_NO_UPDATE)
+#define TARGET_FUSED_MADD (! TARGET_NO_FUSED_MADD)
+
+/* Pseudo target to indicate whether the object format is ELF
+ (to get around not having conditional compilation in the md file) */
+#ifndef TARGET_ELF
+#define TARGET_ELF 0
+#endif
+
+/* If this isn't V.4, don't support -mno-toc. */
+#ifndef TARGET_NO_TOC
+#define TARGET_NO_TOC 0
+#define TARGET_TOC 1
+#endif
+
+/* Pseudo target to say whether this is Windows NT */
+#ifndef TARGET_WINDOWS_NT
+#define TARGET_WINDOWS_NT 0
+#endif
+
+/* Pseudo target to say whether this is MAC */
+#ifndef TARGET_MACOS
+#define TARGET_MACOS 0
+#endif
+
+/* Pseudo target to say whether this is AIX */
+#ifndef TARGET_AIX
+#if (TARGET_ELF || TARGET_WINDOWS_NT || TARGET_MACOS)
+#define TARGET_AIX 0
+#else
+#define TARGET_AIX 1
+#endif
+#endif
+
+#ifndef TARGET_XL_CALL
+#define TARGET_XL_CALL 0
+#endif
+
+/* Run-time compilation parameters selecting different hardware subsets.
+
+ 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. */
+
+/* This is meant to be redefined in the host dependent files */
+#ifndef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES
+#endif
+
+#define TARGET_SWITCHES \
+ {{"power", MASK_POWER | MASK_MULTIPLE | MASK_STRING}, \
+ {"power2", (MASK_POWER | MASK_MULTIPLE | MASK_STRING \
+ | MASK_POWER2)}, \
+ {"no-power2", - MASK_POWER2}, \
+ {"no-power", - (MASK_POWER | MASK_POWER2 | MASK_MULTIPLE \
+ | MASK_STRING)}, \
+ {"powerpc", MASK_POWERPC}, \
+ {"no-powerpc", - (MASK_POWERPC | MASK_PPC_GPOPT \
+ | MASK_PPC_GFXOPT | MASK_POWERPC64)}, \
+ {"powerpc-gpopt", MASK_POWERPC | MASK_PPC_GPOPT}, \
+ {"no-powerpc-gpopt", - MASK_PPC_GPOPT}, \
+ {"powerpc-gfxopt", MASK_POWERPC | MASK_PPC_GFXOPT}, \
+ {"no-powerpc-gfxopt", - MASK_PPC_GFXOPT}, \
+ {"powerpc64", MASK_POWERPC64}, \
+ {"no-powerpc64", - MASK_POWERPC64}, \
+ {"new-mnemonics", MASK_NEW_MNEMONICS}, \
+ {"old-mnemonics", -MASK_NEW_MNEMONICS}, \
+ {"full-toc", - (MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC \
+ | MASK_MINIMAL_TOC)}, \
+ {"fp-in-toc", - MASK_NO_FP_IN_TOC}, \
+ {"no-fp-in-toc", MASK_NO_FP_IN_TOC}, \
+ {"sum-in-toc", - MASK_NO_SUM_IN_TOC}, \
+ {"no-sum-in-toc", MASK_NO_SUM_IN_TOC}, \
+ {"minimal-toc", MASK_MINIMAL_TOC}, \
+ {"minimal-toc", - (MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC)}, \
+ {"no-minimal-toc", - MASK_MINIMAL_TOC}, \
+ {"hard-float", - MASK_SOFT_FLOAT}, \
+ {"soft-float", MASK_SOFT_FLOAT}, \
+ {"multiple", MASK_MULTIPLE | MASK_MULTIPLE_SET}, \
+ {"no-multiple", - MASK_MULTIPLE}, \
+ {"no-multiple", MASK_MULTIPLE_SET}, \
+ {"string", MASK_STRING | MASK_STRING_SET}, \
+ {"no-string", - MASK_STRING}, \
+ {"no-string", MASK_STRING_SET}, \
+ {"update", - MASK_NO_UPDATE}, \
+ {"no-update", MASK_NO_UPDATE}, \
+ {"fused-madd", - MASK_NO_FUSED_MADD}, \
+ {"no-fused-madd", MASK_NO_FUSED_MADD}, \
+/* CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling */ \
+ {"sched-prolog", MASK_SCHED_PROLOG}, \
+ {"no-sched-prolog", -MASK_SCHED_PROLOG}, \
+ {"sched-epilog", MASK_SCHED_EPILOG}, \
+ {"no-sched-epilog", -MASK_SCHED_EPILOG}, \
+/* END CYGNUS LOCAL */ \
+ SUBTARGET_SWITCHES \
+ {"", TARGET_DEFAULT}}
+
+#define TARGET_DEFAULT (MASK_POWER | MASK_MULTIPLE | MASK_STRING)
+
+/* Processor type. Order must match cpu attribute in MD file. */
+enum processor_type
+{
+ PROCESSOR_RIOS1,
+ PROCESSOR_RIOS2,
+ PROCESSOR_MPCCORE,
+ PROCESSOR_PPC403,
+ PROCESSOR_PPC601,
+ PROCESSOR_PPC603,
+ PROCESSOR_PPC604,
+ PROCESSOR_PPC604e,
+ PROCESSOR_PPC620,
+ PROCESSOR_PPC750
+};
+
+extern enum processor_type rs6000_cpu;
+
+/* Recast the processor type to the cpu attribute. */
+#define rs6000_cpu_attr ((enum attr_cpu)rs6000_cpu)
+
+/* Define generic processor types based upon current deployment. */
+#define PROCESSOR_COMMON PROCESSOR_PPC601
+#define PROCESSOR_POWER PROCESSOR_RIOS1
+#define PROCESSOR_POWERPC PROCESSOR_PPC604
+
+/* Define the default processor. This is overridden by other tm.h files. */
+#define PROCESSOR_DEFAULT PROCESSOR_RIOS1
+
+/* Specify the dialect of assembler to use. New mnemonics is dialect one
+ and the old mnemonics are dialect zero. */
+#define ASSEMBLER_DIALECT TARGET_NEW_MNEMONICS ? 1 : 0
+
+/* This macro is similar to `TARGET_SWITCHES' but defines names of
+ command options that have values. Its definition is an
+ initializer with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ fixed part of the option name, and the address of a variable.
+ The variable, type `char *', is set to the variable part of the
+ given option if the fixed part matches. The actual option name
+ is made by appending `-m' to the specified name.
+
+ Here is an example which defines `-mshort-data-NUMBER'. If the
+ given option is `-mshort-data-512', the variable `m88k_short_data'
+ will be set to the string `"512"'.
+
+ extern char *m88k_short_data;
+ #define TARGET_OPTIONS { { "short-data-", &m88k_short_data } } */
+
+/* This is meant to be overridden in target specific files. */
+#ifndef SUBTARGET_OPTIONS
+#define SUBTARGET_OPTIONS
+#endif
+
+#define TARGET_OPTIONS \
+{ \
+ {"cpu=", &rs6000_select[1].string}, \
+ {"tune=", &rs6000_select[2].string}, \
+ {"debug-", &rs6000_debug_name}, \
+ {"debug=", &rs6000_debug_name}, \
+ /* CYGNUS LOCAL -- vmakarov */ \
+ {"branch-cost=", &rs6000_branch_cost_string},\
+ /* END CYGNUS LOCAL */ \
+ SUBTARGET_OPTIONS \
+}
+
+/* rs6000_select[0] is reserved for the default cpu defined via --with-cpu */
+struct rs6000_cpu_select
+{
+ char *string;
+ char *name;
+ int set_tune_p;
+ int set_arch_p;
+};
+
+extern struct rs6000_cpu_select rs6000_select[];
+
+/* Debug support */
+extern char *rs6000_debug_name; /* Name for -mdebug-xxxx option */
+extern int rs6000_debug_stack; /* debug stack applications */
+extern int rs6000_debug_arg; /* debug argument handling */
+
+#define TARGET_DEBUG_STACK rs6000_debug_stack
+#define TARGET_DEBUG_ARG rs6000_debug_arg
+
+/* CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling. */
+#define TARGET_SCHED_PROLOG ((target_flags & MASK_SCHED_PROLOG)\
+ && rs6000_current_abi == ABI_V4)
+#define TARGET_SCHED_EPILOG ((target_flags & MASK_SCHED_EPILOG)\
+ && rs6000_current_abi == ABI_V4)
+/* END CYGNUS LOCAL */
+
+/* CYGNUS LOCAL -- vmakarov */
+/* Override for BRANCH_COST */
+extern char *rs6000_branch_cost_string;
+int rs6000_branch_cost;
+/* END CYGNUS LOCAL */
+
+/* Sometimes certain combinations of command options do not make sense
+ on a particular target machine. You can define a macro
+ `OVERRIDE_OPTIONS' to take account of this. This macro, if
+ defined, is executed once just after all the command options have
+ been parsed.
+
+ Don't use this macro to turn on various extra optimizations for
+ `-O'. That is what `OPTIMIZATION_OPTIONS' is for.
+
+ On the RS/6000 this is used to define the target cpu type. */
+
+#define OVERRIDE_OPTIONS rs6000_override_options (TARGET_CPU_DEFAULT)
+
+/* Define this to change the optimizations performed by default. */
+#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) optimization_options(LEVEL,SIZE)
+
+
+/* Show we can debug even without a frame pointer. */
+#define CAN_DEBUG_WITHOUT_FP
+
+/* target machine storage layout */
+
+/* Define to support cross compilation to an RS6000 target. */
+#define REAL_ARITHMETIC
+
+/* Define this macro if it is advisable to hold scalars in registers
+ in a wider mode than that declared by the program. In such cases,
+ the value is constrained to be within the bounds of the declared
+ type, but kept valid in the wider mode. The signedness of the
+ extension may differ from that of the type. */
+
+#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \
+ if (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \
+ (MODE) = (! TARGET_POWERPC64 ? SImode : DImode);
+
+/* Define this if function arguments should also be promoted using the above
+ procedure. */
+
+#define PROMOTE_FUNCTION_ARGS
+
+/* Likewise, if the function return value is promoted. */
+
+#define PROMOTE_FUNCTION_RETURN
+
+/* Define this if most significant bit is lowest numbered
+ in instructions that operate on numbered bit-fields. */
+/* That is true on RS/6000. */
+#define BITS_BIG_ENDIAN 1
+
+/* Define this if most significant byte of a word is the lowest numbered. */
+/* That is true on RS/6000. */
+#define BYTES_BIG_ENDIAN 1
+
+/* Define this if most significant word of a multiword number is lowest
+ numbered.
+
+ For RS/6000 we can decide arbitrarily since there are no machine
+ instructions for them. Might as well be consistent with bits and bytes. */
+#define WORDS_BIG_ENDIAN 1
+
+/* number of bits in an addressable storage unit */
+#define BITS_PER_UNIT 8
+
+/* Width in bits of a "word", which is the contents of a machine register.
+ Note that this is not necessarily the width of data type `int';
+ if using 16-bit ints on a 68000, this would still be 32.
+ But on a machine with 16-bit registers, this would be 16. */
+#define BITS_PER_WORD (! TARGET_POWERPC64 ? 32 : 64)
+#define MAX_BITS_PER_WORD 64
+
+/* Width of a word, in units (bytes). */
+#define UNITS_PER_WORD (! TARGET_POWERPC64 ? 4 : 8)
+#define MIN_UNITS_PER_WORD 4
+#define UNITS_PER_FP_WORD 8
+
+/* Type used for ptrdiff_t, as a string used in a declaration. */
+#define PTRDIFF_TYPE "int"
+
+/* Type used for wchar_t, as a string used in a declaration. */
+#define WCHAR_TYPE "short unsigned int"
+
+/* Width of wchar_t in bits. */
+#define WCHAR_TYPE_SIZE 16
+
+/* A C expression for the size in bits of the type `short' on the
+ target machine. If you don't define this, the default is half a
+ word. (If this would be less than one storage unit, it is
+ rounded up to one unit.) */
+#define SHORT_TYPE_SIZE 16
+
+/* A C expression for the size in bits of the type `int' on the
+ target machine. If you don't define this, the default is one
+ word. */
+#define INT_TYPE_SIZE 32
+
+/* A C expression for the size in bits of the type `long' on the
+ target machine. If you don't define this, the default is one
+ word. */
+#define LONG_TYPE_SIZE (TARGET_32BIT ? 32 : 64)
+#define MAX_LONG_TYPE_SIZE 64
+
+/* A C expression for the size in bits of the type `long long' on the
+ target machine. If you don't define this, the default is two
+ words. */
+#define LONG_LONG_TYPE_SIZE 64
+
+/* A C expression for the size in bits of the type `char' on the
+ target machine. If you don't define this, the default is one
+ quarter of a word. (If this would be less than one storage unit,
+ it is rounded up to one unit.) */
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+
+/* A C expression for the size in bits of the type `float' on the
+ target machine. If you don't define this, the default is one
+ word. */
+#define FLOAT_TYPE_SIZE 32
+
+/* A C expression for the size in bits of the type `double' on the
+ target machine. If you don't define this, the default is two
+ words. */
+#define DOUBLE_TYPE_SIZE 64
+
+/* A C expression for the size in bits of the type `long double' on
+ the target machine. If you don't define this, the default is two
+ words. */
+#define LONG_DOUBLE_TYPE_SIZE 64
+
+/* Width in bits of a pointer.
+ See also the macro `Pmode' defined below. */
+#define POINTER_SIZE (TARGET_32BIT ? 32 : 64)
+
+/* Allocation boundary (in *bits*) for storing arguments in argument list. */
+#define PARM_BOUNDARY (TARGET_32BIT ? 32 : 64)
+
+/* Boundary (in *bits*) on which stack pointer should be aligned. */
+#define STACK_BOUNDARY (TARGET_32BIT ? 64 : 128)
+
+/* Allocation boundary (in *bits*) for the code of a function. */
+#define FUNCTION_BOUNDARY 32
+
+/* No data type wants to be aligned rounder than this. */
+#define BIGGEST_ALIGNMENT 64
+
+/* AIX word-aligns FP doubles but doubleword-aligns 64-bit ints. */
+#define ADJUST_FIELD_ALIGN(FIELD, COMPUTED) \
+ (TYPE_MODE (TREE_CODE (TREE_TYPE (FIELD)) == ARRAY_TYPE \
+ ? get_inner_array_type (FIELD) \
+ : TREE_TYPE (FIELD)) == DFmode \
+ ? MIN ((COMPUTED), 32) : (COMPUTED))
+
+/* Alignment of field after `int : 0' in a structure. */
+#define EMPTY_FIELD_BOUNDARY 32
+
+/* Every structure's size must be a multiple of this. */
+#define STRUCTURE_SIZE_BOUNDARY 8
+
+/* A bitfield declared as `int' forces `int' alignment for the struct. */
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* AIX increases natural record alignment to doubleword if the first
+ field is an FP double while the FP fields remain word aligned. */
+#define ROUND_TYPE_ALIGN(STRUCT, COMPUTED, SPECIFIED) \
+ ((TREE_CODE (STRUCT) == RECORD_TYPE \
+ || TREE_CODE (STRUCT) == UNION_TYPE \
+ || TREE_CODE (STRUCT) == QUAL_UNION_TYPE) \
+ && TYPE_FIELDS (STRUCT) != 0 \
+ && DECL_MODE (TYPE_FIELDS (STRUCT)) == DFmode \
+ ? MAX (MAX ((COMPUTED), (SPECIFIED)), BIGGEST_ALIGNMENT) \
+ : MAX ((COMPUTED), (SPECIFIED)))
+
+/* Make strings word-aligned so strcpy from constants will be faster. */
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
+ (TREE_CODE (EXP) == STRING_CST \
+ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+/* Make arrays of chars word-aligned for the same reasons. */
+#define DATA_ALIGNMENT(TYPE, ALIGN) \
+ (TREE_CODE (TYPE) == ARRAY_TYPE \
+ && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
+ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+/* Non-zero if move instructions will actually fail to work
+ when given unaligned data. */
+#define STRICT_ALIGNMENT 0
+
+/* Standard register usage. */
+
+/* Number of actual hardware registers.
+ The hardware registers are assigned numbers for the compiler
+ from 0 to just below FIRST_PSEUDO_REGISTER.
+ All registers that the compiler knows about must be given numbers,
+ even those that are not normally considered general registers.
+
+ RS/6000 has 32 fixed-point registers, 32 floating-point registers,
+ an MQ register, a count register, a link register, and 8 condition
+ register fields, which we view here as separate registers.
+
+ In addition, the difference between the frame and argument pointers is
+ a function of the number of registers saved, so we need to have a
+ register for AP that will later be eliminated in favor of SP or FP.
+ This is a normal register, but it is fixed.
+
+ We also create a pseudo register for float/int conversions, that will
+ really represent the memory location used. It is represented here as
+ a register, in order to work around problems in allocating stack storage
+ in inline functions. */
+
+#define FIRST_PSEUDO_REGISTER 77
+
+/* 1 for registers that have pervasive standard uses
+ and are not available for the register allocator.
+
+ On RS/6000, r1 is used for the stack and r2 is used as the TOC pointer.
+
+ cr5 is not supposed to be used.
+
+ On System V implementations, r13 is fixed and not available for use. */
+
+#ifndef FIXED_R13
+#define FIXED_R13 0
+#endif
+
+#define FIXED_REGISTERS \
+ {0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FIXED_R13, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1}
+
+/* 1 for registers not available across function calls.
+ These must include the FIXED_REGISTERS and also any
+ registers that can be used without being saved.
+ The latter must include the registers where values are returned
+ and the register where structure-value addresses are passed.
+ Aside from that, you can include as many other registers as you like. */
+
+#define CALL_USED_REGISTERS \
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, FIXED_R13, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1}
+
+/* List the order in which to allocate registers. Each register must be
+ listed once, even those in FIXED_REGISTERS.
+
+ We allocate in the following order:
+ fp0 (not saved or used for anything)
+ fp13 - fp2 (not saved; incoming fp arg registers)
+ fp1 (not saved; return value)
+ fp31 - fp14 (saved; order given to save least number)
+ cr7, cr6 (not saved or special)
+ cr1 (not saved, but used for FP operations)
+ cr0 (not saved, but used for arithmetic operations)
+ cr4, cr3, cr2 (saved)
+ r0 (not saved; cannot be base reg)
+ r9 (not saved; best for TImode)
+ r11, r10, r8-r4 (not saved; highest used first to make less conflict)
+ r3 (not saved; return value register)
+ r31 - r13 (saved; order given to save least number)
+ r12 (not saved; if used for DImode or DFmode would use r13)
+ mq (not saved; best to use it if we can)
+ ctr (not saved; when we have the choice ctr is better)
+ lr (saved)
+ cr5, r1, r2, ap, fpmem (fixed) */
+
+#define REG_ALLOC_ORDER \
+ {32, \
+ 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, \
+ 33, \
+ 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \
+ 50, 49, 48, 47, 46, \
+ 75, 74, 69, 68, 72, 71, 70, \
+ 0, \
+ 9, 11, 10, 8, 7, 6, 5, 4, \
+ 3, \
+ 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, \
+ 18, 17, 16, 15, 14, 13, 12, \
+ 64, 66, 65, \
+ 73, 1, 2, 67, 76}
+
+/* True if register is floating-point. */
+#define FP_REGNO_P(N) ((N) >= 32 && (N) <= 63)
+
+/* True if register is a condition register. */
+#define CR_REGNO_P(N) ((N) >= 68 && (N) <= 75)
+
+/* True if register is condition register 0. */
+#define CR0_REGNO_P(N) ((N) == 68)
+
+/* True if register is a condition register, but not cr0. */
+#define CR_REGNO_NOT_CR0_P(N) ((N) >= 69 && (N) <= 75)
+
+/* True if register is an integer register. */
+#define INT_REGNO_P(N) ((N) <= 31 || (N) == 67)
+
+/* True if register is the temporary memory location used for int/float
+ conversion. */
+#define FPMEM_REGNO_P(N) ((N) == FPMEM_REGNUM)
+
+/* Return number of consecutive hard regs needed starting at reg REGNO
+ to hold something of mode MODE.
+ This is ordinarily the length in words of a value of mode MODE
+ but can be less for certain modes in special long registers.
+
+ POWER and PowerPC GPRs hold 32 bits worth;
+ PowerPC64 GPRs and FPRs point register holds 64 bits worth. */
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ (FP_REGNO_P (REGNO) || FPMEM_REGNO_P (REGNO) \
+ ? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
+ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
+ For POWER and PowerPC, the GPRs can hold any mode, but the float
+ registers only can hold floating modes and DImode, and CR register only
+ can hold CC modes. We cannot put TImode anywhere except general
+ register and it must be able to fit within the register set. */
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ (FP_REGNO_P (REGNO) ? \
+ (GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ || (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) == UNITS_PER_FP_WORD)) \
+ : CR_REGNO_P (REGNO) ? GET_MODE_CLASS (MODE) == MODE_CC \
+ : FPMEM_REGNO_P (REGNO) ? ((MODE) == DImode || (MODE) == DFmode) \
+ : ! INT_REGNO_P (REGNO) ? (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) <= UNITS_PER_WORD) \
+ : 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,
+ for any hard reg, then this must be 0 for correct output. */
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ (GET_MODE_CLASS (MODE1) == MODE_FLOAT \
+ ? GET_MODE_CLASS (MODE2) == MODE_FLOAT \
+ : GET_MODE_CLASS (MODE2) == MODE_FLOAT \
+ ? GET_MODE_CLASS (MODE1) == MODE_FLOAT \
+ : GET_MODE_CLASS (MODE1) == MODE_CC \
+ ? GET_MODE_CLASS (MODE2) == MODE_CC \
+ : GET_MODE_CLASS (MODE2) == MODE_CC \
+ ? GET_MODE_CLASS (MODE1) == MODE_CC \
+ : 1)
+
+/* A C expression returning the cost of moving data from a register of class
+ CLASS1 to one of CLASS2.
+
+ On the RS/6000, copying between floating-point and fixed-point
+ registers is expensive. */
+
+#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
+ ((CLASS1) == FLOAT_REGS && (CLASS2) == FLOAT_REGS ? 2 \
+ : (CLASS1) == FLOAT_REGS && (CLASS2) != FLOAT_REGS ? 10 \
+ : (CLASS1) != FLOAT_REGS && (CLASS2) == FLOAT_REGS ? 10 \
+ : (((CLASS1) == SPECIAL_REGS || (CLASS1) == MQ_REGS \
+ || (CLASS1) == LINK_REGS || (CLASS1) == CTR_REGS \
+ || (CLASS1) == LINK_OR_CTR_REGS) \
+ && ((CLASS2) == SPECIAL_REGS || (CLASS2) == MQ_REGS \
+ || (CLASS2) == LINK_REGS || (CLASS2) == CTR_REGS \
+ || (CLASS2) == LINK_OR_CTR_REGS)) ? 10 \
+ : 2)
+
+/* A C expressions returning the cost of moving data of MODE from a register to
+ or from memory.
+
+ On the RS/6000, bump this up a bit. */
+
+#define MEMORY_MOVE_COST(MODE,CLASS,IN) \
+ ((GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ && (rs6000_cpu == PROCESSOR_RIOS1 || rs6000_cpu == PROCESSOR_PPC601) \
+ ? 3 : 2) \
+ + 4)
+
+/* Specify the cost of a branch insn; roughly the number of extra insns that
+ should be added to avoid a branch.
+
+ Set this to 3 on the RS/6000 since that is roughly the average cost of an
+ unscheduled conditional branch. */
+
+/* CYGNUS LOCAL -- vmakarov */
+#define BRANCH_COST_DEFAULT 3
+#define BRANCH_COST rs6000_branch_cost
+/* END CYGNUS LOCAL */
+
+/* A C statement (sans semicolon) to update the integer variable COST
+ based on the relationship between INSN that is dependent on
+ DEP_INSN through the dependence LINK. The default is to make no
+ adjustment to COST. On the RS/6000, ignore the cost of anti- and
+ output-dependencies. In fact, output dependencies on the CR do have
+ a cost, but it is probably not worthwhile to track it. */
+
+#define ADJUST_COST(INSN,LINK,DEP_INSN,COST) \
+ (COST) = rs6000_adjust_cost (INSN,LINK,DEP_INSN,COST)
+
+/* A C statement (sans semicolon) to update the integer scheduling priority
+ INSN_PRIORITY (INSN). Reduce the priority to execute the INSN earlier,
+ increase the priority to execute INSN later. Do not define this macro if
+ you do not need to adjust the scheduling priorities of insns. */
+
+#define ADJUST_PRIORITY(INSN) \
+ INSN_PRIORITY (INSN) = rs6000_adjust_priority (INSN, INSN_PRIORITY (INSN))
+
+/* Define this macro to change register usage conditional on target flags.
+ Set MQ register fixed (already call_used) if not POWER architecture
+ (RIOS1, RIOS2, RSC, and PPC601) so that it will not be allocated.
+ 64-bit AIX reserves GPR13 for thread-private data.
+ Conditionally disable FPRs. */
+
+#define CONDITIONAL_REGISTER_USAGE \
+{ \
+ if (! TARGET_POWER) \
+ fixed_regs[64] = 1; \
+ if (TARGET_64BIT) \
+ fixed_regs[13] = call_used_regs[13] = 1; \
+ if (TARGET_SOFT_FLOAT) \
+ for (i = 32; i < 64; i++) \
+ fixed_regs[i] = call_used_regs[i] = 1; \
+}
+
+/* Specify the registers used for certain standard purposes.
+ The values of these macros are register numbers. */
+
+/* RS/6000 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 1
+
+/* Base register for access to local variables of the function. */
+#define FRAME_POINTER_REGNUM 31
+
+/* 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. */
+#define FRAME_POINTER_REQUIRED 0
+
+/* Base register for access to arguments of the function. */
+#define ARG_POINTER_REGNUM 67
+
+/* Place to put static chain when calling a function that requires it. */
+#define STATIC_CHAIN_REGNUM 11
+
+/* count register number for special purposes */
+#define COUNT_REGISTER_REGNUM 66
+
+/* Special register that represents memory, used for float/int conversions. */
+#define FPMEM_REGNUM 76
+
+/* Register to use as a placeholder for the GOT/allocated TOC register.
+ FINALIZE_PIC will change all uses of this register to a an appropriate
+ pseudo register when it adds the code to setup the GOT. We use r2
+ because it is a reserved register in all of the ABI's. */
+#define GOT_TOC_REGNUM 2
+
+/* Place that structure value return address is placed.
+
+ On the RS/6000, it is passed as an extra parameter. */
+#define STRUCT_VALUE 0
+
+/* Define the classes of registers for register constraints in the
+ machine description. Also define ranges of constants.
+
+ One of the classes must always be named ALL_REGS and include all hard regs.
+ If there is more than one class, another class must be named NO_REGS
+ and contain no registers.
+
+ The name GENERAL_REGS must be the name of a class (or an alias for
+ another name such as ALL_REGS). This is the class of registers
+ that is allowed by "g" or "r" in a register constraint.
+ Also, registers outside this class are allocated only when
+ instructions express preferences for them.
+
+ The classes must be numbered in nondecreasing order; that is,
+ a larger-numbered class must never be contained completely
+ in a smaller-numbered class.
+
+ For any two classes, it is very desirable that there be another
+ class that represents their union. */
+
+/* The RS/6000 has three types of registers, fixed-point, floating-point,
+ and condition registers, plus three special registers, MQ, CTR, and the
+ link register.
+
+ However, r0 is special in that it cannot be used as a base register.
+ So make a class for registers valid as base registers.
+
+ Also, cr0 is the only condition code register that can be used in
+ arithmetic insns, so make a separate class for it.
+
+ There is a special 'register' (76), which is not a register, but a
+ placeholder for memory allocated to convert between floating point and
+ integral types. This works around a problem where if we allocate memory
+ with allocate_stack_{local,temp} and the function is an inline function, the
+ memory allocated will clobber memory in the caller. So we use a special
+ register, and if that is used, we allocate stack space for it. */
+
+enum reg_class
+{
+ NO_REGS,
+ BASE_REGS,
+ GENERAL_REGS,
+ FLOAT_REGS,
+ NON_SPECIAL_REGS,
+ MQ_REGS,
+ LINK_REGS,
+ CTR_REGS,
+ LINK_OR_CTR_REGS,
+ SPECIAL_REGS,
+ SPEC_OR_GEN_REGS,
+ CR0_REGS,
+ CR_REGS,
+ NON_FLOAT_REGS,
+ FPMEM_REGS,
+ FLOAT_OR_FPMEM_REGS,
+ ALL_REGS,
+ LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+/* Give names of register classes as strings for dump file. */
+
+#define REG_CLASS_NAMES \
+{ \
+ "NO_REGS", \
+ "BASE_REGS", \
+ "GENERAL_REGS", \
+ "FLOAT_REGS", \
+ "NON_SPECIAL_REGS", \
+ "MQ_REGS", \
+ "LINK_REGS", \
+ "CTR_REGS", \
+ "LINK_OR_CTR_REGS", \
+ "SPECIAL_REGS", \
+ "SPEC_OR_GEN_REGS", \
+ "CR0_REGS", \
+ "CR_REGS", \
+ "NON_FLOAT_REGS", \
+ "FPMEM_REGS", \
+ "FLOAT_OR_FPMEM_REGS", \
+ "ALL_REGS" \
+}
+
+/* Define which registers fit in which classes.
+ This is an initializer for a vector of HARD_REG_SET
+ of length N_REG_CLASSES. */
+
+#define REG_CLASS_CONTENTS \
+{ \
+ { 0x00000000, 0x00000000, 0x00000000 }, /* NO_REGS */ \
+ { 0xfffffffe, 0x00000000, 0x00000008 }, /* BASE_REGS */ \
+ { 0xffffffff, 0x00000000, 0x00000008 }, /* GENERAL_REGS */ \
+ { 0x00000000, 0xffffffff, 0x00000000 }, /* FLOAT_REGS */ \
+ { 0xffffffff, 0xffffffff, 0x00000008 }, /* NON_SPECIAL_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000001 }, /* MQ_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000002 }, /* LINK_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000004 }, /* CTR_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000006 }, /* LINK_OR_CTR_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000007 }, /* SPECIAL_REGS */ \
+ { 0xffffffff, 0x00000000, 0x0000000f }, /* SPEC_OR_GEN_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000010 }, /* CR0_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000ff0 }, /* CR_REGS */ \
+ { 0xffffffff, 0x00000000, 0x0000ffff }, /* NON_FLOAT_REGS */ \
+ { 0x00000000, 0x00000000, 0x00010000 }, /* FPMEM_REGS */ \
+ { 0x00000000, 0xffffffff, 0x00010000 }, /* FLOAT_OR_FPMEM_REGS */ \
+ { 0xffffffff, 0xffffffff, 0x0001ffff } /* ALL_REGS */ \
+}
+
+/* The same information, inverted:
+ Return the class number of the smallest class containing
+ reg number REGNO. This could be a conditional expression
+ or could index an array. */
+
+#define REGNO_REG_CLASS(REGNO) \
+ ((REGNO) == 0 ? GENERAL_REGS \
+ : (REGNO) < 32 ? BASE_REGS \
+ : FP_REGNO_P (REGNO) ? FLOAT_REGS \
+ : (REGNO) == 68 ? CR0_REGS \
+ : CR_REGNO_P (REGNO) ? CR_REGS \
+ : (REGNO) == 64 ? MQ_REGS \
+ : (REGNO) == 65 ? LINK_REGS \
+ : (REGNO) == 66 ? CTR_REGS \
+ : (REGNO) == 67 ? BASE_REGS \
+ : (REGNO) == 76 ? FPMEM_REGS \
+ : NO_REGS)
+
+/* The class value for index registers, and the one for base regs. */
+#define INDEX_REG_CLASS GENERAL_REGS
+#define BASE_REG_CLASS BASE_REGS
+
+/* Get reg_class from a letter such as appears in the machine description. */
+
+#define REG_CLASS_FROM_LETTER(C) \
+ ((C) == 'f' ? FLOAT_REGS \
+ : (C) == 'b' ? BASE_REGS \
+ : (C) == 'h' ? SPECIAL_REGS \
+ : (C) == 'q' ? MQ_REGS \
+ : (C) == 'c' ? CTR_REGS \
+ : (C) == 'l' ? LINK_REGS \
+ : (C) == 'x' ? CR0_REGS \
+ : (C) == 'y' ? CR_REGS \
+ : (C) == 'z' ? FPMEM_REGS \
+ : NO_REGS)
+
+/* The letters I, J, K, L, M, N, and P in a register constraint string
+ can be used to stand for particular ranges of immediate operands.
+ 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.
+
+ `I' is signed 16-bit constants
+ `J' is a constant with only the high-order 16 bits non-zero
+ `K' is a constant with only the low-order 16 bits non-zero
+ `L' is a constant that can be placed into a mask operand
+ `M' is a constant that is greater than 31
+ `N' is a constant that is an exact power of two
+ `O' is the constant zero
+ `P' is a constant whose negation is a signed 16-bit constant */
+
+#define CONST_OK_FOR_LETTER_P(VALUE, C) \
+ ( (C) == 'I' ? (unsigned HOST_WIDE_INT) ((VALUE) + 0x8000) < 0x10000 \
+ : (C) == 'J' ? ((VALUE) & 0xffff) == 0 \
+ : (C) == 'K' ? ((VALUE) & (~ (HOST_WIDE_INT) 0xffff)) == 0 \
+ : (C) == 'L' ? mask_constant (VALUE) \
+ : (C) == 'M' ? (VALUE) > 31 \
+ : (C) == 'N' ? exact_log2 (VALUE) >= 0 \
+ : (C) == 'O' ? (VALUE) == 0 \
+ : (C) == 'P' ? (unsigned HOST_WIDE_INT) ((- (VALUE)) + 0x8000) < 0x1000 \
+ : 0)
+
+/* Similar, but for floating constants, and defining letters G and H.
+ Here VALUE is the CONST_DOUBLE rtx itself.
+
+ We flag for special constants when we can copy the constant into
+ a general register in two insns for DF/DI and one insn for SF.
+
+ 'H' is used for DI/DF constants that take 3 insns. */
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
+ ( (C) == 'G' ? (num_insns_constant (VALUE, GET_MODE (VALUE)) \
+ == ((GET_MODE (VALUE) == SFmode) ? 1 : 2)) \
+ : (C) == 'H' ? (num_insns_constant (VALUE, GET_MODE (VALUE)) == 3) \
+ : 0)
+
+/* Optional extra constraints for this machine.
+
+ 'Q' means that is a memory operand that is just an offset from a reg.
+ 'R' is for AIX TOC entries.
+ 'S' is a constant that can be placed into a 64-bit mask operand
+ 'U' is for V.4 small data references. */
+
+#define EXTRA_CONSTRAINT(OP, C) \
+ ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG \
+ : (C) == 'R' ? LEGITIMATE_CONSTANT_POOL_ADDRESS_P (OP) \
+ : (C) == 'S' ? mask64_operand (OP, VOIDmode) \
+ : (C) == 'U' ? ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) \
+ && small_data_operand (OP, GET_MODE (OP))) \
+ : 0)
+
+/* Given an rtx X being reloaded into a reg required to be
+ in class CLASS, return the class of reg to actually use.
+ In general this is just CLASS; but on some machines
+ in some cases it is preferable to use a more restrictive class.
+
+ On the RS/6000, we have to return NO_REGS when we want to reload a
+ floating-point CONST_DOUBLE to force it to be copied to memory. */
+
+#define PREFERRED_RELOAD_CLASS(X,CLASS) \
+ ((GET_CODE (X) == CONST_DOUBLE \
+ && GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) \
+ ? NO_REGS : (CLASS))
+
+/* Return the register class of a scratch register needed to copy IN into
+ or out of a register in CLASS in MODE. If it can be done directly,
+ NO_REGS is returned. */
+
+#define SECONDARY_RELOAD_CLASS(CLASS,MODE,IN) \
+ secondary_reload_class (CLASS, MODE, IN)
+
+/* If we are copying between FP registers and anything else, we need a memory
+ location. */
+
+#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \
+ ((CLASS1) != (CLASS2) && ((CLASS1) == FLOAT_REGS || (CLASS2) == FLOAT_REGS))
+
+/* Return the maximum number of consecutive registers
+ needed to represent mode MODE in a register of class CLASS.
+
+ On RS/6000, this is the size of MODE in words,
+ except in the FP regs, where a single reg is enough for two words. */
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ (((CLASS) == FLOAT_REGS || (CLASS) == FPMEM_REGS \
+ || (CLASS) == FLOAT_OR_FPMEM_REGS) \
+ ? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
+ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+/* If defined, gives a class of registers that cannot be used as the
+ operand of a SUBREG that changes the size of the object. */
+
+#define CLASS_CANNOT_CHANGE_SIZE FLOAT_OR_FPMEM_REGS
+
+/* Stack layout; function entry, exit and calling. */
+
+/* Enumeration to give which calling sequence to use. */
+enum rs6000_abi {
+ ABI_NONE,
+ ABI_AIX, /* IBM's AIX */
+ ABI_AIX_NODESC, /* AIX calling sequence minus function descriptors */
+ ABI_V4, /* System V.4/eabi */
+ ABI_NT, /* Windows/NT */
+ ABI_SOLARIS /* Solaris */
+};
+
+extern enum rs6000_abi rs6000_current_abi; /* available for use by subtarget */
+
+/* Default ABI to compile code for */
+#ifndef DEFAULT_ABI
+#define DEFAULT_ABI ABI_AIX
+/* The prefix to add to user-visible assembler symbols. */
+#define USER_LABEL_PREFIX "."
+#endif
+
+/* Structure used to define the rs6000 stack */
+typedef struct rs6000_stack {
+ int first_gp_reg_save; /* first callee saved GP register used */
+ int first_fp_reg_save; /* first callee saved FP register used */
+ int lr_save_p; /* true if the link reg needs to be saved */
+ int cr_save_p; /* true if the CR reg needs to be saved */
+ int toc_save_p; /* true if the TOC needs to be saved */
+ int push_p; /* true if we need to allocate stack space */
+ int calls_p; /* true if the function makes any calls */
+ int main_p; /* true if this is main */
+ int main_save_p; /* true if this is main and we need to save args */
+ int fpmem_p; /* true if float/int conversion temp needed */
+ enum rs6000_abi abi; /* which ABI to use */
+ int gp_save_offset; /* offset to save GP regs from initial SP */
+ int fp_save_offset; /* offset to save FP regs from initial SP */
+ int lr_save_offset; /* offset to save LR from initial SP */
+ int cr_save_offset; /* offset to save CR from initial SP */
+ int toc_save_offset; /* offset to save the TOC pointer */
+ int varargs_save_offset; /* offset to save the varargs registers */
+ int main_save_offset; /* offset to save main's args */
+ int fpmem_offset; /* offset for float/int conversion temp */
+ int reg_size; /* register size (4 or 8) */
+ int varargs_size; /* size to hold V.4 args passed in regs */
+ int vars_size; /* variable save area size */
+ int parm_size; /* outgoing parameter size */
+ int main_size; /* size to hold saving main's args */
+ int save_size; /* save area size */
+ int fixed_size; /* fixed size of stack frame */
+ int gp_size; /* size of saved GP registers */
+ int fp_size; /* size of saved FP registers */
+ int cr_size; /* size to hold CR if not in save_size */
+ int lr_size; /* size to hold LR if not in save_size */
+ int fpmem_size; /* size to hold float/int conversion */
+ int toc_size; /* size to hold TOC if not in save_size */
+ int total_size; /* total bytes allocated for stack */
+} rs6000_stack_t;
+
+/* 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
+ 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.
+
+ On the RS/6000, we grow upwards, from the area after the outgoing
+ arguments. */
+/* #define FRAME_GROWS_DOWNWARD */
+
+/* Size of the outgoing register save area */
+#define RS6000_REG_SAVE (TARGET_32BIT ? 32 : 64)
+
+/* Size of the fixed area on the stack */
+#define RS6000_SAVE_AREA (TARGET_32BIT ? 24 : 48)
+
+/* Address to save the TOC register */
+#define RS6000_SAVE_TOC plus_constant (stack_pointer_rtx, (TARGET_32BIT ? 20 : 40))
+
+/* Offset & size for fpmem stack locations used for converting between
+ float and integral types. */
+extern int rs6000_fpmem_offset;
+extern int rs6000_fpmem_size;
+
+/* Size of the V.4 varargs area if needed */
+#define RS6000_VARARGS_AREA 0
+
+/* Whether a V.4 varargs area is needed */
+extern int rs6000_sysv_varargs_p;
+
+/* Align an address */
+#define RS6000_ALIGN(n,a) (((n) + (a) - 1) & ~((a) - 1))
+
+/* Initialize data used by insn expanders. This is called from
+ init_emit, once for each function, before code is generated. */
+#define INIT_EXPANDERS rs6000_init_expanders ()
+
+/* Size of V.4 varargs area in bytes */
+#define RS6000_VARARGS_SIZE \
+ ((GP_ARG_NUM_REG * (TARGET_32BIT ? 4 : 8)) + (FP_ARG_NUM_REG * 8) + 8)
+
+/* Offset of V.4 varargs area */
+#define RS6000_VARARGS_OFFSET \
+ (RS6000_ALIGN (current_function_outgoing_args_size, 8) \
+ + RS6000_SAVE_AREA)
+
+/* 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.
+
+ On the RS/6000, the frame pointer is the same as the stack pointer,
+ except for dynamic allocations. So we start after the fixed area and
+ outgoing parameter area. */
+
+#define STARTING_FRAME_OFFSET \
+ (RS6000_ALIGN (current_function_outgoing_args_size, 8) \
+ + RS6000_VARARGS_AREA \
+ + RS6000_SAVE_AREA)
+
+/* Offset from the stack pointer register to an item dynamically
+ allocated on the stack, e.g., by `alloca'.
+
+ The default value for this macro is `STACK_POINTER_OFFSET' plus the
+ length of the outgoing arguments. The default is correct for most
+ machines. See `function.c' for details. */
+#define STACK_DYNAMIC_OFFSET(FUNDECL) \
+ (RS6000_ALIGN (current_function_outgoing_args_size, 8) \
+ + (STACK_POINTER_OFFSET))
+
+/* If we generate an insn to push BYTES bytes,
+ this says how many the stack pointer really advances by.
+ On RS/6000, don't define this because there are no push insns. */
+/* #define PUSH_ROUNDING(BYTES) */
+
+/* Offset of first parameter from the argument pointer register value.
+ On the RS/6000, we define the argument pointer to the start of the fixed
+ area. */
+#define FIRST_PARM_OFFSET(FNDECL) RS6000_SAVE_AREA
+
+/* Define this if stack space is still allocated for a parameter passed
+ in a register. The value is the number of bytes allocated to this
+ area. */
+#define REG_PARM_STACK_SPACE(FNDECL) RS6000_REG_SAVE
+
+/* Define this if the above stack space is to be considered part of the
+ space allocated by the caller. */
+#define OUTGOING_REG_PARM_STACK_SPACE
+
+/* This is the difference between the logical top of stack and the actual sp.
+
+ For the RS/6000, sp points past the fixed area. */
+#define STACK_POINTER_OFFSET RS6000_SAVE_AREA
+
+/* Define this if the maximum size of all the outgoing args is to be
+ accumulated and pushed during the prologue. The amount can be
+ found in the variable current_function_outgoing_args_size. */
+#define ACCUMULATE_OUTGOING_ARGS
+
+/* Value is the number of bytes of arguments automatically
+ popped when returning from a subroutine call.
+ FUNDECL is the declaration node of the function (as a tree),
+ FUNTYPE is the data type of the function (as a tree),
+ or for a library call it is an identifier node for the subroutine name.
+ SIZE is the number of bytes of arguments passed on the stack. */
+
+#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0
+
+/* Define how to find the value returned by a function.
+ VALTYPE is the data type of the value (as a tree).
+ If the precise function being called is known, FUNC is its FUNCTION_DECL;
+ otherwise, FUNC is 0.
+
+ On RS/6000 an integer value is in r3 and a floating-point value is in
+ fp1, unless -msoft-float. */
+
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+ gen_rtx_REG ((INTEGRAL_TYPE_P (VALTYPE) \
+ && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
+ || POINTER_TYPE_P (VALTYPE) \
+ ? word_mode : TYPE_MODE (VALTYPE), \
+ TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_HARD_FLOAT ? 33 : 3)
+
+/* Define how to find the value returned by a library function
+ assuming the value has mode MODE. */
+
+#define LIBCALL_VALUE(MODE) \
+ gen_rtx_REG (MODE, \
+ GET_MODE_CLASS (MODE) == MODE_FLOAT && TARGET_HARD_FLOAT ? 33 : 3)
+
+/* The definition of this macro implies that there are cases where
+ a scalar value cannot be returned in registers.
+
+ For the RS/6000, any structure or union type is returned in memory, except for
+ Solaris, which returns structures <= 8 bytes in registers. */
+
+#define RETURN_IN_MEMORY(TYPE) \
+ (TYPE_MODE (TYPE) == BLKmode \
+ && (DEFAULT_ABI != ABI_SOLARIS || int_size_in_bytes (TYPE) > 8))
+
+/* Mode of stack savearea.
+ FUNCTION is VOIDmode because calling convention maintains SP.
+ BLOCK needs Pmode for SP.
+ NONLOCAL needs twice Pmode to maintain both backchain and SP. */
+#define STACK_SAVEAREA_MODE(LEVEL) \
+ (LEVEL == SAVE_FUNCTION ? VOIDmode \
+ : LEVEL == SAVE_NONLOCAL ? (TARGET_32BIT ? DImode : TImode) : Pmode)
+
+/* Minimum and maximum general purpose registers used to hold arguments. */
+#define GP_ARG_MIN_REG 3
+#define GP_ARG_MAX_REG 10
+#define GP_ARG_NUM_REG (GP_ARG_MAX_REG - GP_ARG_MIN_REG + 1)
+
+/* Minimum and maximum floating point registers used to hold arguments. */
+#define FP_ARG_MIN_REG 33
+#define FP_ARG_AIX_MAX_REG 45
+#define FP_ARG_V4_MAX_REG 40
+#define FP_ARG_MAX_REG FP_ARG_AIX_MAX_REG
+#define FP_ARG_NUM_REG (FP_ARG_MAX_REG - FP_ARG_MIN_REG + 1)
+
+/* Return registers */
+#define GP_ARG_RETURN GP_ARG_MIN_REG
+#define FP_ARG_RETURN FP_ARG_MIN_REG
+
+/* Flags for the call/call_value rtl operations set up by function_arg */
+#define CALL_NORMAL 0x00000000 /* no special processing */
+#define CALL_NT_DLLIMPORT 0x00000001 /* NT, this is a DLL import call */
+#define CALL_V4_CLEAR_FP_ARGS 0x00000002 /* V.4, no FP args passed */
+#define CALL_V4_SET_FP_ARGS 0x00000004 /* V.4, FP args were passed */
+#define CALL_LONG 0x00000008 /* always call indirect */
+
+/* Define cutoff for using external functions to save floating point */
+#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) == 62 || (FIRST_REG) == 63)
+
+/* 1 if N is a possible register number for a function value
+ as seen by the caller.
+
+ On RS/6000, this is r3 and fp1. */
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_ARG_RETURN || ((N) == FP_ARG_RETURN))
+
+/* 1 if N is a possible register number for function argument passing.
+ On RS/6000, these are r3-r10 and fp1-fp13. */
+#define FUNCTION_ARG_REGNO_P(N) \
+ (((unsigned)((N) - GP_ARG_MIN_REG) < (unsigned)(GP_ARG_NUM_REG)) \
+ || ((unsigned)((N) - FP_ARG_MIN_REG) < (unsigned)(FP_ARG_NUM_REG)))
+
+
+/* Define a data type for recording info about an argument list
+ during the scan of that argument list. This data type should
+ hold all necessary information about the function itself
+ and about the args processed so far, enough to enable macros
+ such as FUNCTION_ARG to determine where the next arg should go.
+
+ On the RS/6000, this is a structure. The first element is the number of
+ total argument words, the second is used to store the next
+ floating-point register number, and the third says how many more args we
+ have prototype types for.
+
+ The System V.4 varargs/stdarg support requires that this structure's size
+ be a multiple of sizeof(int), and that WORDS, FREGNO, NARGS_PROTOTYPE,
+ ORIG_NARGS, and VARARGS_OFFSET be the first five ints. */
+
+typedef struct rs6000_args
+{
+ int words; /* # words uses for passing GP registers */
+ int fregno; /* next available FP register */
+ int nargs_prototype; /* # args left in the current prototype */
+ int orig_nargs; /* Original value of nargs_prototype */
+ int varargs_offset; /* offset of the varargs save area */
+ int prototype; /* Whether a prototype was defined */
+ int call_cookie; /* Do special things for this call */
+} CUMULATIVE_ARGS;
+
+/* Define intermediate macro to compute the size (in registers) of an argument
+ for the RS/6000. */
+
+#define RS6000_ARG_SIZE(MODE, TYPE, NAMED) \
+(! (NAMED) ? 0 \
+ : (MODE) != BLKmode \
+ ? (GET_MODE_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD \
+ : (int_size_in_bytes (TYPE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
+
+/* Initialize a variable CUM of type CUMULATIVE_ARGS
+ for a call to a function whose data type is FNTYPE.
+ For a library call, FNTYPE is 0. */
+
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
+ init_cumulative_args (&CUM, FNTYPE, LIBNAME, FALSE)
+
+/* Similar, but when scanning the definition of a procedure. We always
+ set NARGS_PROTOTYPE large so we never return an EXPR_LIST. */
+
+#define INIT_CUMULATIVE_INCOMING_ARGS(CUM,FNTYPE,LIBNAME) \
+ init_cumulative_args (&CUM, FNTYPE, LIBNAME, TRUE)
+
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ (TYPE is null for libcalls where that information may not be available.) */
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+ function_arg_advance (&CUM, MODE, TYPE, NAMED)
+
+/* Non-zero if we can use a floating-point register to pass this arg. */
+#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE) \
+ (GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ && (CUM).fregno <= FP_ARG_MAX_REG \
+ && TARGET_HARD_FLOAT)
+
+/* 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.
+
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis).
+
+ On RS/6000 the first eight words of non-FP are normally in registers
+ and the rest are pushed. The first 13 FP args are in registers.
+
+ If this is floating-point and no prototype is specified, we use
+ both an FP and integer register (or possibly FP reg and stack). Library
+ functions (when TYPE is zero) always have the proper types for args,
+ so we can pass the FP value just in one register. emit_library_function
+ doesn't support EXPR_LIST anyway. */
+
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+ function_arg (&CUM, MODE, TYPE, NAMED)
+
+/* 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, `downward' to pad below, or `none' to inhibit
+ padding. */
+
+#define FUNCTION_ARG_PADDING(MODE, TYPE) \
+ (enum direction) function_arg_padding (MODE, TYPE)
+
+/* If defined, a C expression that gives the alignment boundary, in bits,
+ of an argument with the specified mode and type. If it is not defined,
+ PARM_BOUNDARY is used for all arguments. */
+
+#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \
+ function_arg_boundary (MODE, TYPE)
+
+/* Perform any needed actions needed for a function that is receiving a
+ variable number of arguments.
+
+ CUM is as above.
+
+ MODE and TYPE are the mode and type of the current parameter.
+
+ PRETEND_SIZE is a variable that should be set to the amount of stack
+ that must be pushed by the prolog to pretend that our caller pushed
+ it.
+
+ Normally, this macro will push all remaining incoming registers on the
+ stack and set PRETEND_SIZE to the length of the registers pushed. */
+
+#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
+ setup_incoming_varargs (&CUM, MODE, TYPE, &PRETEND_SIZE, NO_RTL)
+
+/* If defined, is a C expression that produces the machine-specific
+ code for a call to `__builtin_saveregs'. This code will be moved
+ to the very beginning of the function, before any parameter access
+ are made. The return value of this function should be an RTX that
+ contains the value to use as the return of `__builtin_saveregs'.
+
+ The argument ARGS is a `tree_list' containing the arguments that
+ were passed to `__builtin_saveregs'.
+
+ If this macro is not defined, the compiler will output an ordinary
+ call to the library function `__builtin_saveregs'. */
+
+#define EXPAND_BUILTIN_SAVEREGS(ARGS) \
+ expand_builtin_saveregs (ARGS)
+
+/* This macro 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. */
+
+#define FUNCTION_PROLOGUE(FILE, SIZE) output_prolog (FILE, SIZE)
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
+
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ output_function_profiler ((FILE), (LABELNO));
+
+/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
+ the stack pointer does not matter. No definition is equivalent to
+ always zero.
+
+ On the RS/6000, this is non-zero because we can restore the stack from
+ its backpointer, which we maintain. */
+#define EXIT_IGNORE_STACK 1
+
+/* This macro generates the assembly code for function exit,
+ on machines that need it. If FUNCTION_EPILOGUE is not defined
+ then individual return instructions are generated for each
+ return statement. Args are same as for FUNCTION_PROLOGUE.
+
+ 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. */
+
+#define FUNCTION_EPILOGUE(FILE, SIZE) output_epilog (FILE, SIZE)
+
+/* A C compound statement that outputs the assembler code for a thunk function,
+ used to implement C++ virtual function calls with multiple inheritance. The
+ thunk acts as a wrapper around a virtual function, adjusting the implicit
+ object parameter before handing control off to the real function.
+
+ First, emit code to add the integer DELTA to the location that contains the
+ incoming first argument. Assume that this argument contains a pointer, and
+ is the one used to pass the `this' pointer in C++. This is the incoming
+ argument *before* the function prologue, e.g. `%o0' on a sparc. The
+ addition must preserve the values of all other incoming arguments.
+
+ After the addition, emit code to jump to FUNCTION, which is a
+ `FUNCTION_DECL'. This is a direct pure jump, not a call, and does not touch
+ the return address. Hence returning from FUNCTION will return to whoever
+ called the current `thunk'.
+
+ The effect must be as if FUNCTION had been called directly with the adjusted
+ first argument. This macro is responsible for emitting all of the code for
+ a thunk function; `FUNCTION_PROLOGUE' and `FUNCTION_EPILOGUE' are not
+ invoked.
+
+ The THUNK_FNDECL is redundant. (DELTA and FUNCTION have already been
+ extracted from it.) It might possibly be useful on some targets, but
+ probably not.
+
+ If you do not define this macro, the target-independent code in the C++
+ frontend will generate a less efficient heavyweight thunk that calls
+ FUNCTION instead of jumping to it. The generic approach does not support
+ varargs. */
+#if TARGET_ELF
+#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+ output_mi_thunk (FILE, THUNK_FNDECL, DELTA, FUNCTION)
+#endif
+
+/* TRAMPOLINE_TEMPLATE deleted */
+
+/* Length in units of the trampoline for entering a nested function. */
+
+#define TRAMPOLINE_SIZE rs6000_trampoline_size ()
+
+/* Emit RTL insns to initialize the variable parts of a trampoline.
+ FNADDR is an RTX for the address of the function's pure code.
+ CXT is an RTX for the static chain value for the function. */
+
+#define INITIALIZE_TRAMPOLINE(ADDR, FNADDR, CXT) \
+ rs6000_initialize_trampoline (ADDR, FNADDR, CXT)
+
+/* If defined, a C expression whose value is nonzero if IDENTIFIER
+ with arguments ARGS is a valid machine specific attribute for DECL.
+ The attributes in ATTRIBUTES have previously been assigned to DECL. */
+
+#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, NAME, ARGS) \
+ (rs6000_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS))
+
+/* If defined, a C expression whose value is nonzero if IDENTIFIER
+ with arguments ARGS is a valid machine specific attribute for TYPE.
+ The attributes in ATTRIBUTES have previously been assigned to TYPE. */
+
+#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, NAME, ARGS) \
+ (rs6000_valid_type_attribute_p (TYPE, ATTRIBUTES, NAME, ARGS))
+
+/* If defined, a C expression whose value is zero if the attributes on
+ TYPE1 and TYPE2 are incompatible, one if they are compatible, and
+ two if they are nearly compatible (which causes a warning to be
+ generated). */
+
+#define COMP_TYPE_ATTRIBUTES(TYPE1, TYPE2) \
+ (rs6000_comp_type_attributes (TYPE1, TYPE2))
+
+/* If defined, a C statement that assigns default attributes to newly
+ defined TYPE. */
+
+#define SET_DEFAULT_TYPE_ATTRIBUTES(TYPE) \
+ (rs6000_set_default_type_attributes (TYPE))
+
+
+/* Definitions for __builtin_return_address and __builtin_frame_address.
+ __builtin_return_address (0) should give link register (65), enable
+ this. */
+/* This should be uncommented, so that the link register is used, but
+ currently this would result in unmatched insns and spilling fixed
+ registers so we'll leave it for another day. When these problems are
+ taken care of one additional fetch will be necessary in RETURN_ADDR_RTX.
+ (mrs) */
+/* #define RETURN_ADDR_IN_PREVIOUS_FRAME */
+
+/* Number of bytes into the frame return addresses can be found. See
+ rs6000_stack_info in rs6000.c for more information on how the different
+ abi's store the return address. */
+#define RETURN_ADDRESS_OFFSET \
+ ((DEFAULT_ABI == ABI_AIX \
+ || DEFAULT_ABI == ABI_AIX_NODESC) ? 8 : \
+ (DEFAULT_ABI == ABI_V4 \
+ || DEFAULT_ABI == ABI_SOLARIS) ? (TARGET_32BIT ? 4 : 8) : \
+ (DEFAULT_ABI == ABI_NT) ? -4 : \
+ (fatal ("RETURN_ADDRESS_OFFSET not supported"), 0))
+
+/* The current return address is in link register (65). The return address
+ of anything farther back is accessed normally at an offset of 8 from the
+ frame pointer. */
+#define RETURN_ADDR_RTX(count, frame) \
+ ((count == -1) \
+ ? gen_rtx_REG (Pmode, 65) \
+ : gen_rtx_MEM (Pmode, \
+ memory_address (Pmode, \
+ plus_constant (copy_to_reg (gen_rtx_MEM (Pmode, \
+ memory_address (Pmode, frame))), \
+ RETURN_ADDRESS_OFFSET))))
+
+/* Definitions for register eliminations.
+
+ We have two registers that can be eliminated on the RS/6000. First, the
+ frame pointer register can often be eliminated in favor of the stack
+ pointer register. Secondly, the argument pointer register can always be
+ eliminated; it is replaced with either the stack or frame pointer.
+
+ In addition, we use the elimination mechanism to see if r30 is needed
+ Initially we assume that it isn't. If it is, we spill it. This is done
+ by making it an eliminable register. We replace it with itself so that
+ if it isn't needed, then existing uses won't be modified. */
+
+/* This is an array of structures. Each structure initializes one pair
+ of eliminable registers. The "from" register number is given first,
+ followed by "to". Eliminations of the same "from" register are listed
+ in order of preference. */
+#define ELIMINABLE_REGS \
+{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ { 30, 30} }
+
+/* Given FROM and TO register numbers, say whether this elimination is allowed.
+ Frame pointer elimination is automatically handled.
+
+ For the RS/6000, if frame pointer elimination is being done, we would like
+ to convert ap into fp, not sp.
+
+ We need r30 if -mminimal-toc was specified, and there are constant pool
+ references. */
+
+#define CAN_ELIMINATE(FROM, TO) \
+ ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM \
+ ? ! frame_pointer_needed \
+ : (FROM) == 30 ? ! TARGET_MINIMAL_TOC || TARGET_NO_TOC || get_pool_size () == 0 \
+ : 1)
+
+/* Define the offset between two registers, one to be eliminated, and the other
+ its replacement, at the start of a routine. */
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+{ \
+ rs6000_stack_t *info = rs6000_stack_info (); \
+ \
+ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
+ (OFFSET) = (info->push_p) ? 0 : - info->total_size; \
+ else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \
+ (OFFSET) = info->total_size; \
+ else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
+ (OFFSET) = (info->push_p) ? info->total_size : 0; \
+ else if ((FROM) == 30) \
+ (OFFSET) = 0; \
+ else \
+ abort (); \
+}
+
+/* Addressing modes, and classification of registers for them. */
+
+/* #define HAVE_POST_INCREMENT 0 */
+/* #define HAVE_POST_DECREMENT 0 */
+
+#define HAVE_PRE_DECREMENT 1
+#define HAVE_PRE_INCREMENT 1
+
+/* Macros to check register numbers against specific register classes. */
+
+/* These assume that REGNO is a hard or pseudo reg number.
+ They give nonzero only if REGNO is a hard reg of the suitable class
+ or a pseudo reg currently allocated to a suitable hard reg.
+ Since they use reg_renumber, they are safe only once reg_renumber
+ has been allocated, which happens in local-alloc.c. */
+
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+((REGNO) < FIRST_PSEUDO_REGISTER \
+ ? (REGNO) <= 31 || (REGNO) == 67 \
+ : (reg_renumber[REGNO] >= 0 \
+ && (reg_renumber[REGNO] <= 31 || reg_renumber[REGNO] == 67)))
+
+#define REGNO_OK_FOR_BASE_P(REGNO) \
+((REGNO) < FIRST_PSEUDO_REGISTER \
+ ? ((REGNO) > 0 && (REGNO) <= 31) || (REGNO) == 67 \
+ : (reg_renumber[REGNO] > 0 \
+ && (reg_renumber[REGNO] <= 31 || reg_renumber[REGNO] == 67)))
+
+/* Maximum number of registers that can appear in a valid memory address. */
+
+#define MAX_REGS_PER_ADDRESS 2
+
+/* Recognize any constant value that is a valid address. */
+
+#define CONSTANT_ADDRESS_P(X) \
+ (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
+ || GET_CODE (X) == HIGH)
+
+/* Nonzero if the constant value X is a legitimate general operand.
+ It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.
+
+ On the RS/6000, all integer constants are acceptable, most won't be valid
+ for particular insns, though. Only easy FP constants are
+ acceptable. */
+
+#define LEGITIMATE_CONSTANT_P(X) \
+ (GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode \
+ || (TARGET_POWERPC64 && GET_MODE (X) == DImode) \
+ || easy_fp_constant (X, GET_MODE (X)))
+
+/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
+ and check its validity for a certain class.
+ We have two alternate definitions for each of them.
+ The usual definition accepts all pseudo regs; the other rejects
+ them unless they have been allocated suitable hard regs.
+ The symbol REG_OK_STRICT causes the latter definition to be used.
+
+ Most source files want to accept pseudo regs in the hope that
+ they will get allocated to the class that the insn wants them to be in.
+ Source files for reload pass need to be strict.
+ After reload, it makes no difference, since pseudo regs have
+ been eliminated by then. */
+
+#ifndef REG_OK_STRICT
+
+/* Nonzero if X is a hard reg that can be used as an index
+ or if it is a pseudo reg. */
+#define REG_OK_FOR_INDEX_P(X) \
+ (REGNO (X) <= 31 || REGNO (X) == 67 || REGNO (X) >= FIRST_PSEUDO_REGISTER)
+
+/* Nonzero if X is a hard reg that can be used as a base reg
+ or if it is a pseudo reg. */
+#define REG_OK_FOR_BASE_P(X) \
+ (REGNO (X) > 0 && REG_OK_FOR_INDEX_P (X))
+
+#else
+
+/* Nonzero if X is a hard reg that can be used as an index. */
+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
+/* Nonzero if X is a hard reg that can be used as a base reg. */
+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+
+#endif
+
+/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
+ that is a valid memory address for an instruction.
+ The MODE argument is the machine mode for the MEM expression
+ that wants to use this address.
+
+ On the RS/6000, there are four valid address: a SYMBOL_REF that
+ refers to a constant pool entry of an address (or the sum of it
+ plus a constant), a short (16-bit signed) constant plus a register,
+ the sum of two registers, or a register indirect, possibly with an
+ auto-increment. For DFmode and DImode with an constant plus register,
+ we must ensure that both words are addressable or PowerPC64 with offset
+ word aligned.
+
+ For modes spanning multiple registers (DFmode in 32-bit GPRs,
+ 32-bit DImode, TImode), indexed addressing cannot be used because
+ adjacent memory cells are accessed by adding word-sized offsets
+ during assembly output. */
+
+#define LEGITIMATE_CONSTANT_POOL_BASE_P(X) \
+ (TARGET_TOC && GET_CODE (X) == SYMBOL_REF \
+ && CONSTANT_POOL_ADDRESS_P (X) \
+ && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (X)))
+
+/* AIX64 guaranteed to have 64 bit TOC alignment. */
+#define LEGITIMATE_CONSTANT_POOL_ADDRESS_P(X) \
+ (LEGITIMATE_CONSTANT_POOL_BASE_P (X) \
+ || (TARGET_TOC \
+ && GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \
+ && LEGITIMATE_CONSTANT_POOL_BASE_P (XEXP (XEXP (X, 0), 0))))
+
+#define LEGITIMATE_SMALL_DATA_P(MODE, X) \
+ ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) \
+ && !flag_pic && !TARGET_TOC \
+ && (GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == CONST) \
+ && small_data_operand (X, MODE))
+
+#define LEGITIMATE_ADDRESS_INTEGER_P(X,OFFSET) \
+ (GET_CODE (X) == CONST_INT \
+ && (unsigned HOST_WIDE_INT) (INTVAL (X) + (OFFSET) + 0x8000) < 0x10000)
+
+#define LEGITIMATE_OFFSET_ADDRESS_P(MODE,X) \
+ (GET_CODE (X) == PLUS \
+ && GET_CODE (XEXP (X, 0)) == REG \
+ && REG_OK_FOR_BASE_P (XEXP (X, 0)) \
+ && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (X, 1), 0) \
+ && (((MODE) != DFmode && (MODE) != DImode) \
+ || (TARGET_32BIT \
+ ? LEGITIMATE_ADDRESS_INTEGER_P (XEXP (X, 1), 4) \
+ : ! (INTVAL (XEXP (X, 1)) & 3))) \
+ && ((MODE) != TImode \
+ || (TARGET_32BIT \
+ ? LEGITIMATE_ADDRESS_INTEGER_P (XEXP (X, 1), 12) \
+ : (LEGITIMATE_ADDRESS_INTEGER_P (XEXP (X, 1), 8) \
+ && ! (INTVAL (XEXP (X, 1)) & 3)))))
+
+#define LEGITIMATE_INDEXED_ADDRESS_P(X) \
+ (GET_CODE (X) == PLUS \
+ && GET_CODE (XEXP (X, 0)) == REG \
+ && GET_CODE (XEXP (X, 1)) == REG \
+ && ((REG_OK_FOR_BASE_P (XEXP (X, 0)) \
+ && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \
+ || (REG_OK_FOR_BASE_P (XEXP (X, 1)) \
+ && REG_OK_FOR_INDEX_P (XEXP (X, 0)))))
+
+#define LEGITIMATE_INDIRECT_ADDRESS_P(X) \
+ (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X))
+
+#define LEGITIMATE_LO_SUM_ADDRESS_P(MODE, X) \
+ (TARGET_ELF \
+ && !flag_pic && !TARGET_TOC \
+ && (MODE) != DImode \
+ && (MODE) != TImode \
+ && (TARGET_HARD_FLOAT || (MODE) != DFmode) \
+ && GET_CODE (X) == LO_SUM \
+ && GET_CODE (XEXP (X, 0)) == REG \
+ && REG_OK_FOR_BASE_P (XEXP (X, 0)) \
+ && CONSTANT_P (XEXP (X, 1)))
+
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+{ if (LEGITIMATE_INDIRECT_ADDRESS_P (X)) \
+ goto ADDR; \
+ if ((GET_CODE (X) == PRE_INC || GET_CODE (X) == PRE_DEC) \
+ && TARGET_UPDATE \
+ && LEGITIMATE_INDIRECT_ADDRESS_P (XEXP (X, 0))) \
+ goto ADDR; \
+ if (LEGITIMATE_SMALL_DATA_P (MODE, X)) \
+ goto ADDR; \
+ if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (X)) \
+ goto ADDR; \
+ if (LEGITIMATE_OFFSET_ADDRESS_P (MODE, X)) \
+ goto ADDR; \
+ if ((MODE) != TImode \
+ && (TARGET_HARD_FLOAT || TARGET_POWERPC64 || (MODE) != DFmode) \
+ && (TARGET_POWERPC64 || (MODE) != DImode) \
+ && LEGITIMATE_INDEXED_ADDRESS_P (X)) \
+ goto ADDR; \
+ if (LEGITIMATE_LO_SUM_ADDRESS_P (MODE, X)) \
+ goto ADDR; \
+}
+
+/* Try machine-dependent ways of modifying an illegitimate address
+ to be legitimate. If we find one, return the new, valid address.
+ This macro is used in only one place: `memory_address' in explow.c.
+
+ OLDX is the address as it was before break_out_memory_refs was called.
+ In some cases it is useful to look at this to decide what needs to be done.
+
+ MODE and WIN are passed so that this macro can use
+ GO_IF_LEGITIMATE_ADDRESS.
+
+ It is always safe for this macro to do nothing. It exists to recognize
+ opportunities to optimize the output.
+
+ On RS/6000, first check for the sum of a register with a constant
+ integer that is out of range. If so, generate code to add the
+ constant with the low-order 16 bits masked to the register and force
+ this result into another register (this can be done with `cau').
+ Then generate an address of REG+(CONST&0xffff), allowing for the
+ possibility of bit 16 being a one.
+
+ Then check for the sum of a register and something not constant, try to
+ load the other things into a register and return the sum. */
+
+#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
+{ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (X, 1)) + 0x8000) >= 0x10000) \
+ { HOST_WIDE_INT high_int, low_int; \
+ rtx sum; \
+ high_int = INTVAL (XEXP (X, 1)) & (~ (HOST_WIDE_INT) 0xffff); \
+ low_int = INTVAL (XEXP (X, 1)) & 0xffff; \
+ if (low_int & 0x8000) \
+ high_int += 0x10000, low_int |= ((HOST_WIDE_INT) -1) << 16; \
+ sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (X, 0), \
+ GEN_INT (high_int)), 0); \
+ (X) = gen_rtx_PLUS (Pmode, sum, GEN_INT (low_int)); \
+ goto WIN; \
+ } \
+ else if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \
+ && GET_CODE (XEXP (X, 1)) != CONST_INT \
+ && (TARGET_HARD_FLOAT || TARGET_POWERPC64 || (MODE) != DFmode) \
+ && (TARGET_POWERPC64 || (MODE) != DImode) \
+ && (MODE) != TImode) \
+ { \
+ (X) = gen_rtx_PLUS (Pmode, XEXP (X, 0), \
+ force_reg (Pmode, force_operand (XEXP (X, 1), 0))); \
+ goto WIN; \
+ } \
+ else if (TARGET_ELF && TARGET_32BIT && TARGET_NO_TOC \
+ && !flag_pic \
+ && GET_CODE (X) != CONST_INT \
+ && GET_CODE (X) != CONST_DOUBLE && CONSTANT_P (X) \
+ && (TARGET_HARD_FLOAT || (MODE) != DFmode) \
+ && (MODE) != DImode && (MODE) != TImode) \
+ { \
+ rtx reg = gen_reg_rtx (Pmode); \
+ emit_insn (gen_elf_high (reg, (X))); \
+ (X) = gen_rtx_LO_SUM (Pmode, reg, (X)); \
+ goto WIN; \
+ } \
+}
+
+/* Try a machine-dependent way of reloading an illegitimate address
+ operand. If we find one, push the reload and jump to WIN. This
+ macro is used in only one place: `find_reloads_address' in reload.c.
+
+ For RS/6000, we wish to handle large displacements off a base
+ register by splitting the addend across an addiu/addis and the mem insn.
+ This cuts number of extra insns needed from 3 to 1. */
+
+#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \
+do { \
+ /* We must recognize output that we have already generated ourselves. */ \
+ if (GET_CODE (X) == PLUS \
+ && GET_CODE (XEXP (X, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \
+ && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ { \
+ push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
+ BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \
+ OPNUM, TYPE); \
+ goto WIN; \
+ } \
+ if (GET_CODE (X) == PLUS \
+ && GET_CODE (XEXP (X, 0)) == REG \
+ && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \
+ && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ { \
+ HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \
+ HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000; \
+ HOST_WIDE_INT high \
+ = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000; \
+ \
+ /* Check for 32-bit overflow. */ \
+ if (high + low != val) \
+ break; \
+ \
+ /* Reload the high part into a base reg; leave the low part \
+ in the mem directly. */ \
+ \
+ X = gen_rtx_PLUS (GET_MODE (X), \
+ gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \
+ GEN_INT (high)), \
+ GEN_INT (low)); \
+ \
+ push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
+ BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \
+ OPNUM, TYPE); \
+ goto WIN; \
+ } \
+} while (0)
+
+/* Go to LABEL if ADDR (a legitimate address expression)
+ has an effect that depends on the machine mode it is used for.
+
+ On the RS/6000 this is true if the address is valid with a zero offset
+ but not with an offset of four (this means it cannot be used as an
+ address for DImode or DFmode) or is a pre-increment or decrement. Since
+ we know it is valid, we just check for an address that is not valid with
+ an offset of four. */
+
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \
+{ if (GET_CODE (ADDR) == PLUS \
+ && LEGITIMATE_ADDRESS_INTEGER_P (XEXP (ADDR, 1), 0) \
+ && ! LEGITIMATE_ADDRESS_INTEGER_P (XEXP (ADDR, 1), \
+ (TARGET_32BIT ? 4 : 8))) \
+ goto LABEL; \
+ if (TARGET_UPDATE && GET_CODE (ADDR) == PRE_INC) \
+ goto LABEL; \
+ if (TARGET_UPDATE && GET_CODE (ADDR) == PRE_DEC) \
+ goto LABEL; \
+ if (GET_CODE (ADDR) == LO_SUM) \
+ goto LABEL; \
+}
+
+/* The register number of the register used to address a table of
+ static data addresses in memory. In some cases this register is
+ defined by a processor's "application binary interface" (ABI).
+ When this macro is defined, RTL is generated for this register
+ once, as with the stack pointer and frame pointer registers. If
+ this macro is not defined, it is up to the machine-dependent files
+ to allocate such a register (if necessary). */
+
+/* #define PIC_OFFSET_TABLE_REGNUM */
+
+/* Define this macro if the register defined by
+ `PIC_OFFSET_TABLE_REGNUM' is clobbered by calls. Do not define
+ this macro if `PPIC_OFFSET_TABLE_REGNUM' is not defined. */
+
+/* #define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED */
+
+/* By generating position-independent code, when two different
+ programs (A and B) share a common library (libC.a), the text of
+ the library can be shared whether or not the library is linked at
+ the same address for both programs. In some of these
+ environments, position-independent code requires not only the use
+ of different addressing modes, but also special code to enable the
+ use of these addressing modes.
+
+ The `FINALIZE_PIC' macro serves as a hook to emit these special
+ codes once the function is being compiled into assembly code, but
+ not before. (It is not done before, because in the case of
+ compiling an inline function, it would lead to multiple PIC
+ prologues being included in functions which used inline functions
+ and were compiled to assembly language.) */
+
+#define FINALIZE_PIC rs6000_finalize_pic ()
+
+/* A C expression that is nonzero if X is a legitimate immediate
+ operand on the target machine when generating position independent
+ code. You can assume that X satisfies `CONSTANT_P', so you need
+ not check this. You can also assume FLAG_PIC is true, so you need
+ not check it either. You need not define this macro if all
+ constants (including `SYMBOL_REF') can be immediate operands when
+ generating position independent code. */
+
+/* #define LEGITIMATE_PIC_OPERAND_P (X) */
+
+/* In rare cases, correct code generation requires extra machine
+ dependent processing between the second jump optimization pass and
+ delayed branch scheduling. On those machines, define this macro
+ as a C statement to act on the code starting at INSN.
+
+ On the RS/6000, we use it to make sure the GOT_TOC register marker
+ that FINALIZE_PIC is supposed to remove actually got removed. */
+
+#define MACHINE_DEPENDENT_REORG(INSN) rs6000_reorg (INSN)
+
+
+/* Define this if some processing needs to be done immediately before
+ emitting code for an insn. */
+
+/* #define FINAL_PRESCAN_INSN(INSN,OPERANDS,NOPERANDS) */
+
+/* Specify the machine mode that this machine uses
+ for the index in the tablejump instruction. */
+#define CASE_VECTOR_MODE (TARGET_32BIT ? SImode : DImode)
+
+/* 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
+
+/* Specify the tree operation to be used to convert reals to integers. */
+#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
+
+/* This is the kind of divide that is easiest to do in the general case. */
+#define EASY_DIV_EXPR TRUNC_DIV_EXPR
+
+/* Define this as 1 if `char' should by default be signed; else as 0. */
+#define DEFAULT_SIGNED_CHAR 0
+
+/* This flag, if defined, says the same insns that convert to a signed fixnum
+ also convert validly to an unsigned one. */
+
+/* #define FIXUNS_TRUNC_LIKE_FIX_TRUNC */
+
+/* Max number of bytes we can move from memory to memory
+ in one reasonably fast instruction. */
+#define MOVE_MAX (! TARGET_POWERPC64 ? 4 : 8)
+#define MAX_MOVE_MAX 8
+
+/* Nonzero if access to memory by bytes is no faster than for words.
+ Also non-zero if doing byte operations (specifically shifts) in registers
+ is undesirable. */
+#define SLOW_BYTE_ACCESS 1
+
+/* Define if operations between registers always perform the operation
+ on the full register even if a narrower mode is specified. */
+#define WORD_REGISTER_OPERATIONS
+
+/* 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. */
+#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND
+
+/* Define if loading short immediate values into registers sign extends. */
+#define SHORT_IMMEDIATES_SIGN_EXTEND
+
+/* The RS/6000 uses the XCOFF format. */
+
+#define XCOFF_DEBUGGING_INFO
+
+/* Define if the object format being used is COFF or a superset. */
+#define OBJECT_FORMAT_COFF
+
+/* Define the magic numbers that we recognize as COFF.
+ AIX 4.3 adds U803XTOCMAGIC (0757) for 64-bit objects, but collect2.c
+ does not include files in the correct order to conditionally define
+ the symbolic name in this macro. */
+#define MY_ISCOFF(magic) \
+ ((magic) == U802WRMAGIC || (magic) == U802ROMAGIC \
+ || (magic) == U802TOCMAGIC || (magic) == 0757)
+
+/* This is the only version of nm that collect2 can work with. */
+#define REAL_NM_FILE_NAME "/usr/ucb/nm"
+
+/* We don't have GAS for the RS/6000 yet, so don't write out special
+ .stabs in cc1plus. */
+
+#define FASCIST_ASSEMBLER
+
+/* AIX does not have any init/fini or ctor/dtor sections, so create
+ static constructors and destructors as normal functions. */
+/* #define ASM_OUTPUT_CONSTRUCTOR(file, name) */
+/* #define ASM_OUTPUT_DESTRUCTOR(file, name) */
+
+/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
+ is done just by pretending it is already truncated. */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* Specify the machine mode that pointers have.
+ After generation of rtl, the compiler makes no further distinction
+ between pointers and any other objects of this machine mode. */
+#define Pmode (TARGET_32BIT ? SImode : DImode)
+
+/* Mode of a function address in a call instruction (for indexing purposes).
+ Doesn't matter on RS/6000. */
+#define FUNCTION_MODE (TARGET_32BIT ? SImode : DImode)
+
+/* Define this if addresses of constant functions
+ shouldn't be put through pseudo regs where they can be cse'd.
+ Desirable on machines where ordinary constants are expensive
+ but a CALL with constant address is cheap. */
+#define NO_FUNCTION_CSE
+
+/* Define this to be nonzero if shift instructions ignore all but the low-order
+ few bits.
+
+ The sle and sre instructions which allow SHIFT_COUNT_TRUNCATED
+ have been dropped from the PowerPC architecture. */
+
+#define SHIFT_COUNT_TRUNCATED (TARGET_POWER ? 1 : 0)
+
+/* Use atexit for static constructors/destructors, instead of defining
+ our own exit function. */
+#define HAVE_ATEXIT
+
+/* Compute the cost of computing a constant rtl expression RTX
+ whose rtx-code is CODE. The body of this macro is a portion
+ of a switch statement. If the code is computed here,
+ return it with a return statement. Otherwise, break from the switch.
+
+ On the RS/6000, if it is valid in the insn, it is free. So this
+ always returns 0. */
+
+#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
+ case CONST_INT: \
+ case CONST: \
+ case LABEL_REF: \
+ case SYMBOL_REF: \
+ case CONST_DOUBLE: \
+ case HIGH: \
+ return 0;
+
+/* Provide the costs of a rtl expression. This is in the body of a
+ switch on CODE. */
+
+#define RTX_COSTS(X,CODE,OUTER_CODE) \
+ case PLUS: \
+ return ((GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (X, 1)) \
+ + 0x8000) >= 0x10000) \
+ && ((INTVAL (XEXP (X, 1)) & 0xffff) != 0)) \
+ ? COSTS_N_INSNS (2) \
+ : COSTS_N_INSNS (1)); \
+ case AND: \
+ case IOR: \
+ case XOR: \
+ return ((GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && (INTVAL (XEXP (X, 1)) & (~ (HOST_WIDE_INT) 0xffff)) != 0 \
+ && ((INTVAL (XEXP (X, 1)) & 0xffff) != 0)) \
+ ? COSTS_N_INSNS (2) \
+ : COSTS_N_INSNS (1)); \
+ case MULT: \
+ switch (rs6000_cpu) \
+ { \
+ case PROCESSOR_RIOS1: \
+ return (GET_CODE (XEXP (X, 1)) != CONST_INT \
+ ? COSTS_N_INSNS (5) \
+ : INTVAL (XEXP (X, 1)) >= -256 && INTVAL (XEXP (X, 1)) <= 255 \
+ ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4)); \
+ case PROCESSOR_RIOS2: \
+ case PROCESSOR_MPCCORE: \
+ case PROCESSOR_PPC604e: \
+ return COSTS_N_INSNS (2); \
+ case PROCESSOR_PPC601: \
+ return COSTS_N_INSNS (5); \
+ case PROCESSOR_PPC603: \
+ case PROCESSOR_PPC750: \
+ return (GET_CODE (XEXP (X, 1)) != CONST_INT \
+ ? COSTS_N_INSNS (5) \
+ : INTVAL (XEXP (X, 1)) >= -256 && INTVAL (XEXP (X, 1)) <= 255 \
+ ? COSTS_N_INSNS (2) : COSTS_N_INSNS (3)); \
+ case PROCESSOR_PPC403: \
+ case PROCESSOR_PPC604: \
+ case PROCESSOR_PPC620: \
+ return COSTS_N_INSNS (4); \
+ } \
+ case DIV: \
+ case MOD: \
+ if (GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && exact_log2 (INTVAL (XEXP (X, 1))) >= 0) \
+ return COSTS_N_INSNS (2); \
+ /* otherwise fall through to normal divide. */ \
+ case UDIV: \
+ case UMOD: \
+ switch (rs6000_cpu) \
+ { \
+ case PROCESSOR_RIOS1: \
+ return COSTS_N_INSNS (19); \
+ case PROCESSOR_RIOS2: \
+ return COSTS_N_INSNS (13); \
+ case PROCESSOR_MPCCORE: \
+ return COSTS_N_INSNS (6); \
+ case PROCESSOR_PPC403: \
+ return COSTS_N_INSNS (33); \
+ case PROCESSOR_PPC601: \
+ return COSTS_N_INSNS (36); \
+ case PROCESSOR_PPC603: \
+ return COSTS_N_INSNS (37); \
+ case PROCESSOR_PPC604: \
+ case PROCESSOR_PPC604e: \
+ case PROCESSOR_PPC620: \
+ return COSTS_N_INSNS (20); \
+ case PROCESSOR_PPC750: \
+ return COSTS_N_INSNS (19); \
+ } \
+ case FFS: \
+ return COSTS_N_INSNS (4); \
+ case MEM: \
+ /* MEM should be slightly more expensive than (plus (reg) (const)) */ \
+ return 5;
+
+/* Compute the cost of an address. This is meant to approximate the size
+ and/or execution delay of an insn using that address. If the cost is
+ approximated by the RTL complexity, including CONST_COSTS above, as
+ is usually the case for CISC machines, this macro should not be defined.
+ For aggressively RISCy machines, only one insn format is allowed, so
+ this macro should be a constant. The value of this macro only matters
+ for valid addresses.
+
+ For the RS/6000, everything is cost 0. */
+
+#define ADDRESS_COST(RTX) 0
+
+/* Adjust the length of an INSN. LENGTH is the currently-computed length and
+ should be adjusted to reflect any required changes. This macro is used when
+ there is some systematic length adjustment required that would be difficult
+ to express in the length attribute. */
+
+/* #define ADJUST_INSN_LENGTH(X,LENGTH) */
+
+/* Add any extra modes needed to represent the condition code.
+
+ For the RS/6000, we need separate modes when unsigned (logical) comparisons
+ are being done and we need a separate mode for floating-point. We also
+ use a mode for the case when we are comparing the results of two
+ comparisons. */
+
+#define EXTRA_CC_MODES CCUNSmode, CCFPmode, CCEQmode
+
+/* Define the names for the modes specified above. */
+#define EXTRA_CC_NAMES "CCUNS", "CCFP", "CCEQ"
+
+/* 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, CCFPmode
+ should be used. CCUNSmode should be used for unsigned comparisons.
+ CCEQmode should be used when we are doing an inequality comparison on
+ the result of a comparison. CCmode should be used in all other cases. */
+
+#define SELECT_CC_MODE(OP,X,Y) \
+ (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? CCFPmode \
+ : (OP) == GTU || (OP) == LTU || (OP) == GEU || (OP) == LEU ? CCUNSmode \
+ : (((OP) == EQ || (OP) == NE) && GET_RTX_CLASS (GET_CODE (X)) == '<' \
+ ? CCEQmode : CCmode))
+
+/* Define the information needed to generate branch and scc insns. This is
+ stored from the compare operation. Note that we can't use "rtx" here
+ since it hasn't been defined! */
+
+extern struct rtx_def *rs6000_compare_op0, *rs6000_compare_op1;
+extern int rs6000_compare_fp_p;
+
+/* Set to non-zero by "fix" operation to indicate that itrunc and
+ uitrunc must be defined. */
+
+extern int rs6000_trunc_used;
+
+/* Function names to call to do floating point truncation. */
+
+#define RS6000_ITRUNC "__itrunc"
+#define RS6000_UITRUNC "__uitrunc"
+
+/* Prefix and suffix to use to saving floating point */
+#ifndef SAVE_FP_PREFIX
+#define SAVE_FP_PREFIX "._savef"
+#define SAVE_FP_SUFFIX ""
+#endif
+
+/* Prefix and suffix to use to restoring floating point */
+#ifndef RESTORE_FP_PREFIX
+#define RESTORE_FP_PREFIX "._restf"
+#define RESTORE_FP_SUFFIX ""
+#endif
+
+/* Function name to call to do profiling. */
+#define RS6000_MCOUNT ".__mcount"
+
+
+/* Control the assembler format that we output. */
+
+/* A C string constant describing how to begin a comment in the target
+ assembler language. The compiler assumes that the comment will end at
+ the end of the line. */
+#define ASM_COMMENT_START " #"
+
+/* Output at beginning of assembler file.
+
+ Initialize the section names for the RS/6000 at this point.
+
+ Specify filename to assembler.
+
+ We want to go into the TOC section so at least one .toc will be emitted.
+ Also, in order to output proper .bs/.es pairs, we need at least one static
+ [RW] section emitted.
+
+ We then switch back to text to force the gcc2_compiled. label and the space
+ allocated after it (when profiling) into the text section.
+
+ Finally, declare mcount when profiling to make the assembler happy. */
+
+#define ASM_FILE_START(FILE) \
+{ \
+ rs6000_gen_section_name (&xcoff_bss_section_name, \
+ main_input_filename, ".bss_"); \
+ rs6000_gen_section_name (&xcoff_private_data_section_name, \
+ main_input_filename, ".rw_"); \
+ rs6000_gen_section_name (&xcoff_read_only_section_name, \
+ main_input_filename, ".ro_"); \
+ \
+ output_file_directive (FILE, main_input_filename); \
+ if (TARGET_64BIT) \
+ fputs ("\t.machine\t\"ppc64\"\n", FILE); \
+ toc_section (); \
+ if (write_symbols != NO_DEBUG) \
+ private_data_section (); \
+ text_section (); \
+ if (profile_flag) \
+ fprintf (FILE, "\t.extern %s\n", RS6000_MCOUNT); \
+ rs6000_file_start (FILE, TARGET_CPU_DEFAULT); \
+}
+
+/* Output at end of assembler file.
+
+ On the RS/6000, referencing data should automatically pull in text. */
+
+#define ASM_FILE_END(FILE) \
+{ \
+ text_section (); \
+ fputs ("_section_.text:\n", FILE); \
+ data_section (); \
+ fputs ("\t.long _section_.text\n", FILE); \
+}
+
+/* We define this to prevent the name mangler from putting dollar signs into
+ function names. */
+
+#define NO_DOLLAR_IN_LABEL
+
+/* We define this to 0 so that gcc will never accept a dollar sign in a
+ variable name. This is needed because the AIX assembler will not accept
+ dollar signs. */
+
+#define DOLLARS_IN_IDENTIFIERS 0
+
+/* Implicit library calls should use memcpy, not bcopy, etc. */
+
+#define TARGET_MEM_FUNCTIONS
+
+/* Define the extra sections we need. We define three: one is the read-only
+ data section which is used for constants. This is a csect whose name is
+ derived from the name of the input file. The second is for initialized
+ global variables. This is a csect whose name is that of the variable.
+ The third is the TOC. */
+
+#define EXTRA_SECTIONS \
+ read_only_data, private_data, read_only_private_data, toc, bss
+
+/* Define the name of our readonly data section. */
+
+#define READONLY_DATA_SECTION read_only_data_section
+
+
+/* Define the name of the section to use for the exception tables.
+ TODO: test and see if we can use read_only_data_section, if so,
+ remove this. */
+
+#define EXCEPTION_SECTION data_section
+
+/* If we are referencing a function that is static or is known to be
+ in this file, make the SYMBOL_REF special. We can use this to indicate
+ that we can branch to this function without emitting a no-op after the
+ call. */
+
+#define ENCODE_SECTION_INFO(DECL) \
+ if (TREE_CODE (DECL) == FUNCTION_DECL \
+ && (TREE_ASM_WRITTEN (DECL) || ! TREE_PUBLIC (DECL))) \
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1;
+
+/* Indicate that jump tables go in the text section. */
+
+#define JUMP_TABLES_IN_TEXT_SECTION 1
+
+/* Define the routines to implement these extra sections. */
+
+#define EXTRA_SECTION_FUNCTIONS \
+ \
+void \
+read_only_data_section () \
+{ \
+ if (in_section != read_only_data) \
+ { \
+ fprintf (asm_out_file, ".csect %s[RO]\n", \
+ xcoff_read_only_section_name); \
+ in_section = read_only_data; \
+ } \
+} \
+ \
+void \
+private_data_section () \
+{ \
+ if (in_section != private_data) \
+ { \
+ fprintf (asm_out_file, ".csect %s[RW]\n", \
+ xcoff_private_data_section_name); \
+ \
+ in_section = private_data; \
+ } \
+} \
+ \
+void \
+read_only_private_data_section () \
+{ \
+ if (in_section != read_only_private_data) \
+ { \
+ fprintf (asm_out_file, ".csect %s[RO]\n", \
+ xcoff_private_data_section_name); \
+ in_section = read_only_private_data; \
+ } \
+} \
+ \
+void \
+toc_section () \
+{ \
+ if (TARGET_MINIMAL_TOC) \
+ { \
+ /* toc_section is always called at least once from ASM_FILE_START, \
+ so this is guaranteed to always be defined once and only once \
+ in each file. */ \
+ if (! toc_initialized) \
+ { \
+ fputs (".toc\nLCTOC..0:\n", asm_out_file); \
+ fputs ("\t.tc toc_table[TC],toc_table[RW]\n", asm_out_file); \
+ toc_initialized = 1; \
+ } \
+ \
+ if (in_section != toc) \
+ fputs (".csect toc_table[RW]\n", asm_out_file); \
+ } \
+ else \
+ { \
+ if (in_section != toc) \
+ fputs (".toc\n", asm_out_file); \
+ } \
+ in_section = toc; \
+}
+
+/* Flag to say the TOC is initialized */
+extern int toc_initialized;
+
+/* This macro produces the initial definition of a function name.
+ On the RS/6000, we need to place an extra '.' in the function name and
+ output the function descriptor.
+
+ The csect for the function will have already been created by the
+ `text_section' call previously done. We do have to go back to that
+ csect, however. */
+
+/* ??? What do the 16 and 044 in the .function line really mean? */
+
+#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \
+{ if (TREE_PUBLIC (DECL)) \
+ { \
+ fputs ("\t.globl .", FILE); \
+ RS6000_OUTPUT_BASENAME (FILE, NAME); \
+ putc ('\n', FILE); \
+ } \
+ else \
+ { \
+ fputs ("\t.lglobl .", FILE); \
+ RS6000_OUTPUT_BASENAME (FILE, NAME); \
+ putc ('\n', FILE); \
+ } \
+ fputs (".csect ", FILE); \
+ RS6000_OUTPUT_BASENAME (FILE, NAME); \
+ fputs (TARGET_32BIT ? "[DS]\n" : "[DS],3\n", FILE); \
+ RS6000_OUTPUT_BASENAME (FILE, NAME); \
+ fputs (":\n", FILE); \
+ fputs (TARGET_32BIT ? "\t.long ." : "\t.llong .", FILE); \
+ RS6000_OUTPUT_BASENAME (FILE, NAME); \
+ fputs (", TOC[tc0], 0\n", FILE); \
+ fputs (".csect .text[PR]\n.", FILE); \
+ RS6000_OUTPUT_BASENAME (FILE, NAME); \
+ fputs (":\n", FILE); \
+ if (write_symbols == XCOFF_DEBUG) \
+ xcoffout_declare_function (FILE, DECL, NAME); \
+}
+
+/* Return non-zero if this entry is to be written into the constant pool
+ in a special way. We do so if this is a SYMBOL_REF, LABEL_REF or a CONST
+ containing one of them. If -mfp-in-toc (the default), we also do
+ this for floating-point constants. We actually can only do this
+ if the FP formats of the target and host machines are the same, but
+ we can't check that since not every file that uses
+ GO_IF_LEGITIMATE_ADDRESS_P includes real.h. */
+
+#define ASM_OUTPUT_SPECIAL_POOL_ENTRY_P(X) \
+ (TARGET_TOC \
+ && (GET_CODE (X) == SYMBOL_REF \
+ || (GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF) \
+ || GET_CODE (X) == LABEL_REF \
+ || (! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC) \
+ && GET_CODE (X) == CONST_DOUBLE \
+ && (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
+ || (TARGET_POWERPC64 && GET_MODE (X) == DImode)))))
+#if 0
+ && BITS_PER_WORD == HOST_BITS_PER_INT)))
+#endif
+
+/* Select section for constant in constant pool.
+
+ On RS/6000, all constants are in the private read-only data area.
+ However, if this is being placed in the TOC it must be output as a
+ toc entry. */
+
+#define SELECT_RTX_SECTION(MODE, X) \
+{ if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (X)) \
+ toc_section (); \
+ else \
+ read_only_private_data_section (); \
+}
+
+/* Macro to output a special constant pool entry. Go to WIN if we output
+ it. Otherwise, it is written the usual way.
+
+ On the RS/6000, toc entries are handled this way. */
+
+#define ASM_OUTPUT_SPECIAL_POOL_ENTRY(FILE, X, MODE, ALIGN, LABELNO, WIN) \
+{ if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (X)) \
+ { \
+ output_toc (FILE, X, LABELNO); \
+ goto WIN; \
+ } \
+}
+
+/* Select the section for an initialized data object.
+
+ On the RS/6000, we have a special section for all variables except those
+ that are static. */
+
+#define SELECT_SECTION(EXP,RELOC) \
+{ \
+ if ((TREE_CODE (EXP) == STRING_CST \
+ && !flag_writable_strings) \
+ || (TREE_CODE_CLASS (TREE_CODE (EXP)) == 'd' \
+ && TREE_READONLY (EXP) && ! TREE_THIS_VOLATILE (EXP) \
+ && DECL_INITIAL (EXP) \
+ && (DECL_INITIAL (EXP) == error_mark_node \
+ || TREE_CONSTANT (DECL_INITIAL (EXP))) \
+ && ! (RELOC))) \
+ { \
+ if (TREE_PUBLIC (EXP)) \
+ read_only_data_section (); \
+ else \
+ read_only_private_data_section (); \
+ } \
+ else \
+ { \
+ if (TREE_PUBLIC (EXP)) \
+ data_section (); \
+ else \
+ private_data_section (); \
+ } \
+}
+
+/* This outputs NAME to FILE up to the first null or '['. */
+
+#define RS6000_OUTPUT_BASENAME(FILE, NAME) \
+ { \
+ char *_p; \
+ \
+ STRIP_NAME_ENCODING (_p, (NAME)); \
+ assemble_name ((FILE), _p); \
+ }
+
+/* Remove any trailing [DS] or the like from the symbol name. */
+
+#define STRIP_NAME_ENCODING(VAR,NAME) \
+ do \
+ { \
+ char *_name = (NAME); \
+ int _len; \
+ if (_name[0] == '*') \
+ _name++; \
+ _len = strlen (_name); \
+ if (_name[_len - 1] != ']') \
+ (VAR) = _name; \
+ else \
+ { \
+ (VAR) = (char *) alloca (_len + 1); \
+ strcpy ((VAR), _name); \
+ (VAR)[_len - 4] = '\0'; \
+ } \
+ } \
+ while (0)
+
+/* Output something to declare an external symbol to the assembler. Most
+ assemblers don't need this.
+
+ If we haven't already, add "[RW]" (or "[DS]" for a function) to the
+ name. Normally we write this out along with the name. In the few cases
+ where we can't, it gets stripped off. */
+
+#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
+{ rtx _symref = XEXP (DECL_RTL (DECL), 0); \
+ if ((TREE_CODE (DECL) == VAR_DECL \
+ || TREE_CODE (DECL) == FUNCTION_DECL) \
+ && (NAME)[strlen (NAME) - 1] != ']') \
+ { \
+ char *_name = (char *) permalloc (strlen (XSTR (_symref, 0)) + 5); \
+ strcpy (_name, XSTR (_symref, 0)); \
+ strcat (_name, TREE_CODE (DECL) == FUNCTION_DECL ? "[DS]" : "[RW]"); \
+ XSTR (_symref, 0) = _name; \
+ } \
+ fputs ("\t.extern ", FILE); \
+ assemble_name (FILE, XSTR (_symref, 0)); \
+ if (TREE_CODE (DECL) == FUNCTION_DECL) \
+ { \
+ fputs ("\n\t.extern .", FILE); \
+ RS6000_OUTPUT_BASENAME (FILE, XSTR (_symref, 0)); \
+ } \
+ putc ('\n', FILE); \
+}
+
+/* Similar, but for libcall. We only have to worry about the function name,
+ not that of the descriptor. */
+
+#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \
+{ fputs ("\t.extern .", FILE); \
+ assemble_name (FILE, XSTR (FUN, 0)); \
+ putc ('\n', FILE); \
+}
+
+/* Output to assembler file text saying following lines
+ may contain character constants, extra white space, comments, etc. */
+
+#define ASM_APP_ON ""
+
+/* Output to assembler file text saying following lines
+ no longer contain unusual constructs. */
+
+#define ASM_APP_OFF ""
+
+/* Output before instructions. */
+
+#define TEXT_SECTION_ASM_OP ".csect .text[PR]"
+
+/* Output before writable data. */
+
+#define DATA_SECTION_ASM_OP ".csect .data[RW]"
+
+/* How to refer to registers in assembler output.
+ This sequence is indexed by compiler's hard-register-number (see above). */
+
+extern char rs6000_reg_names[][8]; /* register names (0 vs. %r0). */
+
+#define REGISTER_NAMES \
+{ \
+ &rs6000_reg_names[ 0][0], /* r0 */ \
+ &rs6000_reg_names[ 1][0], /* r1 */ \
+ &rs6000_reg_names[ 2][0], /* r2 */ \
+ &rs6000_reg_names[ 3][0], /* r3 */ \
+ &rs6000_reg_names[ 4][0], /* r4 */ \
+ &rs6000_reg_names[ 5][0], /* r5 */ \
+ &rs6000_reg_names[ 6][0], /* r6 */ \
+ &rs6000_reg_names[ 7][0], /* r7 */ \
+ &rs6000_reg_names[ 8][0], /* r8 */ \
+ &rs6000_reg_names[ 9][0], /* r9 */ \
+ &rs6000_reg_names[10][0], /* r10 */ \
+ &rs6000_reg_names[11][0], /* r11 */ \
+ &rs6000_reg_names[12][0], /* r12 */ \
+ &rs6000_reg_names[13][0], /* r13 */ \
+ &rs6000_reg_names[14][0], /* r14 */ \
+ &rs6000_reg_names[15][0], /* r15 */ \
+ &rs6000_reg_names[16][0], /* r16 */ \
+ &rs6000_reg_names[17][0], /* r17 */ \
+ &rs6000_reg_names[18][0], /* r18 */ \
+ &rs6000_reg_names[19][0], /* r19 */ \
+ &rs6000_reg_names[20][0], /* r20 */ \
+ &rs6000_reg_names[21][0], /* r21 */ \
+ &rs6000_reg_names[22][0], /* r22 */ \
+ &rs6000_reg_names[23][0], /* r23 */ \
+ &rs6000_reg_names[24][0], /* r24 */ \
+ &rs6000_reg_names[25][0], /* r25 */ \
+ &rs6000_reg_names[26][0], /* r26 */ \
+ &rs6000_reg_names[27][0], /* r27 */ \
+ &rs6000_reg_names[28][0], /* r28 */ \
+ &rs6000_reg_names[29][0], /* r29 */ \
+ &rs6000_reg_names[30][0], /* r30 */ \
+ &rs6000_reg_names[31][0], /* r31 */ \
+ \
+ &rs6000_reg_names[32][0], /* fr0 */ \
+ &rs6000_reg_names[33][0], /* fr1 */ \
+ &rs6000_reg_names[34][0], /* fr2 */ \
+ &rs6000_reg_names[35][0], /* fr3 */ \
+ &rs6000_reg_names[36][0], /* fr4 */ \
+ &rs6000_reg_names[37][0], /* fr5 */ \
+ &rs6000_reg_names[38][0], /* fr6 */ \
+ &rs6000_reg_names[39][0], /* fr7 */ \
+ &rs6000_reg_names[40][0], /* fr8 */ \
+ &rs6000_reg_names[41][0], /* fr9 */ \
+ &rs6000_reg_names[42][0], /* fr10 */ \
+ &rs6000_reg_names[43][0], /* fr11 */ \
+ &rs6000_reg_names[44][0], /* fr12 */ \
+ &rs6000_reg_names[45][0], /* fr13 */ \
+ &rs6000_reg_names[46][0], /* fr14 */ \
+ &rs6000_reg_names[47][0], /* fr15 */ \
+ &rs6000_reg_names[48][0], /* fr16 */ \
+ &rs6000_reg_names[49][0], /* fr17 */ \
+ &rs6000_reg_names[50][0], /* fr18 */ \
+ &rs6000_reg_names[51][0], /* fr19 */ \
+ &rs6000_reg_names[52][0], /* fr20 */ \
+ &rs6000_reg_names[53][0], /* fr21 */ \
+ &rs6000_reg_names[54][0], /* fr22 */ \
+ &rs6000_reg_names[55][0], /* fr23 */ \
+ &rs6000_reg_names[56][0], /* fr24 */ \
+ &rs6000_reg_names[57][0], /* fr25 */ \
+ &rs6000_reg_names[58][0], /* fr26 */ \
+ &rs6000_reg_names[59][0], /* fr27 */ \
+ &rs6000_reg_names[60][0], /* fr28 */ \
+ &rs6000_reg_names[61][0], /* fr29 */ \
+ &rs6000_reg_names[62][0], /* fr30 */ \
+ &rs6000_reg_names[63][0], /* fr31 */ \
+ \
+ &rs6000_reg_names[64][0], /* mq */ \
+ &rs6000_reg_names[65][0], /* lr */ \
+ &rs6000_reg_names[66][0], /* ctr */ \
+ &rs6000_reg_names[67][0], /* ap */ \
+ \
+ &rs6000_reg_names[68][0], /* cr0 */ \
+ &rs6000_reg_names[69][0], /* cr1 */ \
+ &rs6000_reg_names[70][0], /* cr2 */ \
+ &rs6000_reg_names[71][0], /* cr3 */ \
+ &rs6000_reg_names[72][0], /* cr4 */ \
+ &rs6000_reg_names[73][0], /* cr5 */ \
+ &rs6000_reg_names[74][0], /* cr6 */ \
+ &rs6000_reg_names[75][0], /* cr7 */ \
+ \
+ &rs6000_reg_names[76][0], /* fpmem */ \
+}
+
+/* print-rtl can't handle the above REGISTER_NAMES, so define the
+ following for it. Switch to use the alternate names since
+ they are more mnemonic. */
+
+#define DEBUG_REGISTER_NAMES \
+{ \
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", \
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
+ "mq", "lr", "ctr", "ap", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "fpmem" \
+}
+
+/* Table of additional register names to use in user input. */
+
+#define ADDITIONAL_REGISTER_NAMES \
+ {{"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3}, \
+ {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7}, \
+ {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11}, \
+ {"r12", 12}, {"r13", 13}, {"r14", 14}, {"r15", 15}, \
+ {"r16", 16}, {"r17", 17}, {"r18", 18}, {"r19", 19}, \
+ {"r20", 20}, {"r21", 21}, {"r22", 22}, {"r23", 23}, \
+ {"r24", 24}, {"r25", 25}, {"r26", 26}, {"r27", 27}, \
+ {"r28", 28}, {"r29", 29}, {"r30", 30}, {"r31", 31}, \
+ {"fr0", 32}, {"fr1", 33}, {"fr2", 34}, {"fr3", 35}, \
+ {"fr4", 36}, {"fr5", 37}, {"fr6", 38}, {"fr7", 39}, \
+ {"fr8", 40}, {"fr9", 41}, {"fr10", 42}, {"fr11", 43}, \
+ {"fr12", 44}, {"fr13", 45}, {"fr14", 46}, {"fr15", 47}, \
+ {"fr16", 48}, {"fr17", 49}, {"fr18", 50}, {"fr19", 51}, \
+ {"fr20", 52}, {"fr21", 53}, {"fr22", 54}, {"fr23", 55}, \
+ {"fr24", 56}, {"fr25", 57}, {"fr26", 58}, {"fr27", 59}, \
+ {"fr28", 60}, {"fr29", 61}, {"fr30", 62}, {"fr31", 63}, \
+ /* no additional names for: mq, lr, ctr, ap */ \
+ {"cr0", 68}, {"cr1", 69}, {"cr2", 70}, {"cr3", 71}, \
+ {"cr4", 72}, {"cr5", 73}, {"cr6", 74}, {"cr7", 75}, \
+ {"cc", 68}, {"sp", 1}, {"toc", 2} }
+
+/* How to renumber registers for dbx and gdb. */
+
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+/* Text to write out after a CALL that may be replaced by glue code by
+ the loader. This depends on the AIX version. */
+#define RS6000_CALL_GLUE "cror 31,31,31"
+
+/* This is how to output the definition of a user-level label named NAME,
+ such as the label on a static function or variable NAME. */
+
+#define ASM_OUTPUT_LABEL(FILE,NAME) \
+ do { RS6000_OUTPUT_BASENAME (FILE, NAME); fputs (":\n", FILE); } while (0)
+
+/* This is how to output a command to make the user-level label named NAME
+ defined for reference from other files. */
+
+#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
+ do { fputs ("\t.globl ", FILE); \
+ RS6000_OUTPUT_BASENAME (FILE, NAME); fputs ("\n", FILE);} while (0)
+
+/* This is how to output a reference to a user-level label named NAME.
+ `assemble_name' uses this. */
+
+#define ASM_OUTPUT_LABELREF(FILE,NAME) \
+ fputs (NAME, FILE)
+
+/* This is how to output an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
+ fprintf (FILE, "%s..%d:\n", PREFIX, NUM)
+
+/* This is how to output an internal label prefix. rs6000.c uses this
+ when generating traceback tables. */
+
+#define ASM_OUTPUT_INTERNAL_LABEL_PREFIX(FILE,PREFIX) \
+ fprintf (FILE, "%s..", PREFIX)
+
+/* This is how to output a label for a jump table. Arguments are the same as
+ for ASM_OUTPUT_INTERNAL_LABEL, except the insn for the jump table is
+ passed. */
+
+#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLEINSN) \
+{ ASM_OUTPUT_ALIGN (FILE, 2); ASM_OUTPUT_INTERNAL_LABEL (FILE, 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.
+ This is suitable for output with `assemble_name'. */
+
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf (LABEL, "*%s..%d", PREFIX, NUM)
+
+/* This is how to output an assembler line defining a `double' constant. */
+
+#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \
+ { \
+ if (REAL_VALUE_ISINF (VALUE) \
+ || REAL_VALUE_ISNAN (VALUE) \
+ || REAL_VALUE_MINUS_ZERO (VALUE)) \
+ { \
+ long t[2]; \
+ REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \
+ fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n", \
+ t[0] & 0xffffffff, t[1] & 0xffffffff); \
+ } \
+ else \
+ { \
+ char str[30]; \
+ REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", str); \
+ fprintf (FILE, "\t.double 0d%s\n", str); \
+ } \
+ }
+
+/* This is how to output an assembler line defining a `float' constant. */
+
+#define ASM_OUTPUT_FLOAT(FILE, VALUE) \
+ { \
+ if (REAL_VALUE_ISINF (VALUE) \
+ || REAL_VALUE_ISNAN (VALUE) \
+ || REAL_VALUE_MINUS_ZERO (VALUE)) \
+ { \
+ long t; \
+ REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
+ fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
+ } \
+ else \
+ { \
+ char str[30]; \
+ REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
+ fprintf (FILE, "\t.float 0d%s\n", str); \
+ } \
+ }
+
+/* This is how to output an assembler line defining an `int' constant. */
+
+#define ASM_OUTPUT_DOUBLE_INT(FILE,VALUE) \
+do { \
+ if (TARGET_32BIT) \
+ { \
+ assemble_integer (operand_subword ((VALUE), 0, 0, DImode), \
+ UNITS_PER_WORD, 1); \
+ assemble_integer (operand_subword ((VALUE), 1, 0, DImode), \
+ UNITS_PER_WORD, 1); \
+ } \
+ else \
+ { \
+ fputs ("\t.llong ", FILE); \
+ output_addr_const (FILE, (VALUE)); \
+ putc ('\n', FILE); \
+ } \
+} while (0)
+
+#define ASM_OUTPUT_INT(FILE,VALUE) \
+( fputs ("\t.long ", FILE), \
+ output_addr_const (FILE, (VALUE)), \
+ putc ('\n', FILE))
+
+/* Likewise for `char' and `short' constants. */
+
+#define ASM_OUTPUT_SHORT(FILE,VALUE) \
+( fputs ("\t.short ", FILE), \
+ output_addr_const (FILE, (VALUE)), \
+ putc ('\n', FILE))
+
+#define ASM_OUTPUT_CHAR(FILE,VALUE) \
+( fputs ("\t.byte ", FILE), \
+ output_addr_const (FILE, (VALUE)), \
+ putc ('\n', FILE))
+
+/* This is how to output an assembler line for a numeric constant byte. */
+
+#define ASM_OUTPUT_BYTE(FILE,VALUE) \
+ fprintf (FILE, "\t.byte 0x%x\n", (VALUE))
+
+/* This is how to output an assembler line to define N characters starting
+ at P to FILE. */
+
+#define ASM_OUTPUT_ASCII(FILE, P, N) output_ascii ((FILE), (P), (N))
+
+/* This is how to output code to push a register on the stack.
+ It need not be very fast code.
+
+ On the rs6000, we must keep the backchain up to date. In order
+ to simplify things, always allocate 16 bytes for a push (System V
+ wants to keep stack aligned to a 16 byte boundary). */
+
+#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
+do { \
+ extern char *reg_names[]; \
+ asm_fprintf (FILE, "\t{stu|stwu} %s,-16(%s)\n\t{st|stw} %s,8(%s)\n", \
+ reg_names[1], reg_names[1], reg_names[REGNO], \
+ reg_names[1]); \
+} while (0)
+
+/* This is how to output an insn to pop a register from the stack.
+ It need not be very fast code. */
+
+#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
+do { \
+ extern char *reg_names[]; \
+ asm_fprintf (FILE, "\t{l|lwz} %s,8(%s)\n\t{ai|addic} %s,%s,16\n", \
+ reg_names[REGNO], reg_names[1], reg_names[1], \
+ reg_names[1]); \
+} while (0)
+
+/* This is how to output an element of a case-vector that is absolute.
+ (RS/6000 does not use such vectors, but we must define this macro
+ anyway.) */
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+ do { char buf[100]; \
+ fputs (TARGET_32BIT ? "\t.long " : "\t.llong ", FILE); \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "L", VALUE); \
+ assemble_name (FILE, buf); \
+ putc ('\n', FILE); \
+ } while (0)
+
+/* This is how to output an element of a case-vector that is relative. */
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL)\
+ do { char buf[100]; \
+ fputs (TARGET_32BIT ? "\t.long " : "\t.llong ", FILE); \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "L", VALUE); \
+ assemble_name (FILE, buf); \
+ putc ('-', FILE); \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "L", REL); \
+ assemble_name (FILE, buf); \
+ putc ('\n', FILE); \
+ } while (0)
+
+/* This is how to output an assembler line
+ that says to advance the location counter
+ to a multiple of 2**LOG bytes. */
+
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG) != 0) \
+ fprintf (FILE, "\t.align %d\n", (LOG))
+
+#define ASM_OUTPUT_SKIP(FILE,SIZE) \
+ fprintf (FILE, "\t.space %d\n", (SIZE))
+
+/* This says how to output an assembler line
+ to define a global common symbol. */
+
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGNMENT) \
+ do { fputs (".comm ", (FILE)); \
+ RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \
+ if ( (SIZE) > 4) \
+ fprintf ((FILE), ",%d,3\n", (SIZE)); \
+ else \
+ fprintf( (FILE), ",%d\n", (SIZE)); \
+ } while (0)
+
+/* This says how to output an assembler line
+ to define a local common symbol. */
+
+#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE,ROUNDED) \
+ do { fputs (".lcomm ", (FILE)); \
+ RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \
+ fprintf ((FILE), ",%d,%s\n", (SIZE), xcoff_bss_section_name); \
+ } while (0)
+
+/* Store in OUTPUT a string (made with alloca) containing
+ an assembler-name for a local static variable named NAME.
+ LABELNO is an integer which is different for each call. */
+
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
+( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
+ sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
+
+/* Define the parentheses used to group arithmetic operations
+ in assembler code. */
+
+#define ASM_OPEN_PAREN "("
+#define ASM_CLOSE_PAREN ")"
+
+/* Define results of standard character escape sequences. */
+#define TARGET_BELL 007
+#define TARGET_BS 010
+#define TARGET_TAB 011
+#define TARGET_NEWLINE 012
+#define TARGET_VT 013
+#define TARGET_FF 014
+#define TARGET_CR 015
+
+/* 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.
+ For `%' followed by punctuation, CODE is the punctuation and X is null. */
+
+#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
+
+/* Define which CODE values are valid. */
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
+ ((CODE) == '.' || (CODE) == '*' || (CODE) == '$')
+
+/* Print a memory address as an operand to reference that memory location. */
+
+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR)
+
+/* Define the codes that are matched by predicates in rs6000.c. */
+
+#define PREDICATE_CODES \
+ {"short_cint_operand", {CONST_INT, CONSTANT_P_RTX}}, \
+ {"u_short_cint_operand", {CONST_INT, CONSTANT_P_RTX}}, \
+ {"non_short_cint_operand", {CONST_INT}}, \
+ {"gpc_reg_operand", {SUBREG, REG}}, \
+ {"cc_reg_operand", {SUBREG, REG}}, \
+ {"cc_reg_not_cr0_operand", {SUBREG, REG}}, \
+ {"reg_or_short_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"reg_or_neg_short_operand", {SUBREG, REG, CONST_INT}}, \
+ {"reg_or_u_short_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"reg_or_cint_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \
+ {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}}, \
+ {"easy_fp_constant", {CONST_DOUBLE}}, \
+ {"reg_or_mem_operand", {SUBREG, MEM, REG}}, \
+ {"lwa_operand", {SUBREG, MEM, REG}}, \
+ {"volatile_mem_operand", {MEM}}, \
+ {"offsettable_addr_operand", {REG, SUBREG, PLUS}}, \
+ {"mem_or_easy_const_operand", {SUBREG, MEM, CONST_DOUBLE}}, \
+ {"add_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"non_add_cint_operand", {CONST_INT}}, \
+ {"and_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"and64_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX, \
+ CONST_DOUBLE}}, \
+ {"logical_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"non_logical_cint_operand", {CONST_INT}}, \
+ {"mask_operand", {CONST_INT}}, \
+ {"mask64_operand", {CONST_INT, CONST_DOUBLE}}, \
+ {"count_register_operand", {REG}}, \
+ {"fpmem_operand", {REG}}, \
+ {"call_operand", {SYMBOL_REF, REG}}, \
+ {"current_file_function_operand", {SYMBOL_REF}}, \
+ {"input_operand", {SUBREG, MEM, REG, CONST_INT, CONSTANT_P_RTX, \
+ CONST_DOUBLE, SYMBOL_REF}}, \
+ {"load_multiple_operation", {PARALLEL}}, \
+ {"store_multiple_operation", {PARALLEL}}, \
+ {"branch_comparison_operator", {EQ, NE, LE, LT, GE, \
+ GT, LEU, LTU, GEU, GTU}}, \
+ {"scc_comparison_operator", {EQ, NE, LE, LT, GE, \
+ GT, LEU, LTU, GEU, GTU}}, \
+ {"trap_comparison_operator", {EQ, NE, LE, LT, GE, \
+ GT, LEU, LTU, GEU, GTU}},
+
+/* uncomment for disabling the corresponding default options */
+/* #define MACHINE_no_sched_interblock */
+/* #define MACHINE_no_sched_speculative */
+/* #define MACHINE_no_sched_speculative_load */
+
+/* indicate that issue rate is defined for this machine
+ (no need to use the default) */
+#define ISSUE_RATE get_issue_rate ()
+
+/* General flags. */
+extern int flag_pic;
+extern int optimize;
+extern int flag_expensive_optimizations;
+extern int frame_pointer_needed;
+
+/* Declare functions in rs6000.c */
+extern void output_options ();
+extern void rs6000_override_options ();
+extern void rs6000_file_start ();
+extern struct rtx_def *rs6000_float_const ();
+extern struct rtx_def *rs6000_got_register ();
+extern int direct_return ();
+extern int get_issue_rate ();
+extern int any_operand ();
+extern int short_cint_operand ();
+extern int u_short_cint_operand ();
+extern int non_short_cint_operand ();
+extern int gpc_reg_operand ();
+extern int cc_reg_operand ();
+extern int cc_reg_not_cr0_operand ();
+extern int reg_or_short_operand ();
+extern int reg_or_neg_short_operand ();
+extern int reg_or_u_short_operand ();
+extern int reg_or_cint_operand ();
+extern int got_operand ();
+extern int got_no_const_operand ();
+extern int num_insns_constant ();
+extern int easy_fp_constant ();
+extern int volatile_mem_operand ();
+extern int offsettable_addr_operand ();
+extern int mem_or_easy_const_operand ();
+extern int add_operand ();
+extern int non_add_cint_operand ();
+extern int non_logical_cint_operand ();
+extern int logical_operand ();
+extern int mask_constant ();
+extern int mask_operand ();
+extern int mask64_operand ();
+extern int and64_operand ();
+extern int and_operand ();
+extern int count_register_operand ();
+extern int fpmem_operand ();
+extern int reg_or_mem_operand ();
+extern int lwa_operand ();
+extern int call_operand ();
+extern int current_file_function_operand ();
+extern int input_operand ();
+extern int small_data_operand ();
+extern void init_cumulative_args ();
+extern void function_arg_advance ();
+extern int function_arg_boundary ();
+extern struct rtx_def *function_arg ();
+extern int function_arg_partial_nregs ();
+extern int function_arg_pass_by_reference ();
+extern void setup_incoming_varargs ();
+extern struct rtx_def *expand_builtin_saveregs ();
+extern struct rtx_def *rs6000_stack_temp ();
+extern int expand_block_move ();
+extern int load_multiple_operation ();
+extern int store_multiple_operation ();
+extern int branch_comparison_operator ();
+extern int scc_comparison_operator ();
+extern int trap_comparison_operator ();
+extern int includes_lshift_p ();
+extern int includes_rshift_p ();
+extern int registers_ok_for_quad_peep ();
+extern int addrs_ok_for_quad_peep ();
+extern enum reg_class secondary_reload_class ();
+extern int ccr_bit ();
+extern void rs6000_finalize_pic ();
+extern void rs6000_reorg ();
+extern void rs6000_save_machine_status ();
+extern void rs6000_restore_machine_status ();
+extern void rs6000_init_expanders ();
+extern void print_operand ();
+extern void print_operand_address ();
+extern int first_reg_to_save ();
+extern int first_fp_reg_to_save ();
+extern int rs6000_makes_calls ();
+extern rs6000_stack_t *rs6000_stack_info ();
+extern void output_prolog ();
+extern void output_epilog ();
+extern void output_mi_thunk ();
+extern void output_toc ();
+extern void output_ascii ();
+extern void rs6000_gen_section_name ();
+extern void output_function_profiler ();
+extern int rs6000_adjust_cost ();
+extern int rs6000_adjust_priority ();
+extern void rs6000_trampoline_template ();
+extern int rs6000_trampoline_size ();
+extern void rs6000_initialize_trampoline ();
+extern void rs6000_output_load_toc_table ();
+extern int rs6000_comp_type_attributes ();
+extern int rs6000_valid_decl_attribute_p ();
+extern int rs6000_valid_type_attribute_p ();
+extern void rs6000_set_default_type_attributes ();
+extern struct rtx_def *rs6000_dll_import_ref ();
+extern struct rtx_def *rs6000_longcall_ref ();
+extern int function_arg_padding ();
+extern void toc_section ();
+extern void private_data_section ();
+extern void rs6000_fatal_bad_address ();
+/* CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling. */
+extern void rs6000_expand_prologue ();
+extern void rs6000_expand_epilogue ();
+/* END CYGNUS LOCAL */
+
+/* See nonlocal_goto_receiver for when this must be set. */
+
+#define DONT_ACCESS_GBLS_AFTER_EPILOGUE (TARGET_TOC && TARGET_MINIMAL_TOC)
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
new file mode 100755
index 0000000..9891796
--- /dev/null
+++ b/gcc/config/rs6000/rs6000.md
@@ -0,0 +1,13242 @@
+;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler
+;; Copyright (C) 1990, 91-98, 1999 Free Software Foundation, Inc.
+;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+
+;; This file is part of GNU CC.
+
+;; GNU CC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU CC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU CC; see the file COPYING. If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+;; Define an insn type attribute. This is used in function unit delay
+;; computations.
+(define_attr "type" "integer,load,store,fpload,fpstore,imul,idiv,branch,compare,delayed_compare,fpcompare,mtjmpr,fp,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg"
+ (const_string "integer"))
+
+;; Length (in bytes).
+(define_attr "length" ""
+ (if_then_else (eq_attr "type" "branch")
+ (if_then_else (and (ge (minus (pc) (match_dup 0))
+ (const_int -32768))
+ (lt (minus (pc) (match_dup 0))
+ (const_int 32767)))
+ (const_int 8)
+ (const_int 12))
+ (const_int 4)))
+
+;; Processor type -- this attribute must exactly match the processor_type
+;; enumeration in rs6000.h.
+
+(define_attr "cpu" "rios1,rios2,mpccore,ppc403,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc750"
+ (const (symbol_ref "rs6000_cpu_attr")))
+
+; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
+; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST])
+
+; Load/Store Unit -- pure PowerPC only
+; (POWER and 601 use Integer Unit)
+(define_function_unit "lsu" 1 0
+ (and (eq_attr "type" "load")
+ (eq_attr "cpu" "mpccore,ppc603,ppc604,ppc604e,ppc620,ppc750"))
+ 2 1)
+
+(define_function_unit "lsu" 1 0
+ (and (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "mpccore,ppc603,ppc604,ppc604e,ppc620,ppc750"))
+ 1 1)
+
+(define_function_unit "lsu" 1 0
+ (and (eq_attr "type" "fpload")
+ (eq_attr "cpu" "mpccore,ppc603,ppc750"))
+ 2 1)
+
+(define_function_unit "lsu" 1 0
+ (and (eq_attr "type" "fpload")
+ (eq_attr "cpu" "ppc604,ppc604e,ppc620"))
+ 3 1)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "load")
+ (eq_attr "cpu" "rios1,ppc403,ppc601"))
+ 2 1)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "rios1,ppc403,ppc601"))
+ 1 1)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "fpstore")
+ (eq_attr "cpu" "rios1,ppc601"))
+ 0 1)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "fpload")
+ (eq_attr "cpu" "rios1"))
+ 2 1)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "fpload")
+ (eq_attr "cpu" "ppc601"))
+ 3 1)
+
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "load,fpload")
+ (eq_attr "cpu" "rios2"))
+ 2 1)
+
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "rios2"))
+ 1 1)
+
+; Integer Unit (RIOS1, PPC601, PPC603)
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "integer")
+ (eq_attr "cpu" "rios1,mpccore,ppc403,ppc601,ppc603"))
+ 1 1)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "imul")
+ (eq_attr "cpu" "ppc403"))
+ 4 4)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "imul")
+ (eq_attr "cpu" "rios1,ppc601,ppc603"))
+ 5 5)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "rios1"))
+ 19 19)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "ppc403"))
+ 33 33)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "ppc601"))
+ 36 36)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "ppc603"))
+ 37 36)
+
+; RIOS2 has two integer units: a primary one which can perform all
+; operations and a secondary one which is fed in lock step with the first
+; and can perform "simple" integer operations.
+; To catch this we define a 'dummy' imuldiv-unit that is also needed
+; for the complex insns.
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "integer")
+ (eq_attr "cpu" "rios2"))
+ 1 1)
+
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "imul")
+ (eq_attr "cpu" "rios2"))
+ 2 2)
+
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "rios2"))
+ 13 13)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "imul")
+ (eq_attr "cpu" "rios2"))
+ 2 2)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "rios2"))
+ 13 13)
+
+; MPCCORE has separate IMUL/IDIV unit for multicycle instructions
+; Divide latency varies greatly from 2-11, use 6 as average
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "imul")
+ (eq_attr "cpu" "mpccore"))
+ 2 1)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "mpccore"))
+ 6 6)
+
+; PPC604{,e} has two units that perform integer operations
+; and one unit for divide/multiply operations (and move
+; from/to spr).
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "integer")
+ (eq_attr "cpu" "ppc604,ppc604e,ppc620"))
+ 1 1)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "imul")
+ (eq_attr "cpu" "ppc604,ppc620"))
+ 4 2)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "imul")
+ (eq_attr "cpu" "ppc604e"))
+ 2 1)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "ppc604,ppc604e,ppc620"))
+ 20 19)
+
+; PPC750 has two integer units: a primary one which can perform all
+; operations and a secondary one which is fed in lock step with the first
+; and can perform "simple" integer operations.
+; To catch this we define a 'dummy' imuldiv-unit that is also needed
+; for the complex insns.
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "integer")
+ (eq_attr "cpu" "ppc750"))
+ 1 1)
+
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "imul")
+ (eq_attr "cpu" "ppc750"))
+ 4 2)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "imul")
+ (eq_attr "cpu" "ppc750"))
+ 4 2)
+
+(define_function_unit "imuldiv" 1 0
+ (and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "ppc750"))
+ 19 19)
+
+; compare is done on integer unit, but feeds insns which
+; execute on the branch unit.
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "compare")
+ (eq_attr "cpu" "rios1"))
+ 4 1)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "delayed_compare")
+ (eq_attr "cpu" "rios1"))
+ 5 1)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "compare,delayed_compare")
+ (eq_attr "cpu" "mpccore,ppc403,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc750"))
+ 3 1)
+
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "compare,delayed_compare")
+ (eq_attr "cpu" "rios2"))
+ 3 1)
+
+(define_function_unit "iu2" 2 0
+ (and (eq_attr "type" "compare,delayed_compare")
+ (eq_attr "cpu" "ppc604,ppc604e,ppc620,ppc750"))
+ 1 1)
+
+; fp compare uses fp unit
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "fpcompare")
+ (eq_attr "cpu" "rios1"))
+ 9 1)
+
+; rios1 and rios2 have different fpcompare delays
+(define_function_unit "fpu2" 2 0
+ (and (eq_attr "type" "fpcompare")
+ (eq_attr "cpu" "rios2"))
+ 5 1)
+
+; on ppc601 and ppc603, fpcompare takes also 2 cycles from
+; the integer unit
+; here we do not define delays, just occupy the unit. The dependencies
+; will be assigned by the fpcompare definition in the fpu.
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "fpcompare")
+ (eq_attr "cpu" "ppc601,ppc603"))
+ 0 2)
+
+; fp compare uses fp unit
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "fpcompare")
+ (eq_attr "cpu" "ppc601,ppc603,ppc604,ppc604e,ppc620,ppc750"))
+ 5 1)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "fpcompare")
+ (eq_attr "cpu" "mpccore"))
+ 1 1)
+
+(define_function_unit "bpu" 1 0
+ (and (eq_attr "type" "mtjmpr")
+ (eq_attr "cpu" "rios1,rios2"))
+ 5 1)
+
+(define_function_unit "bpu" 1 0
+ (and (eq_attr "type" "mtjmpr")
+ (eq_attr "cpu" "mpccore,ppc403,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc750"))
+ 4 1)
+
+; all jumps/branches are executing on the bpu, in 1 cycle, for all machines.
+(define_function_unit "bpu" 1 0
+ (eq_attr "type" "jmpreg")
+ 1 1)
+
+(define_function_unit "bpu" 1 0
+ (eq_attr "type" "branch")
+ 1 1)
+
+; Floating Point Unit
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "fp,dmul")
+ (eq_attr "cpu" "rios1"))
+ 2 1)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "fp")
+ (eq_attr "cpu" "mpccore"))
+ 4 4)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "fp")
+ (eq_attr "cpu" "ppc601"))
+ 4 1)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "fp")
+ (eq_attr "cpu" "ppc603,ppc604,ppc604e,ppc620,ppc750"))
+ 3 1)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "dmul")
+ (eq_attr "cpu" "mpccore"))
+ 5 5)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "dmul")
+ (eq_attr "cpu" "ppc601"))
+ 5 2)
+
+; is this true?
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "dmul")
+ (eq_attr "cpu" "ppc603,ppc750"))
+ 4 2)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "dmul")
+ (eq_attr "cpu" "ppc604,ppc604e,ppc620"))
+ 3 1)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "sdiv,ddiv")
+ (eq_attr "cpu" "rios1"))
+ 19 19)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "sdiv")
+ (eq_attr "cpu" "ppc601"))
+ 17 17)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "sdiv")
+ (eq_attr "cpu" "mpccore"))
+ 10 10)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "sdiv")
+ (eq_attr "cpu" "ppc603,ppc604,ppc604e,ppc620"))
+ 18 18)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "ddiv")
+ (eq_attr "cpu" "mpccore"))
+ 17 17)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "ddiv")
+ (eq_attr "cpu" "ppc601,ppc604,ppc604e,ppc620,ppc750"))
+ 31 31)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "ddiv")
+ (eq_attr "cpu" "ppc603"))
+ 33 33)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "ssqrt")
+ (eq_attr "cpu" "ppc620"))
+ 31 31)
+
+(define_function_unit "fpu" 1 0
+ (and (eq_attr "type" "dsqrt")
+ (eq_attr "cpu" "ppc620"))
+ 31 31)
+
+; RIOS2 has two symmetric FPUs.
+(define_function_unit "fpu2" 2 0
+ (and (eq_attr "type" "fp")
+ (eq_attr "cpu" "rios2"))
+ 2 1)
+
+(define_function_unit "fpu2" 2 0
+ (and (eq_attr "type" "dmul")
+ (eq_attr "cpu" "rios2"))
+ 2 1)
+
+(define_function_unit "fpu2" 2 0
+ (and (eq_attr "type" "sdiv,ddiv")
+ (eq_attr "cpu" "rios2"))
+ 17 17)
+
+(define_function_unit "fpu2" 2 0
+ (and (eq_attr "type" "ssqrt,dsqrt")
+ (eq_attr "cpu" "rios2"))
+ 26 26)
+
+
+;; Start with fixed-point load and store insns. Here we put only the more
+;; complex forms. Basic data transfer is done later.
+
+(define_expand "zero_extendqidi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (zero_extend:DI (match_operand:QI 1 "gpc_reg_operand" "")))]
+ "TARGET_POWERPC64"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:DI (match_operand:QI 1 "reg_or_mem_operand" "m,r")))]
+ "TARGET_POWERPC64"
+ "@
+ lbz%U1%X1 %0,%1
+ rldicl %0,%1,0,56"
+ [(set_attr "type" "load,*")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ rldicl. %2,%1,0,56
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 "=r"))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2)
+ (zero_extend:DI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64"
+ "@
+ rldicl. %0,%1,0,56
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (zero_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:DI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "extendqidi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC64"
+ "extsb %0,%1")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ extsb. %2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2)
+ (sign_extend:DI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (sign_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64"
+ "@
+ extsb. %0,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (sign_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (sign_extend:DI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "zero_extendhidi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (zero_extend:DI (match_operand:HI 1 "gpc_reg_operand" "")))]
+ "TARGET_POWERPC64"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:DI (match_operand:HI 1 "reg_or_mem_operand" "m,r")))]
+ "TARGET_POWERPC64"
+ "@
+ lhz%U1%X1 %0,%1
+ rldicl %0,%1,0,48"
+ [(set_attr "type" "load,*")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ rldicl. %2,%1,0,48
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI (match_operand:HI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2)
+ (zero_extend:DI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64"
+ "@
+ rldicl. %0,%1,0,48
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI (match_operand:HI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (zero_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:DI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "extendhidi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "")))]
+ "TARGET_POWERPC64"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (sign_extend:DI (match_operand:HI 1 "reg_or_mem_operand" "m,r")))]
+ "TARGET_POWERPC64"
+ "@
+ lha%U1%X1 %0,%1
+ extsh %0,%1"
+ [(set_attr "type" "load,*")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ extsh. %2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2)
+ (sign_extend:DI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (sign_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64"
+ "@
+ extsh. %0,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (sign_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (sign_extend:DI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "zero_extendsidi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "")))]
+ "TARGET_POWERPC64"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:DI (match_operand:SI 1 "reg_or_mem_operand" "m,r")))]
+ "TARGET_POWERPC64"
+ "@
+ lwz%U1%X1 %0,%1
+ rldicl %0,%1,0,32"
+ [(set_attr "type" "load,*")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ rldicl. %2,%1,0,32
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2)
+ (zero_extend:DI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64"
+ "@
+ rldicl. %0,%1,0,32
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (zero_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:DI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "extendsidi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "")))]
+ "TARGET_POWERPC64"
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (sign_extend:DI (match_operand:SI 1 "lwa_operand" "m,r")))]
+ "TARGET_POWERPC64"
+ "@
+ lwa%U1%X1 %0,%1
+ extsw %0,%1"
+ [(set_attr "type" "load,*")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ extsw. %2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2)
+ (sign_extend:DI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (sign_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64"
+ "@
+ extsw. %0,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (sign_extend:DI (match_dup 1)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (sign_extend:DI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "zero_extendqisi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (match_operand:QI 1 "reg_or_mem_operand" "m,r")))]
+ ""
+ "@
+ lbz%U1%X1 %0,%1
+ {rlinm|rlwinm} %0,%1,0,0xff"
+ [(set_attr "type" "load,*")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 "=r,r"))]
+ ""
+ "@
+ {andil.|andi.} %2,%1,0xff
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 ""))]
+ "reload_completed"
+ [(set (match_dup 2)
+ (zero_extend:SI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (match_dup 1)))]
+ ""
+ "@
+ {andil.|andi.} %0,%1,0xff
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (zero_extend:SI (match_dup 1)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:SI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "extendqisi2"
+ [(use (match_operand:SI 0 "gpc_reg_operand" ""))
+ (use (match_operand:QI 1 "gpc_reg_operand" ""))]
+ ""
+ "
+{
+ if (TARGET_POWERPC)
+ emit_insn (gen_extendqisi2_ppc (operands[0], operands[1]));
+ else if (TARGET_POWER)
+ emit_insn (gen_extendqisi2_power (operands[0], operands[1]));
+ else
+ emit_insn (gen_extendqisi2_no_power (operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn "extendqisi2_ppc"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC"
+ "extsb %0,%1")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 "=r,r"))]
+ "TARGET_POWERPC"
+ "@
+ extsb. %2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 ""))]
+ "TARGET_POWERPC && reload_completed"
+ [(set (match_dup 2)
+ (sign_extend:SI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (sign_extend:SI (match_dup 1)))]
+ "TARGET_POWERPC"
+ "@
+ extsb. %0,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (sign_extend:SI (match_dup 1)))]
+ "TARGET_POWERPC && reload_completed"
+ [(set (match_dup 0)
+ (sign_extend:SI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "extendqisi2_power"
+ [(parallel [(set (match_dup 2)
+ (ashift:SI (match_operand:QI 1 "gpc_reg_operand" "")
+ (const_int 24)))
+ (clobber (scratch:SI))])
+ (parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ashiftrt:SI (match_dup 2)
+ (const_int 24)))
+ (clobber (scratch:SI))])]
+ "TARGET_POWER"
+ "
+{ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode); }")
+
+(define_expand "extendqisi2_no_power"
+ [(set (match_dup 2)
+ (ashift:SI (match_operand:QI 1 "gpc_reg_operand" "")
+ (const_int 24)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ashiftrt:SI (match_dup 2)
+ (const_int 24)))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "
+{ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode); }")
+
+(define_expand "zero_extendqihi2"
+ [(set (match_operand:HI 0 "gpc_reg_operand" "")
+ (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:HI (match_operand:QI 1 "reg_or_mem_operand" "m,r")))]
+ ""
+ "@
+ lbz%U1%X1 %0,%1
+ {rlinm|rlwinm} %0,%1,0,0xff"
+ [(set_attr "type" "load,*")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:HI 2 "=r,r"))]
+ ""
+ "@
+ {andil.|andi.} %2,%1,0xff
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:HI (match_operand:HI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 ""))]
+ "reload_completed"
+ [(set (match_dup 2)
+ (zero_extend:SI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "
+{
+ rtx reg;
+ int offset;
+ if (GET_CODE (operands[2]) == REG)
+ {
+ reg = operands[2];
+ offset = 0;
+ }
+ else if (GET_CODE (operands[2]) == SUBREG)
+ {
+ reg = SUBREG_REG (operands[2]);
+ offset = SUBREG_WORD (operands[2]);
+ }
+ else
+ abort ();
+
+ operands[3] = gen_rtx_SUBREG (SImode, reg, offset);
+}")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:HI (match_dup 1)))]
+ ""
+ "@
+ {andil.|andi.} %0,%1,0xff
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:HI 0 "gpc_reg_operand" "")
+ (zero_extend:HI (match_dup 1)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:HI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "
+{
+ rtx reg;
+ int offset;
+ if (GET_CODE (operands[0]) == REG)
+ {
+ reg = operands[2];
+ offset = 0;
+ }
+ else if (GET_CODE (operands[2]) == SUBREG)
+ {
+ reg = SUBREG_REG (operands[2]);
+ offset = SUBREG_WORD (operands[2]);
+ }
+ else
+ abort ();
+
+ operands[3] = gen_rtx_SUBREG (SImode, reg, offset);
+}")
+
+(define_expand "extendqihi2"
+ [(use (match_operand:HI 0 "gpc_reg_operand" ""))
+ (use (match_operand:QI 1 "gpc_reg_operand" ""))]
+ ""
+ "
+{
+ if (TARGET_POWERPC)
+ emit_insn (gen_extendqihi2_ppc (operands[0], operands[1]));
+ else if (TARGET_POWER)
+ emit_insn (gen_extendqihi2_power (operands[0], operands[1]));
+ else
+ emit_insn (gen_extendqihi2_no_power (operands[0], operands[1]));
+ DONE;
+}")
+
+(define_insn "extendqihi2_ppc"
+ [(set (match_operand:HI 0 "gpc_reg_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC"
+ "extsb %0,%1")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:HI 2 "=r,r"))]
+ "TARGET_POWERPC"
+ "@
+ extsb. %2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:HI 2 ""))]
+ "TARGET_POWERPC && reload_completed"
+ [(set (match_dup 2)
+ (zero_extend:HI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "
+{
+ rtx reg;
+ int offset;
+ if (GET_CODE (operands[2]) == REG)
+ {
+ reg = operands[2];
+ offset = 0;
+ }
+ else if (GET_CODE (operands[2]) == SUBREG)
+ {
+ reg = SUBREG_REG (operands[2]);
+ offset = SUBREG_WORD (operands[2]);
+ }
+ else
+ abort ();
+
+ operands[3] = gen_rtx_SUBREG (SImode, reg, offset);
+}")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:HI 0 "gpc_reg_operand" "=r,r")
+ (sign_extend:HI (match_dup 1)))]
+ "TARGET_POWERPC"
+ "@
+ extsb. %0,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:HI 0 "gpc_reg_operand" "")
+ (sign_extend:HI (match_dup 1)))]
+ "TARGET_POWERPC && reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:HI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "
+{
+ rtx reg;
+ int offset;
+ if (GET_CODE (operands[0]) == REG)
+ {
+ reg = operands[0];
+ offset = 0;
+ }
+ else if (GET_CODE (operands[0]) == SUBREG)
+ {
+ reg = SUBREG_REG (operands[0]);
+ offset = SUBREG_WORD (operands[0]);
+ }
+ else
+ abort ();
+
+ operands[3] = gen_rtx_SUBREG (SImode, reg, offset);
+}")
+
+(define_expand "extendqihi2_power"
+ [(parallel [(set (match_dup 2)
+ (ashift:SI (match_operand:QI 1 "gpc_reg_operand" "")
+ (const_int 24)))
+ (clobber (scratch:SI))])
+ (parallel [(set (match_operand:HI 0 "gpc_reg_operand" "")
+ (ashiftrt:SI (match_dup 2)
+ (const_int 24)))
+ (clobber (scratch:SI))])]
+ "TARGET_POWER"
+ "
+{ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode); }")
+
+(define_expand "extendqihi2_no_power"
+ [(set (match_dup 2)
+ (ashift:SI (match_operand:QI 1 "gpc_reg_operand" "")
+ (const_int 24)))
+ (set (match_operand:HI 0 "gpc_reg_operand" "")
+ (ashiftrt:SI (match_dup 2)
+ (const_int 24)))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "
+{ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode); }")
+
+(define_expand "zero_extendhisi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (match_operand:HI 1 "reg_or_mem_operand" "m,r")))]
+ ""
+ "@
+ lhz%U1%X1 %0,%1
+ {rlinm|rlwinm} %0,%1,0,0xffff"
+ [(set_attr "type" "load,*")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 "=r,r"))]
+ ""
+ "@
+ {andil.|andi.} %2,%1,0xffff
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 ""))]
+ "reload_completed"
+ [(set (match_dup 2)
+ (zero_extend:SI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (match_dup 1)))]
+ ""
+ "@
+ {andil.|andi.} %0,%1,0xffff
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (zero_extend:SI (match_dup 1)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:SI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "extendhisi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (sign_extend:SI (match_operand:HI 1 "reg_or_mem_operand" "m,r")))]
+ ""
+ "@
+ lha%U1%X1 %0,%1
+ {exts|extsh} %0,%1"
+ [(set_attr "type" "load,*")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 "=r,r"))]
+ ""
+ "@
+ {exts.|extsh.} %2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "=x,?y")
+ (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (sign_extend:SI (match_dup 1)))]
+ ""
+ "@
+ {exts.|extsh.} %0,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_operand" "")
+ (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (sign_extend:SI (match_dup 1)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (sign_extend:SI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+
+;; Fixed-point arithmetic insns.
+
+;; Discourage ai/addic because of carry but provide it in an alternative
+;; allowing register zero as source.
+(define_expand "addsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (plus:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT && !add_operand (operands[2], SImode))
+ {
+ rtx tmp = ((reload_in_progress || reload_completed
+ || rtx_equal_p (operands[0], operands[1]))
+ ? operands[0] : gen_reg_rtx (SImode));
+
+ HOST_WIDE_INT low = INTVAL (operands[2]) & 0xffff;
+ HOST_WIDE_INT high = INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff);
+
+ if (low & 0x8000)
+ high += 0x10000, low |= ((HOST_WIDE_INT) -1) << 16;
+
+ emit_insn (gen_addsi3 (tmp, operands[1], GEN_INT (high)));
+ emit_insn (gen_addsi3 (operands[0], tmp, GEN_INT (low)));
+ DONE;
+ }
+}")
+
+(define_insn "*addsi3_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,?r,r")
+ (plus:SI (match_operand:SI 1 "gpc_reg_operand" "%r,b,r,b")
+ (match_operand:SI 2 "add_operand" "r,I,I,J")))]
+ ""
+ "@
+ {cax|add} %0,%1,%2
+ {cal %0,%2(%1)|addi %0,%1,%2}
+ {ai|addic} %0,%1,%2
+ {cau|addis} %0,%1,%v2"
+ [(set_attr "length" "4,4,4,4")])
+
+(define_insn "*addsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC (plus:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I,r,I"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r,r,r"))]
+ ""
+ "@
+ {cax.|add.} %3,%1,%2
+ {ai.|addic.} %3,%1,%2
+ #
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,4,8,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (plus:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_short_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (plus:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*addsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC (plus:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I,r,I"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (plus:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+ "@
+ {cax.|add.} %0,%1,%2
+ {ai.|addic.} %0,%1,%2
+ #
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,4,8,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (plus:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_short_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (plus:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; Split an add that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine. Note that the low-order
+;; add should be last in case the result gets used in an address.
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (plus:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "non_add_cint_operand" "")))]
+ ""
+ [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))]
+"
+{
+ HOST_WIDE_INT low = INTVAL (operands[2]) & 0xffff;
+ HOST_WIDE_INT high = INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff);
+
+ if (low & 0x8000)
+ high += 0x10000, low |= ((HOST_WIDE_INT) -1) << 16;
+
+ operands[3] = GEN_INT (high);
+ operands[4] = GEN_INT (low);
+}")
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (not:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
+ ""
+ "nor %0,%1,%1")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 "=r,r"))]
+ ""
+ "@
+ nor. %2,%1,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 ""))]
+ "reload_completed"
+ [(set (match_dup 2)
+ (not:SI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (not:SI (match_dup 1)))]
+ ""
+ "@
+ nor. %0,%1,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (not:SI (match_dup 1)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (not:SI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (minus:SI (match_operand:SI 1 "reg_or_short_operand" "rI")
+ (match_operand:SI 2 "gpc_reg_operand" "r")))]
+ "! TARGET_POWERPC"
+ "{sf%I1|subf%I1c} %0,%2,%1")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "reg_or_short_operand" "r,I")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r")))]
+ "TARGET_POWERPC"
+ "@
+ subf %0,%2,%1
+ subfic %0,%2,%1")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "! TARGET_POWERPC"
+ "@
+ {sf.|subfc.} %3,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "! TARGET_POWERPC && reload_completed"
+ [(set (match_dup 3)
+ (minus:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "TARGET_POWERPC"
+ "@
+ subf. %3,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "TARGET_POWERPC && reload_completed"
+ [(set (match_dup 3)
+ (minus:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "! TARGET_POWERPC"
+ "@
+ {sf.|subfc.} %0,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (minus:SI (match_dup 1)
+ (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (minus:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (minus:SI (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_POWERPC"
+ "subf. %0,%2,%1"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_short_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (minus:SI (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_POWERPC && reload_completed"
+ [(set (match_dup 0)
+ (minus:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "subsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (minus:SI (match_operand:SI 1 "reg_or_short_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ emit_insn (gen_addsi3 (operands[0], operands[1],
+ negate_rtx (SImode, operands[2])));
+ DONE;
+ }
+}")
+
+;; For SMIN, SMAX, UMIN, and UMAX, we use DEFINE_EXPAND's that involve a doz[i]
+;; instruction and some auxiliary computations. Then we just have a single
+;; DEFINE_INSN for doz[i] and the define_splits to make them if made by
+;; combine.
+
+(define_expand "sminsi3"
+ [(set (match_dup 3)
+ (if_then_else:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_short_operand" ""))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (minus:SI (match_dup 2) (match_dup 3)))]
+ "TARGET_POWER"
+ "
+{ operands[3] = gen_reg_rtx (SImode); }")
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (smin:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_short_operand" "")))
+ (clobber (match_operand:SI 3 "gpc_reg_operand" ""))]
+ "TARGET_POWER"
+ [(set (match_dup 3)
+ (if_then_else:SI (gt:SI (match_dup 1) (match_dup 2))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1))))
+ (set (match_dup 0) (minus:SI (match_dup 2) (match_dup 3)))]
+ "")
+
+(define_expand "smaxsi3"
+ [(set (match_dup 3)
+ (if_then_else:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_short_operand" ""))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (plus:SI (match_dup 3) (match_dup 1)))]
+ "TARGET_POWER"
+ "
+{ operands[3] = gen_reg_rtx (SImode); }")
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (smax:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_short_operand" "")))
+ (clobber (match_operand:SI 3 "gpc_reg_operand" ""))]
+ "TARGET_POWER"
+ [(set (match_dup 3)
+ (if_then_else:SI (gt:SI (match_dup 1) (match_dup 2))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1))))
+ (set (match_dup 0) (plus:SI (match_dup 3) (match_dup 1)))]
+ "")
+
+(define_expand "uminsi3"
+ [(set (match_dup 3) (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_dup 5)))
+ (set (match_dup 4) (xor:SI (match_operand:SI 2 "gpc_reg_operand" "")
+ (match_dup 5)))
+ (set (match_dup 3) (if_then_else:SI (gt (match_dup 3) (match_dup 4))
+ (const_int 0)
+ (minus:SI (match_dup 4) (match_dup 3))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (minus:SI (match_dup 2) (match_dup 3)))]
+ "TARGET_POWER"
+ "
+{
+ operands[3] = gen_reg_rtx (SImode);
+ operands[4] = gen_reg_rtx (SImode);
+ operands[5] = GEN_INT (-2147483647 - 1);
+}")
+
+(define_expand "umaxsi3"
+ [(set (match_dup 3) (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_dup 5)))
+ (set (match_dup 4) (xor:SI (match_operand:SI 2 "gpc_reg_operand" "")
+ (match_dup 5)))
+ (set (match_dup 3) (if_then_else:SI (gt (match_dup 3) (match_dup 4))
+ (const_int 0)
+ (minus:SI (match_dup 4) (match_dup 3))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (plus:SI (match_dup 3) (match_dup 1)))]
+ "TARGET_POWER"
+ "
+{
+ operands[3] = gen_reg_rtx (SImode);
+ operands[4] = gen_reg_rtx (SImode);
+ operands[5] = GEN_INT (-2147483647 - 1);
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI"))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1))))]
+ "TARGET_POWER"
+ "doz%I2 %0,%1,%2")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1)))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "TARGET_POWER"
+ "@
+ doz%I2. %3,%1,%2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "=x,?y")
+ (compare:CC
+ (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1)))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "TARGET_POWER && reload_completed"
+ [(set (match_dup 3)
+ (if_then_else:SI (gt (match_dup 1)
+ (match_dup 2))
+ (const_int 0)
+ (minus:SI (match_dup 2)
+ (match_dup 1))))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1)))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (if_then_else:SI (gt (match_dup 1) (match_dup 2))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1))))]
+ "TARGET_POWER"
+ "doz%I2. %0,%1,%2"
+ [(set_attr "type" "delayed_compare")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "=x,?y")
+ (compare:CC
+ (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (const_int 0)
+ (minus:SI (match_dup 2) (match_dup 1)))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (if_then_else:SI (gt (match_dup 1)
+ (match_dup 2))
+ (const_int 0)
+ (minus:SI (match_dup 2)
+ (match_dup 1))))]
+ "TARGET_POWER && reload_completed"
+ [(set (match_dup 0)
+ (if_then_else:SI (gt (match_dup 1)
+ (match_dup 2))
+ (const_int 0)
+ (minus:SI (match_dup 2)
+ (match_dup 1))))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; We don't need abs with condition code because such comparisons should
+;; never be done.
+(define_expand "abssi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (abs:SI (match_operand:SI 1 "gpc_reg_operand" "")))]
+ ""
+ "
+{
+ if (!TARGET_POWER)
+ {
+ emit_insn (gen_abssi2_nopower (operands[0], operands[1]));
+ DONE;
+ }
+}")
+
+(define_insn "abssi2_power"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
+ "TARGET_POWER"
+ "abs %0,%1")
+
+(define_insn "abssi2_nopower"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+ (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0")))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "!TARGET_POWER"
+ "*
+{
+ return (TARGET_POWERPC)
+ ? \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;subf %0,%2,%0\"
+ : \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;{sf|subfc} %0,%2,%0\";
+}"
+ [(set_attr "length" "12")])
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+ (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0")))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "!TARGET_POWER && reload_completed"
+ [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31)))
+ (set (match_dup 0) (xor:SI (match_dup 2) (match_dup 1)))
+ (set (match_dup 0) (minus:SI (match_dup 0) (match_dup 2)))]
+ "")
+
+(define_insn "*nabs_power"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r"))))]
+ "TARGET_POWER"
+ "nabs %0,%1")
+
+(define_insn "*nabs_no_power"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+ (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0"))))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "!TARGET_POWER"
+ "*
+{
+ return (TARGET_POWERPC)
+ ? \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;subf %0,%0,%2\"
+ : \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;{sf|subfc} %0,%0,%2\";
+}"
+ [(set_attr "length" "12")])
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+ (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0"))))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "!TARGET_POWER && reload_completed"
+ [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31)))
+ (set (match_dup 0) (xor:SI (match_dup 2) (match_dup 1)))
+ (set (match_dup 0) (minus:SI (match_dup 2) (match_dup 0)))]
+ "")
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (neg:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
+ ""
+ "neg %0,%1")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (neg:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 "=r,r"))]
+ ""
+ "@
+ neg. %2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (neg:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 2 ""))]
+ "reload_completed"
+ [(set (match_dup 2)
+ (neg:SI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (neg:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (neg:SI (match_dup 1)))]
+ ""
+ "@
+ neg. %0,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (neg:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (neg:SI (match_dup 1)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (neg:SI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "ffssi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
+ (ffs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
+ ""
+ "neg %0,%1\;and %0,%0,%1\;{cntlz|cntlzw} %0,%0\;{sfi|subfic} %0,%0,32"
+ [(set_attr "length" "16")])
+
+(define_expand "mulsi3"
+ [(use (match_operand:SI 0 "gpc_reg_operand" ""))
+ (use (match_operand:SI 1 "gpc_reg_operand" ""))
+ (use (match_operand:SI 2 "reg_or_short_operand" ""))]
+ ""
+ "
+{
+ if (TARGET_POWER)
+ emit_insn (gen_mulsi3_mq (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_mulsi3_no_mq (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "mulsi3_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (mult:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))
+ (clobber (match_scratch:SI 3 "=q,q"))]
+ "TARGET_POWER"
+ "@
+ {muls|mullw} %0,%1,%2
+ {muli|mulli} %0,%1,%2"
+ [(set_attr "type" "imul")])
+
+(define_insn "mulsi3_no_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (mult:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))]
+ "! TARGET_POWER"
+ "@
+ {muls|mullw} %0,%1,%2
+ {muli|mulli} %0,%1,%2"
+ [(set_attr "type" "imul")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))
+ (clobber (match_scratch:SI 4 "=q,q"))]
+ "TARGET_POWER"
+ "@
+ {muls.|mullw.} %3,%1,%2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (match_scratch:SI 4 ""))]
+ "TARGET_POWER && reload_completed"
+ [(parallel [(set (match_dup 3)
+ (mult:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "! TARGET_POWER"
+ "@
+ {muls.|mullw.} %3,%1,%2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (mult:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (mult:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:SI 4 "=q,q"))]
+ "TARGET_POWER"
+ "@
+ {muls.|mullw.} %0,%1,%2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (mult:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:SI 4 ""))]
+ "TARGET_POWER && reload_completed"
+ [(parallel [(set (match_dup 0)
+ (mult:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (mult:SI (match_dup 1) (match_dup 2)))]
+ "! TARGET_POWER"
+ "@
+ {muls.|mullw.} %0,%1,%2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (mult:SI (match_dup 1)
+ (match_dup 2)))]
+ "!TARGET_POWER && reload_completed"
+ [(set (match_dup 0)
+ (mult:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; Operand 1 is divided by operand 2; quotient goes to operand
+;; 0 and remainder to operand 3.
+;; ??? At some point, see what, if anything, we can do about if (x % y == 0).
+
+(define_expand "divmodsi4"
+ [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (div:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" "")))
+ (set (match_operand:SI 3 "gpc_reg_operand" "")
+ (mod:SI (match_dup 1) (match_dup 2)))])]
+ "TARGET_POWER || (! TARGET_POWER && ! TARGET_POWERPC)"
+ "
+{
+ if (! TARGET_POWER && ! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]);
+ emit_insn (gen_divss_call ());
+ emit_move_insn (operands[0], gen_rtx_REG (SImode, 3));
+ emit_move_insn (operands[3], gen_rtx_REG (SImode, 4));
+ DONE;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (div:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (set (match_operand:SI 3 "gpc_reg_operand" "=q")
+ (mod:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWER"
+ "divs %0,%1,%2"
+ [(set_attr "type" "idiv")])
+
+(define_expand "udivsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (udiv:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" "")))]
+ "TARGET_POWERPC || (! TARGET_POWER && ! TARGET_POWERPC)"
+ "
+{
+ if (! TARGET_POWER && ! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]);
+ emit_insn (gen_quous_call ());
+ emit_move_insn (operands[0], gen_rtx_REG (SImode, 3));
+ DONE;
+ }
+ else if (TARGET_POWER)
+ {
+ emit_insn (gen_udivsi3_mq (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+
+(define_insn "udivsi3_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (udiv:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 3 "=q"))]
+ "TARGET_POWERPC && TARGET_POWER"
+ "divwu %0,%1,%2"
+ [(set_attr "type" "idiv")])
+
+(define_insn "*udivsi3_no_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (udiv:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC && ! TARGET_POWER"
+ "divwu %0,%1,%2"
+ [(set_attr "type" "idiv")])
+
+;; For powers of two we can do srai/aze for divide and then adjust for
+;; modulus. If it isn't a power of two, FAIL on POWER so divmodsi4 will be
+;; used; for PowerPC, force operands into register and do a normal divide;
+;; for AIX common-mode, use quoss call on register operands.
+(define_expand "divsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (div:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && exact_log2 (INTVAL (operands[2])) >= 0)
+ ;
+ else if (TARGET_POWERPC)
+ {
+ operands[2] = force_reg (SImode, operands[2]);
+ if (TARGET_POWER)
+ {
+ emit_insn (gen_divsi3_mq (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ }
+ else if (TARGET_POWER)
+ FAIL;
+ else
+ {
+ emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]);
+ emit_insn (gen_quoss_call ());
+ emit_move_insn (operands[0], gen_rtx_REG (SImode, 3));
+ DONE;
+ }
+}")
+
+(define_insn "divsi3_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (div:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 3 "=q"))]
+ "TARGET_POWERPC && TARGET_POWER"
+ "divw %0,%1,%2"
+ [(set_attr "type" "idiv")])
+
+(define_insn "*divsi3_no_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (div:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC && ! TARGET_POWER"
+ "divw %0,%1,%2"
+ [(set_attr "type" "idiv")])
+
+(define_expand "modsi3"
+ [(use (match_operand:SI 0 "gpc_reg_operand" ""))
+ (use (match_operand:SI 1 "gpc_reg_operand" ""))
+ (use (match_operand:SI 2 "reg_or_cint_operand" ""))]
+ ""
+ "
+{
+ int i = exact_log2 (INTVAL (operands[2]));
+ rtx temp1;
+ rtx temp2;
+
+ if (GET_CODE (operands[2]) != CONST_INT || i < 0)
+ FAIL;
+
+ temp1 = gen_reg_rtx (SImode);
+ temp2 = gen_reg_rtx (SImode);
+
+ emit_insn (gen_divsi3 (temp1, operands[1], operands[2]));
+ emit_insn (gen_ashlsi3 (temp2, temp1, GEN_INT (i)));
+ emit_insn (gen_subsi3 (operands[0], operands[1], temp2));
+ DONE;
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (div:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "N")))]
+ "exact_log2 (INTVAL (operands[2])) >= 0"
+ "{srai|srawi} %0,%1,%p2\;{aze|addze} %0,%0"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (div:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "N,N"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "exact_log2 (INTVAL (operands[2])) >= 0"
+ "@
+ {srai|srawi} %3,%1,%p2\;{aze.|addze.} %3,%3
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (div:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed && exact_log2 (INTVAL (operands[2])) >= 0"
+ [(set (match_dup 3)
+ (div:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (div:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "N,N"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (div:SI (match_dup 1)
+ (match_dup 2)))]
+ "exact_log2 (INTVAL (operands[2])) >= 0"
+ "@
+ {srai|srawi} %0,%1,%p2\;{aze.|addze.} %0,%0
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (div:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_short_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (div:SI (match_dup 1)
+ (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (div:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (udiv:SI
+ (plus:DI (ashift:DI
+ (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (const_int 32))
+ (zero_extend:DI (match_operand:SI 4 "register_operand" "2")))
+ (match_operand:SI 3 "gpc_reg_operand" "r")))
+ (set (match_operand:SI 2 "register_operand" "=*q")
+ (umod:SI
+ (plus:DI (ashift:DI
+ (zero_extend:DI (match_dup 1)) (const_int 32))
+ (zero_extend:DI (match_dup 4)))
+ (match_dup 3)))]
+ "TARGET_POWER"
+ "div %0,%1,%3"
+ [(set_attr "type" "idiv")])
+
+;; To do unsigned divide we handle the cases of the divisor looking like a
+;; negative number. If it is a constant that is less than 2**31, we don't
+;; have to worry about the branches. So make a few subroutines here.
+;;
+;; First comes the normal case.
+(define_expand "udivmodsi4_normal"
+ [(set (match_dup 4) (const_int 0))
+ (parallel [(set (match_operand:SI 0 "" "")
+ (udiv:SI (plus:DI (ashift:DI (zero_extend:DI (match_dup 4))
+ (const_int 32))
+ (zero_extend:DI (match_operand:SI 1 "" "")))
+ (match_operand:SI 2 "" "")))
+ (set (match_operand:SI 3 "" "")
+ (umod:SI (plus:DI (ashift:DI (zero_extend:DI (match_dup 4))
+ (const_int 32))
+ (zero_extend:DI (match_dup 1)))
+ (match_dup 2)))])]
+ "TARGET_POWER"
+ "
+{ operands[4] = gen_reg_rtx (SImode); }")
+
+;; This handles the branches.
+(define_expand "udivmodsi4_tests"
+ [(set (match_operand:SI 0 "" "") (const_int 0))
+ (set (match_operand:SI 3 "" "") (match_operand:SI 1 "" ""))
+ (set (match_dup 5) (compare:CCUNS (match_dup 1) (match_operand:SI 2 "" "")))
+ (set (pc) (if_then_else (ltu (match_dup 5) (const_int 0))
+ (label_ref (match_operand:SI 4 "" "")) (pc)))
+ (set (match_dup 0) (const_int 1))
+ (set (match_dup 3) (minus:SI (match_dup 1) (match_dup 2)))
+ (set (match_dup 6) (compare:CC (match_dup 2) (const_int 0)))
+ (set (pc) (if_then_else (lt (match_dup 6) (const_int 0))
+ (label_ref (match_dup 4)) (pc)))]
+ "TARGET_POWER"
+ "
+{ operands[5] = gen_reg_rtx (CCUNSmode);
+ operands[6] = gen_reg_rtx (CCmode);
+}")
+
+(define_expand "udivmodsi4"
+ [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (udiv:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))
+ (set (match_operand:SI 3 "gpc_reg_operand" "")
+ (umod:SI (match_dup 1) (match_dup 2)))])]
+ ""
+ "
+{
+ rtx label = 0;
+
+ if (! TARGET_POWER)
+ {
+ if (! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]);
+ emit_insn (gen_divus_call ());
+ emit_move_insn (operands[0], gen_rtx_REG (SImode, 3));
+ emit_move_insn (operands[3], gen_rtx_REG (SImode, 4));
+ DONE;
+ }
+ else
+ FAIL;
+ }
+
+ if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) < 0)
+ {
+ operands[2] = force_reg (SImode, operands[2]);
+ label = gen_label_rtx ();
+ emit (gen_udivmodsi4_tests (operands[0], operands[1], operands[2],
+ operands[3], label));
+ }
+ else
+ operands[2] = force_reg (SImode, operands[2]);
+
+ emit (gen_udivmodsi4_normal (operands[0], operands[1], operands[2],
+ operands[3]));
+ if (label)
+ emit_label (label);
+
+ DONE;
+}")
+
+;; AIX architecture-independent common-mode multiply (DImode),
+;; divide/modulus, and quotient subroutine calls. Input operands in R3 and
+;; R4; results in R3 and sometimes R4; link register always clobbered by bla
+;; instruction; R0 sometimes clobbered; also, MQ sometimes clobbered but
+;; assumed unused if generating common-mode, so ignore.
+(define_insn "mulh_call"
+ [(set (reg:SI 3)
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI (reg:SI 3))
+ (sign_extend:DI (reg:SI 4)))
+ (const_int 32))))
+ (clobber (match_scratch:SI 0 "=l"))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __mulh"
+ [(set_attr "type" "imul")])
+
+(define_insn "mull_call"
+ [(set (reg:DI 3)
+ (mult:DI (sign_extend:DI (reg:SI 3))
+ (sign_extend:DI (reg:SI 4))))
+ (clobber (match_scratch:SI 0 "=l"))
+ (clobber (reg:SI 0))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __mull"
+ [(set_attr "type" "imul")])
+
+(define_insn "divss_call"
+ [(set (reg:SI 3)
+ (div:SI (reg:SI 3) (reg:SI 4)))
+ (set (reg:SI 4)
+ (mod:SI (reg:SI 3) (reg:SI 4)))
+ (clobber (match_scratch:SI 0 "=l"))
+ (clobber (reg:SI 0))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __divss"
+ [(set_attr "type" "idiv")])
+
+(define_insn "divus_call"
+ [(set (reg:SI 3)
+ (udiv:SI (reg:SI 3) (reg:SI 4)))
+ (set (reg:SI 4)
+ (umod:SI (reg:SI 3) (reg:SI 4)))
+ (clobber (match_scratch:SI 0 "=l"))
+ (clobber (reg:SI 0))
+ (clobber (match_scratch:CC 1 "=x"))
+ (clobber (reg:CC 69))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __divus"
+ [(set_attr "type" "idiv")])
+
+(define_insn "quoss_call"
+ [(set (reg:SI 3)
+ (div:SI (reg:SI 3) (reg:SI 4)))
+ (clobber (match_scratch:SI 0 "=l"))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __quoss"
+ [(set_attr "type" "idiv")])
+
+(define_insn "quous_call"
+ [(set (reg:SI 3)
+ (udiv:SI (reg:SI 3) (reg:SI 4)))
+ (clobber (match_scratch:SI 0 "=l"))
+ (clobber (reg:SI 0))
+ (clobber (match_scratch:CC 1 "=x"))
+ (clobber (reg:CC 69))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __quous"
+ [(set_attr "type" "idiv")])
+
+;; Logical instructions
+(define_expand "andsi3"
+ [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r")
+ (match_operand:SI 2 "and_operand" "?r,L,K,J")))
+ (clobber (match_scratch:CC 3 "=X,X,x,x"))])]
+ ""
+ "")
+
+;; If cr0 isn't available, and we want to do an andi, load the register into
+;; the destination first.
+
+(define_insn "andsi3_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,&??r,&??r")
+ (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r")
+ (match_operand:SI 2 "and_operand" "?r,L,K,J,K,J")))
+ (clobber (match_operand:CC 3 "scratch_operand" "=X,X,x,x,X,X"))]
+ ""
+ "@
+ and %0,%1,%2
+ {rlinm|rlwinm} %0,%1,0,%m2,%M2
+ {andil.|andi.} %0,%1,%b2
+ {andiu.|andis.} %0,%1,%u2
+ #
+ #"
+ [(set_attr "length" "4,4,4,4,8,8")])
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (and:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))
+ (clobber (scratch:CC))]
+ "reload_completed && !mask_constant (INTVAL (operands[2]))"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (parallel [(set (match_dup 0)
+ (and:SI (match_dup 0)
+ (match_dup 1)))
+ (clobber (scratch:CC))])]
+ "")
+
+;; Note to set cr's other than cr0 we do the and immediate and then
+;; the test again -- this avoids a mcrf which on the higher end
+;; machines causes an execution serialization
+
+(define_insn "*andsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y,???y,???y")
+ (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r")
+ (match_operand:SI 2 "and_operand" "r,K,J,L,r,K,J,L,K,L"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r,r,r,r,r,r,r,&r,&r"))
+ (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X,X,X"))]
+ ""
+ "@
+ and. %3,%1,%2
+ {andil.|andi.} %3,%1,%b2
+ {andiu.|andis.} %3,%1,%u2
+ {rlinm.|rlwinm.} %3,%1,0,%m2,%M2
+ #
+ #
+ #
+ #
+ #
+ #"
+ [(set_attr "type" "compare,compare,compare,delayed_compare,compare,compare,compare,compare,compare,compare")
+ (set_attr "length" "4,4,4,4,8,8,8,8,12,12")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "and_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (match_scratch:CC 4 ""))]
+ "reload_completed"
+ [(parallel [(set (match_dup 3)
+ (and:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*andsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y,???y,???y")
+ (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r")
+ (match_operand:SI 2 "and_operand" "r,K,J,L,r,K,J,L,K,J"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r,r,r,r,&r,&r")
+ (and:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X,X,X"))]
+ ""
+ "@
+ and. %0,%1,%2
+ {andil.|andi.} %0,%1,%b2
+ {andiu.|andis.} %0,%1,%u2
+ {rlinm.|rlwinm.} %0,%1,0,%m2,%M2
+ #
+ #
+ #
+ #
+ #
+ #"
+ [(set_attr "type" "compare,compare,compare,delayed_compare,compare,compare,compare,compare,compare,compare")
+ (set_attr "length" "4,4,4,4,8,8,8,8,12,12")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "and_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (and:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:CC 4 ""))]
+ "reload_completed"
+ [(parallel [(set (match_dup 0)
+ (and:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "iorsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ior:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && !logical_operand (operands[2], SImode))
+ {
+ HOST_WIDE_INT value = INTVAL (operands[2]);
+ rtx tmp = ((reload_in_progress || reload_completed
+ || rtx_equal_p (operands[0], operands[1]))
+ ? operands[0] : gen_reg_rtx (SImode));
+
+ emit_insn (gen_iorsi3 (tmp, operands[1],
+ GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff))));
+ emit_insn (gen_iorsi3 (operands[0], tmp, GEN_INT (value & 0xffff)));
+ DONE;
+ }
+}")
+
+(define_insn "*iorsi3_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r")
+ (ior:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r")
+ (match_operand:SI 2 "logical_operand" "r,K,J")))]
+ ""
+ "@
+ or %0,%1,%2
+ {oril|ori} %0,%1,%b2
+ {oriu|oris} %0,%1,%u2"
+ [(set_attr "length" "4,4,4")])
+
+(define_insn "*iorsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ or. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (ior:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*iorsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ior:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+ "@
+ or. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ior:SI (match_dup 1) (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (ior:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; Split an IOR that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine.
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ior:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "non_logical_cint_operand" "")))]
+ ""
+ [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (ior:SI (match_dup 0) (match_dup 4)))]
+"
+{
+ operands[3] = GEN_INT (INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff));
+ operands[4] = GEN_INT (INTVAL (operands[2]) & 0xffff);
+}")
+
+(define_expand "xorsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && !logical_operand (operands[2], SImode))
+ {
+ HOST_WIDE_INT value = INTVAL (operands[2]);
+ rtx tmp = ((reload_in_progress || reload_completed
+ || rtx_equal_p (operands[0], operands[1]))
+ ? operands[0] : gen_reg_rtx (SImode));
+
+ emit_insn (gen_xorsi3 (tmp, operands[1],
+ GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff))));
+ emit_insn (gen_xorsi3 (operands[0], tmp, GEN_INT (value & 0xffff)));
+ DONE;
+ }
+}")
+
+(define_insn "*xorsi3_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r")
+ (xor:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r")
+ (match_operand:SI 2 "logical_operand" "r,K,J")))]
+ ""
+ "@
+ xor %0,%1,%2
+ {xoril|xori} %0,%1,%b2
+ {xoriu|xoris} %0,%1,%u2"
+ [(set_attr "length" "4,4,4")])
+
+(define_insn "*xorsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (xor:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ xor. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (xor:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*xorsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (xor:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (xor:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+ "@
+ xor. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (xor:SI (match_dup 1) (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (xor:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; Split an XOR that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine.
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "non_logical_cint_operand" "")))]
+ ""
+ [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (xor:SI (match_dup 0) (match_dup 4)))]
+"
+{
+ operands[3] = GEN_INT (INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff));
+ operands[4] = GEN_INT (INTVAL (operands[2]) & 0xffff);
+}")
+
+(define_insn "*eqvsi3_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (not:SI (xor:SI (match_operand:SI 1 "gpc_reg_operand" "%r")
+ (match_operand:SI 2 "gpc_reg_operand" "r"))))]
+ ""
+ "eqv %0,%1,%2")
+
+(define_insn "*eqvsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (not:SI (xor:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ eqv. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (not:SI (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (not:SI (xor:SI (match_dup 1)
+ (match_dup 2))))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*eqvsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (not:SI (xor:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (not:SI (xor:SI (match_dup 1) (match_dup 2))))]
+ ""
+ "@
+ eqv. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (not:SI (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_short_operand" "")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (not:SI (xor:SI (match_dup 1)
+ (match_dup 2))))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (not:SI (xor:SI (match_dup 1)
+ (match_dup 2))))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*andcsi3_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (match_operand:SI 2 "gpc_reg_operand" "r")))]
+ ""
+ "andc %0,%2,%1")
+
+(define_insn "*andcsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ andc. %3,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (and:SI (not:SI (match_dup 1))
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*andcsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (and:SI (not:SI (match_dup 1))
+ (match_dup 2)))]
+ ""
+ "@
+ andc. %0,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (and:SI (not:SI (match_dup 1))
+ (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (and:SI (not:SI (match_dup 1))
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*iorcsi3_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (match_operand:SI 2 "gpc_reg_operand" "r")))]
+ ""
+ "orc %0,%2,%1")
+
+(define_insn "*iorcsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ orc. %3,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (ior:SI (not:SI (match_dup 1))
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*iorcsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ior:SI (not:SI (match_dup 1)) (match_dup 2)))]
+ ""
+ "@
+ orc. %0,%2,%1
+ #"
+ [(set_attr "type" "compare")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ior:SI (not:SI (match_dup 1))
+ (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (ior:SI (not:SI (match_dup 1))
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*nandsi3_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
+ ""
+ "nand %0,%1,%2")
+
+(define_insn "*nandsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ nand. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (ior:SI (not:SI (match_dup 1))
+ (not:SI (match_dup 2))))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*nandsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ior:SI (not:SI (match_dup 1))
+ (not:SI (match_dup 2))))]
+ ""
+ "@
+ nand. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ior:SI (not:SI (match_dup 1))
+ (not:SI (match_dup 2))))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (ior:SI (not:SI (match_dup 1))
+ (not:SI (match_dup 2))))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*norsi3_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
+ ""
+ "nor %0,%1,%2")
+
+(define_insn "*norsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ nor. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (and:SI (not:SI (match_dup 1))
+ (not:SI (match_dup 2))))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*norsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (and:SI (not:SI (match_dup 1))
+ (not:SI (match_dup 2))))]
+ ""
+ "@
+ nor. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:SI (not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (not:SI (match_operand:SI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (and:SI (not:SI (match_dup 1))
+ (not:SI (match_dup 2))))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (and:SI (not:SI (match_dup 1))
+ (not:SI (match_dup 2))))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; maskir insn. We need four forms because things might be in arbitrary
+;; orders. Don't define forms that only set CR fields because these
+;; would modify an input register.
+
+(define_insn "*maskir_internal1"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (match_operand:SI 1 "gpc_reg_operand" "0"))
+ (and:SI (match_dup 2)
+ (match_operand:SI 3 "gpc_reg_operand" "r"))))]
+ "TARGET_POWER"
+ "maskir %0,%3,%2")
+
+(define_insn "*maskir_internal2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (match_operand:SI 1 "gpc_reg_operand" "0"))
+ (and:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_dup 2))))]
+ "TARGET_POWER"
+ "maskir %0,%3,%2")
+
+(define_insn "*maskir_internal3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ior:SI (and:SI (match_operand:SI 2 "gpc_reg_operand" "r")
+ (match_operand:SI 3 "gpc_reg_operand" "r"))
+ (and:SI (not:SI (match_dup 2))
+ (match_operand:SI 1 "gpc_reg_operand" "0"))))]
+ "TARGET_POWER"
+ "maskir %0,%3,%2")
+
+(define_insn "*maskir_internal4"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ior:SI (and:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (and:SI (not:SI (match_dup 2))
+ (match_operand:SI 1 "gpc_reg_operand" "0"))))]
+ "TARGET_POWER"
+ "maskir %0,%3,%2")
+
+(define_insn "*maskir_internal5"
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (match_operand:SI 1 "gpc_reg_operand" "0,0"))
+ (and:SI (match_dup 2)
+ (match_operand:SI 3 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1))
+ (and:SI (match_dup 2) (match_dup 3))))]
+ "TARGET_POWER"
+ "@
+ maskir. %0,%3,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" ""))
+ (match_operand:SI 1 "gpc_reg_operand" ""))
+ (and:SI (match_dup 2)
+ (match_operand:SI 3 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1))
+ (and:SI (match_dup 2) (match_dup 3))))]
+ "TARGET_POWER && reload_completed"
+ [(set (match_dup 0)
+ (ior:SI (and:SI (not:SI (match_dup 2))
+ (match_dup 1))
+ (and:SI (match_dup 2)
+ (match_dup 3))))
+ (set (match_dup 4)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+
+(define_insn "*maskir_internal6"
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (match_operand:SI 1 "gpc_reg_operand" "0,0"))
+ (and:SI (match_operand:SI 3 "gpc_reg_operand" "r,r")
+ (match_dup 2)))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1))
+ (and:SI (match_dup 3) (match_dup 2))))]
+ "TARGET_POWER"
+ "@
+ maskir. %0,%3,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" ""))
+ (match_operand:SI 1 "gpc_reg_operand" ""))
+ (and:SI (match_operand:SI 3 "gpc_reg_operand" "")
+ (match_dup 2)))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1))
+ (and:SI (match_dup 3) (match_dup 2))))]
+ "TARGET_POWER && reload_completed"
+ [(set (match_dup 0)
+ (ior:SI (and:SI (not:SI (match_dup 2))
+ (match_dup 1))
+ (and:SI (match_dup 3)
+ (match_dup 2))))
+ (set (match_dup 4)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*maskir_internal7"
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (ior:SI (and:SI (match_operand:SI 2 "gpc_reg_operand" "r,r")
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (and:SI (not:SI (match_dup 2))
+ (match_operand:SI 1 "gpc_reg_operand" "0,0")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ior:SI (and:SI (match_dup 2) (match_dup 3))
+ (and:SI (not:SI (match_dup 2)) (match_dup 1))))]
+ "TARGET_POWER"
+ "@
+ maskir. %0,%3,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (ior:SI (and:SI (match_operand:SI 2 "gpc_reg_operand" "")
+ (match_operand:SI 3 "gpc_reg_operand" ""))
+ (and:SI (not:SI (match_dup 2))
+ (match_operand:SI 1 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ior:SI (and:SI (match_dup 2) (match_dup 3))
+ (and:SI (not:SI (match_dup 2)) (match_dup 1))))]
+ "TARGET_POWER"
+ [(set (match_dup 0)
+ (ior:SI (and:SI (match_dup 2)
+ (match_dup 3))
+ (and:SI (not:SI (match_dup 2))
+ (match_dup 1))))
+ (set (match_dup 4)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*maskir_internal8"
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (ior:SI (and:SI (match_operand:SI 3 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (and:SI (not:SI (match_dup 2))
+ (match_operand:SI 1 "gpc_reg_operand" "0,0")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ior:SI (and:SI (match_dup 3) (match_dup 2))
+ (and:SI (not:SI (match_dup 2)) (match_dup 1))))]
+ "TARGET_POWER"
+ "@
+ maskir. %0,%3,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (ior:SI (and:SI (match_operand:SI 3 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" ""))
+ (and:SI (not:SI (match_dup 2))
+ (match_operand:SI 1 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ior:SI (and:SI (match_dup 3) (match_dup 2))
+ (and:SI (not:SI (match_dup 2)) (match_dup 1))))]
+ "TARGET_POWER && reload_completed"
+ [(set (match_dup 0)
+ (ior:SI (and:SI (match_dup 3)
+ (match_dup 2))
+ (and:SI (not:SI (match_dup 2))
+ (match_dup 1))))
+ (set (match_dup 4)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+
+;; Rotate and shift insns, in all their variants. These support shifts,
+;; field inserts and extracts, and various combinations thereof.
+(define_expand "insv"
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (match_operand:SI 3 "gpc_reg_operand" "r"))]
+ ""
+ "
+{
+ /* Do not handle 16/8 bit structures that fit in HI/QI modes directly, since
+ the (SUBREG:SI (REG:HI xxx)) that is otherwise generated can confuse the
+ compiler if the address of the structure is taken later. */
+ if (GET_CODE (operands[0]) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (operands[0]))) < UNITS_PER_WORD))
+ FAIL;
+}")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (match_operand:SI 3 "gpc_reg_operand" "r"))]
+ ""
+ "*
+{
+ int start = INTVAL (operands[2]) & 31;
+ int size = INTVAL (operands[1]) & 31;
+
+ operands[4] = GEN_INT (32 - start - size);
+ operands[1] = GEN_INT (start + size - 1);
+ return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\";
+}")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (ashift:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "i")))]
+ "(32 - (INTVAL (operands[4]) & 31)) >= INTVAL (operands[1])"
+ "*
+{
+ int shift = INTVAL (operands[4]) & 31;
+ int start = INTVAL (operands[2]) & 31;
+ int size = INTVAL (operands[1]) & 31;
+
+ operands[4] = GEN_INT (shift - start - size);
+ operands[1] = GEN_INT (start + size - 1);
+ return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\";
+}")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (ashiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "i")))]
+ "(32 - (INTVAL (operands[4]) & 31)) >= INTVAL (operands[1])"
+ "*
+{
+ int shift = INTVAL (operands[4]) & 31;
+ int start = INTVAL (operands[2]) & 31;
+ int size = INTVAL (operands[1]) & 31;
+
+ operands[4] = GEN_INT (32 - shift - start - size);
+ operands[1] = GEN_INT (start + size - 1);
+ return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\";
+}")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (lshiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "i")))]
+ "(32 - (INTVAL (operands[4]) & 31)) >= INTVAL (operands[1])"
+ "*
+{
+ int shift = INTVAL (operands[4]) & 31;
+ int start = INTVAL (operands[2]) & 31;
+ int size = INTVAL (operands[1]) & 31;
+
+ operands[4] = GEN_INT (32 - shift - start - size);
+ operands[1] = GEN_INT (start + size - 1);
+ return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\";
+}")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (zero_extract:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "i")
+ (match_operand:SI 5 "const_int_operand" "i")))]
+ "INTVAL (operands[4]) >= INTVAL (operands[1])"
+ "*
+{
+ int extract_start = INTVAL (operands[5]) & 31;
+ int extract_size = INTVAL (operands[4]) & 31;
+ int insert_start = INTVAL (operands[2]) & 31;
+ int insert_size = INTVAL (operands[1]) & 31;
+
+/* Align extract field with insert field */
+ operands[5] = GEN_INT (extract_start + extract_size - insert_start - insert_size);
+ operands[1] = GEN_INT (insert_start + insert_size - 1);
+ return \"{rlimi|rlwimi} %0,%3,%h5,%h2,%h1\";
+}")
+
+(define_insn ""
+ [(set (zero_extract:DI (match_operand:DI 0 "gpc_reg_operand" "+r")
+ (match_operand:DI 1 "const_int_operand" "i")
+ (match_operand:DI 2 "const_int_operand" "i"))
+ (match_operand:DI 3 "gpc_reg_operand" "r"))]
+ "TARGET_POWERPC64"
+ "*
+{
+ int start = INTVAL (operands[2]) & 63;
+ int size = INTVAL (operands[1]) & 63;
+
+ operands[2] = GEN_INT (64 - start - size);
+ return \"rldimi %0,%3,%H2,%H1\";
+}")
+
+(define_expand "extzv"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "i")
+ (match_operand:SI 3 "const_int_operand" "i")))]
+ ""
+ "
+{
+ /* Do not handle 16/8 bit structures that fit in HI/QI modes directly, since
+ the (SUBREG:SI (REG:HI xxx)) that is otherwise generated can confuse the
+ compiler if the address of the structure is taken later. */
+ if (GET_CODE (operands[0]) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (operands[0]))) < UNITS_PER_WORD))
+ FAIL;
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "i")
+ (match_operand:SI 3 "const_int_operand" "i")))]
+ ""
+ "*
+{
+ int start = INTVAL (operands[3]) & 31;
+ int size = INTVAL (operands[2]) & 31;
+
+ if (start + size >= 32)
+ operands[3] = const0_rtx;
+ else
+ operands[3] = GEN_INT (start + size);
+ return \"{rlinm|rlwinm} %0,%1,%3,%s2,31\";
+}")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i")
+ (match_operand:SI 3 "const_int_operand" "i,i"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=r,r"))]
+ ""
+ "*
+{
+ int start = INTVAL (operands[3]) & 31;
+ int size = INTVAL (operands[2]) & 31;
+
+ /* Split insn if not setting cr0. */
+ if (cc_reg_not_cr0_operand (operands[0], CCmode))
+ return \"#\";
+
+ /* If the bitfield being tested fits in the upper or lower half of a
+ word, it is possible to use andiu. or andil. to test it. This is
+ useful because the condition register set-use delay is smaller for
+ andi[ul]. than for rlinm. This doesn't work when the starting bit
+ position is 0 because the LT and GT bits may be set wrong. */
+
+ if ((start > 0 && start + size <= 16) || start >= 16)
+ {
+ operands[3] = GEN_INT (((1 << (16 - (start & 15)))
+ - (1 << (16 - (start & 15) - size))));
+ if (start < 16)
+ return \"{andiu.|andis.} %4,%1,%3\";
+ else
+ return \"{andil.|andi.} %4,%1,%3\";
+ }
+
+ if (start + size >= 32)
+ operands[3] = const0_rtx;
+ else
+ operands[3] = GEN_INT (start + size);
+ return \"{rlinm.|rlwinm.} %4,%1,%3,%s2,31\";
+}"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")
+ (match_operand:SI 3 "const_int_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 ""))]
+ "reload_completed"
+ [(set (match_dup 4)
+ (zero_extract:SI (match_dup 1)
+ (match_dup 2)
+ (match_dup 3)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 4)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i")
+ (match_operand:SI 3 "const_int_operand" "i,i"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extract:SI (match_dup 1) (match_dup 2) (match_dup 3)))]
+ ""
+ "*
+{
+ int start = INTVAL (operands[3]) & 31;
+ int size = INTVAL (operands[2]) & 31;
+
+ /* Split insn if not setting cr0. */
+ if (cc_reg_not_cr0_operand (operands[0], CCmode))
+ return \"#\";
+
+ if (start >= 16 && start + size == 32)
+ {
+ operands[3] = GEN_INT ((1 << (32 - start)) - 1);
+ return \"{andil.|andi.} %0,%1,%3\";
+ }
+
+ if (start + size >= 32)
+ operands[3] = const0_rtx;
+ else
+ operands[3] = GEN_INT (start + size);
+ return \"{rlinm.|rlwinm.} %0,%1,%3,%s2,31\";
+}"
+ [(set_attr "type" "delayed_compare")])
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")
+ (match_operand:SI 3 "const_int_operand" ""))
+ (const_int 0)))
+ (set (match_dup 0)
+ (zero_extract:SI (match_dup 1)
+ (match_dup 2)
+ (match_dup 3)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (zero_extract:SI (match_dup 1)
+ (match_dup 2)
+ (match_dup 3)))
+ (set (match_dup 4)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "const_int_operand" "i")
+ (match_operand:DI 3 "const_int_operand" "i")))]
+ "TARGET_POWERPC64"
+ "*
+{
+ int start = INTVAL (operands[3]) & 63;
+ int size = INTVAL (operands[2]) & 63;
+
+ if (start + size >= 64)
+ operands[3] = const0_rtx;
+ else
+ operands[3] = GEN_INT (start + size);
+ operands[2] = GEN_INT (64 - size);
+ return \"rldicl %0,%1,%3,%2\";
+}")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "gpc_reg_operand" "=x,?y")
+ (compare:CC (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "const_int_operand" "i,i")
+ (match_operand:DI 3 "const_int_operand" "i,i"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 4 "=r,r"))]
+ "TARGET_POWERPC64"
+ "*
+{
+ int start = INTVAL (operands[3]) & 63;
+ int size = INTVAL (operands[2]) & 63;
+
+ /* Split insn if not setting cr0. */
+ if (cc_reg_not_cr0_operand (operands[0], CCmode))
+ return \"#\";
+
+ if (start + size >= 64)
+ operands[3] = const0_rtx;
+ else
+ operands[3] = GEN_INT (start + size);
+ operands[2] = GEN_INT (64 - size);
+ return \"rldicl. %4,%1,%3,%2\";
+}")
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "const_int_operand" "")
+ (match_operand:DI 3 "const_int_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 4 ""))]
+ "reload_completed"
+ [(set (match_dup 4)
+ (zero_extract:DI (match_dup 1)
+ (match_dup 2)
+ (match_dup 3)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 4)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 4 "gpc_reg_operand" "=x,?y")
+ (compare:CC (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "const_int_operand" "i,i")
+ (match_operand:DI 3 "const_int_operand" "i,i"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extract:DI (match_dup 1) (match_dup 2) (match_dup 3)))]
+ "TARGET_POWERPC64"
+ "*
+{
+ int start = INTVAL (operands[3]) & 63;
+ int size = INTVAL (operands[2]) & 63;
+
+ /* Split insn if not setting cr0. */
+ if (cc_reg_not_cr0_operand (operands[0], CCmode))
+ return \"#\";
+
+ if (start + size >= 64)
+ operands[3] = const0_rtx;
+ else
+ operands[3] = GEN_INT (start + size);
+ operands[2] = GEN_INT (64 - size);
+ return \"rldicl. %0,%1,%3,%2\";
+}")
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "const_int_operand" "")
+ (match_operand:DI 3 "const_int_operand" ""))
+ (const_int 0)))
+ (set (match_dup 0)
+ (zero_extract:DI (match_dup 1)
+ (match_dup 2)
+ (match_dup 3)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (zero_extract:DI (match_dup 1)
+ (match_dup 2)
+ (match_dup 3)))
+ (set (match_dup 4)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "rotlsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri")))]
+ ""
+ "{rl%I2nm|rlw%I2nm} %0,%1,%h2,0xffffffff")
+
+(define_insn "*rotlsi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ {rl%I2nm.|rlw%I2nm.} %3,%1,%h2,0xffffffff
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (rotate:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotlsi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (rotate:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ {rl%I2nm.|rlw%I2nm.} %0,%1,%h2,0xffffffff
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (rotate:SI (match_dup 1)
+ (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (rotate:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotlsi3_internal4"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (and:SI (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri"))
+ (match_operand:SI 3 "mask_operand" "L")))]
+ ""
+ "{rl%I2nm|rlw%I2nm} %0,%1,%h2,%m3,%M3")
+
+(define_insn "*rotlsi3_internal5"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:SI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (match_operand:SI 3 "mask_operand" "L,L"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=r,r"))]
+ ""
+ "@
+ {rl%I2nm.|rlw%I2nm.} %4,%1,%h2,%m3,%M3
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:SI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (match_operand:SI 3 "mask_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 ""))]
+ "reload_completed"
+ [(set (match_dup 4)
+ (and:SI (rotate:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 4)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotlsi3_internal6"
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:SI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (match_operand:SI 3 "mask_operand" "L,L"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (and:SI (rotate:SI (match_dup 1) (match_dup 2)) (match_dup 3)))]
+ ""
+ "@
+ {rl%I2nm.|rlw%I2nm.} %0,%1,%h2,%m3,%M3
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:SI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (match_operand:SI 3 "mask_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (and:SI
+ (rotate:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (and:SI (rotate:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))
+ (set (match_dup 4)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotlsi3_internal7"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (zero_extend:SI
+ (subreg:QI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri")) 0)))]
+ ""
+ "{rl%I2nm|rlw%I2nm} %0,%1,%h2,0xff")
+
+(define_insn "*rotlsi3_internal8"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:SI
+ (subreg:QI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ {rl%I2nm.|rlw%I2nm.} %3,%1,%h2,0xff
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:SI
+ (subreg:QI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (zero_extend:SI
+ (subreg:QI
+ (rotate:SI (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotlsi3_internal9"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:SI
+ (subreg:QI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (subreg:QI (rotate:SI (match_dup 1) (match_dup 2)) 0)))]
+ ""
+ "@
+ {rl%I2nm.|rlw%I2nm.} %0,%1,%h2,0xff
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "=x,?y")
+ (compare:CC (zero_extend:SI
+ (subreg:QI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (subreg:QI (rotate:SI (match_dup 1) (match_dup 2)) 0)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:SI
+ (subreg:QI
+ (rotate:SI (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotlsi3_internal10"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (zero_extend:SI
+ (subreg:HI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri")) 0)))]
+ ""
+ "{rl%I2nm|rlw%I2nm} %0,%1,%h2,0xffff")
+
+(define_insn "*rotlsi3_internal11"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:SI
+ (subreg:HI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ ""
+ "@
+ {rl%I2nm.|rlw%I2nm.} %3,%1,%h2,0xffff
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:SI
+ (subreg:HI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (zero_extend:SI
+ (subreg:HI
+ (rotate:SI (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotlsi3_internal12"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:SI
+ (subreg:HI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (subreg:HI (rotate:SI (match_dup 1) (match_dup 2)) 0)))]
+ ""
+ "@
+ {rl%I2nm.|rlw%I2nm.} %0,%1,%h2,0xffff
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "=x,?y")
+ (compare:CC (zero_extend:SI
+ (subreg:HI
+ (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (subreg:QI (rotate:SI (match_dup 1) (match_dup 2)) 0)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:SI
+ (subreg:HI
+ (rotate:SI (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; Note that we use "sle." instead of "sl." so that we can set
+;; SHIFT_COUNT_TRUNCATED.
+
+(define_expand "ashlsi3"
+ [(use (match_operand:SI 0 "gpc_reg_operand" ""))
+ (use (match_operand:SI 1 "gpc_reg_operand" ""))
+ (use (match_operand:SI 2 "reg_or_cint_operand" ""))]
+ ""
+ "
+{
+ if (TARGET_POWER)
+ emit_insn (gen_ashlsi3_power (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_ashlsi3_no_power (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "ashlsi3_power"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,i")))
+ (clobber (match_scratch:SI 3 "=q,X"))]
+ "TARGET_POWER"
+ "@
+ sle %0,%1,%2
+ {sli|slwi} %0,%1,%h2"
+ [(set_attr "length" "8")])
+
+(define_insn "ashlsi3_no_power"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri")))]
+ "! TARGET_POWER"
+ "{sl|slw}%I2 %0,%1,%h2"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r,r,r"))
+ (clobber (match_scratch:SI 4 "=q,X,q,X"))]
+ "TARGET_POWER"
+ "@
+ sle. %3,%1,%2
+ {sli.|slwi.} %3,%1,%h2
+ #
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,4,8,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (match_scratch:SI 4 ""))]
+ "TARGET_POWER && reload_completed"
+ [(parallel [(set (match_dup 3)
+ (ashift:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "! TARGET_POWER"
+ "@
+ {sl|slw}%I2. %3,%1,%h2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "! TARGET_POWER && reload_completed"
+ [(set (match_dup 3)
+ (ashift:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (ashift:SI (match_dup 1) (match_dup 2)))
+ (clobber (match_scratch:SI 4 "=q,X,q,X"))]
+ "TARGET_POWER"
+ "@
+ sle. %0,%1,%2
+ {sli.|slwi.} %0,%1,%h2
+ #
+ #"
+ [(set_attr "type" "delayed_compare")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ashift:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:SI 4 ""))]
+ "TARGET_POWER && reload_completed"
+ [(parallel [(set (match_dup 0)
+ (ashift:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ashift:SI (match_dup 1) (match_dup 2)))]
+ "! TARGET_POWER"
+ "{sl|slw}%I2. %0,%1,%h2"
+ [(set_attr "type" "delayed_compare")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ashift:SI (match_dup 1)
+ (match_dup 2)))]
+ "! TARGET_POWER && reload_completed"
+ [(set (match_dup 0)
+ (ashift:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (match_operand:SI 3 "mask_operand" "L")))]
+ "includes_lshift_p (operands[2], operands[3])"
+ "{rlinm|rlwinm} %0,%1,%h2,%m3,%M3")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i"))
+ (match_operand:SI 3 "mask_operand" "L,L"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=r,r"))]
+ "includes_lshift_p (operands[2], operands[3])"
+ "@
+ {rlinm.|rlwinm.} %4,%1,%h2,%m3,%M3
+ #"
+ [(set_attr "type" "delayed_compare")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" ""))
+ (match_operand:SI 3 "mask_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 ""))]
+ "reload_completed && includes_lshift_p (operands[2], operands[3])"
+ [(set (match_dup 4)
+ (and:SI (ashift:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 4)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i"))
+ (match_operand:SI 3 "mask_operand" "L,L"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (and:SI (ashift:SI (match_dup 1) (match_dup 2)) (match_dup 3)))]
+ "includes_lshift_p (operands[2], operands[3])"
+ "@
+ {rlinm.|rlwinm.} %0,%1,%h2,%m3,%M3
+ #"
+ [(set_attr "type" "delayed_compare")])
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" ""))
+ (match_operand:SI 3 "mask_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (and:SI (ashift:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))]
+ "reload_completed && includes_lshift_p (operands[2], operands[3])"
+ [(set (match_dup 4)
+ (and:SI (ashift:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 4)
+ (const_int 0)))]
+ "")
+
+;; The AIX assembler mis-handles "sri x,x,0", so write that case as
+;; "sli x,x,0".
+(define_expand "lshrsi3"
+ [(use (match_operand:SI 0 "gpc_reg_operand" ""))
+ (use (match_operand:SI 1 "gpc_reg_operand" ""))
+ (use (match_operand:SI 2 "reg_or_cint_operand" ""))]
+ ""
+ "
+{
+ if (TARGET_POWER)
+ emit_insn (gen_lshrsi3_power (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_lshrsi3_no_power (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "lshrsi3_power"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r")
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,O,i")))
+ (clobber (match_scratch:SI 3 "=q,X,X"))]
+ "TARGET_POWER"
+ "@
+ sre %0,%1,%2
+ mr %0,%1
+ {s%A2i|s%A2wi} %0,%1,%h2")
+
+(define_insn "lshrsi3_no_power"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "O,ri")))]
+ "! TARGET_POWER"
+ "@
+ mr %0,%1
+ {sr|srw}%I2 %0,%1,%h2")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,?y,y,?y")
+ (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,O,i,r,O,i"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,X,r,r,X,r"))
+ (clobber (match_scratch:SI 4 "=q,X,X,q,X,X"))]
+ "TARGET_POWER"
+ "@
+ sre. %3,%1,%2
+ mr. %1,%1
+ {s%A2i.|s%A2wi.} %3,%1,%h2
+ #
+ cmpli %0,%1,0
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,4,4,8,8,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (match_scratch:SI 4 ""))]
+ "TARGET_POWER && reload_completed
+ && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)"
+ [(parallel [(set (match_dup 3)
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,y,?y")
+ (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "O,ri,O,ri"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=X,r,X,r"))]
+ "! TARGET_POWER"
+ "@
+ mr. %1,%1
+ {sr|srw}%I2. %3,%1,%h2
+ cmpli %0,%1,0
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,4,4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "! TARGET_POWER && reload_completed
+ && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)"
+ [(set (match_dup 3)
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,?y")
+ (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,O,i,rOi"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (lshiftrt:SI (match_dup 1) (match_dup 2)))
+ (clobber (match_scratch:SI 4 "=q,X,X,q"))]
+ "TARGET_POWER"
+ "@
+ sre. %0,%1,%2
+ mr. %0,%1
+ {s%A2i.|s%A2wi.} %0,%1,%h2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,4,4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:SI 4 ""))]
+ "TARGET_POWER && reload_completed"
+ [(parallel [(set (match_dup 3)
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "O,ri,O,ri"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (lshiftrt:SI (match_dup 1) (match_dup 2)))]
+ "! TARGET_POWER"
+ "@
+ mr. %0,%1
+ {sr|srw}%I2. %0,%1,%h2
+ #
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,4,8,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)))]
+ "! TARGET_POWER && reload_completed"
+ [(set (match_dup 0)
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (match_operand:SI 3 "mask_operand" "L")))]
+ "includes_rshift_p (operands[2], operands[3])"
+ "{rlinm|rlwinm} %0,%1,%s2,%m3,%M3")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i"))
+ (match_operand:SI 3 "mask_operand" "L,L"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=r,r"))]
+ "includes_rshift_p (operands[2], operands[3])"
+ "@
+ {rlinm.|rlwinm.} %4,%1,%s2,%m3,%M3
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" ""))
+ (match_operand:SI 3 "mask_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 ""))]
+ "reload_completed && includes_rshift_p (operands[2], operands[3])"
+ [(set (match_dup 4)
+ (and:SI (lshiftrt:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 4)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i"))
+ (match_operand:SI 3 "mask_operand" "L,L"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (and:SI (lshiftrt:SI (match_dup 1) (match_dup 2)) (match_dup 3)))]
+ "includes_rshift_p (operands[2], operands[3])"
+ "@
+ {rlinm.|rlwinm.} %0,%1,%s2,%m3,%M3
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" ""))
+ (match_operand:SI 3 "mask_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (and:SI (lshiftrt:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))]
+ "reload_completed && includes_rshift_p (operands[2], operands[3])"
+ [(set (match_dup 4)
+ (and:SI (lshiftrt:SI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 4)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (zero_extend:SI
+ (subreg:QI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "i")) 0)))]
+ "includes_rshift_p (operands[2], GEN_INT (255))"
+ "{rlinm|rlwinm} %0,%1,%s2,0xff")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (zero_extend:SI
+ (subreg:QI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "includes_rshift_p (operands[2], GEN_INT (255))"
+ "@
+ {rlinm.|rlwinm.} %3,%1,%s2,0xff
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (zero_extend:SI
+ (subreg:QI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed && includes_rshift_p (operands[2], GEN_INT (255))"
+ [(set (match_dup 3)
+ (zero_extend:SI
+ (subreg:QI
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (zero_extend:SI
+ (subreg:QI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i")) 0))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (subreg:QI (lshiftrt:SI (match_dup 1) (match_dup 2)) 0)))]
+ "includes_rshift_p (operands[2], GEN_INT (255))"
+ "@
+ {rlinm.|rlwinm.} %0,%1,%s2,0xff
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (zero_extend:SI
+ (subreg:QI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")) 0))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (zero_extend:SI
+ (subreg:QI
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)) 0)))]
+ "reload_completed && includes_rshift_p (operands[2], GEN_INT (255))"
+ [(set (match_dup 0)
+ (zero_extend:SI
+ (subreg:QI
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (zero_extend:SI
+ (subreg:HI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "i")) 0)))]
+ "includes_rshift_p (operands[2], GEN_INT (65535))"
+ "{rlinm|rlwinm} %0,%1,%s2,0xffff")
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (zero_extend:SI
+ (subreg:HI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed && includes_rshift_p (operands[2], GEN_INT (255))"
+ [(set (match_dup 3)
+ (zero_extend:SI
+ (subreg:HI
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (zero_extend:SI
+ (subreg:HI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "includes_rshift_p (operands[2], GEN_INT (65535))"
+ "@
+ {rlinm.|rlwinm.} %3,%1,%s2,0xffff
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (zero_extend:SI
+ (subreg:HI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "i,i")) 0))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI (subreg:HI (lshiftrt:SI (match_dup 1) (match_dup 2)) 0)))]
+ "includes_rshift_p (operands[2], GEN_INT (65535))"
+ "{rlinm.|rlwinm.} %0,%1,%s2,0xffff"
+ [(set_attr "type" "delayed_compare")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC
+ (zero_extend:SI
+ (subreg:HI
+ (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")) 0))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (zero_extend:SI
+ (subreg:HI
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)) 0)))]
+ "reload_completed && includes_rshift_p (operands[2], GEN_INT (255))"
+ [(set (match_dup 0)
+ (zero_extend:SI
+ (subreg:HI
+ (lshiftrt:SI (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (const_int 1)
+ (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (ashiftrt:SI (match_operand:SI 2 "gpc_reg_operand" "r")
+ (const_int 31)))]
+ "TARGET_POWER"
+ "rrib %0,%1,%2")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (const_int 1)
+ (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (lshiftrt:SI (match_operand:SI 2 "gpc_reg_operand" "r")
+ (const_int 31)))]
+ "TARGET_POWER"
+ "rrib %0,%1,%2")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (const_int 1)
+ (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (zero_extract:SI (match_operand:SI 2 "gpc_reg_operand" "r")
+ (const_int 1)
+ (const_int 0)))]
+ "TARGET_POWER"
+ "rrib %0,%1,%2")
+
+(define_expand "ashrsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ ""
+ "
+{
+ if (TARGET_POWER)
+ emit_insn (gen_ashrsi3_power (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_ashrsi3_no_power (operands[0], operands[1], operands[2]));
+ DONE;
+}")
+
+(define_insn "ashrsi3_power"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,i")))
+ (clobber (match_scratch:SI 3 "=q,X"))]
+ "TARGET_POWER"
+ "@
+ srea %0,%1,%2
+ {srai|srawi} %0,%1,%h2")
+
+(define_insn "ashrsi3_no_power"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri")))]
+ "! TARGET_POWER"
+ "{sra|sraw}%I2 %0,%1,%h2")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r,r,r"))
+ (clobber (match_scratch:SI 4 "=q,X,q,X"))]
+ "TARGET_POWER"
+ "@
+ srea. %3,%1,%2
+ {srai.|srawi.} %3,%1,%h2
+ #
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,4,8,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))
+ (clobber (match_scratch:SI 4 ""))]
+ "TARGET_POWER && reload_completed"
+ [(parallel [(set (match_dup 3)
+ (ashiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "! TARGET_POWER"
+ "@
+ {sra|sraw}%I2. %3,%1,%h2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (ashiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (ashiftrt:SI (match_dup 1) (match_dup 2)))
+ (clobber (match_scratch:SI 4 "=q,X,q,X"))]
+ "TARGET_POWER"
+ "@
+ srea. %0,%1,%2
+ {srai.|srawi.} %0,%1,%h2
+ #
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,4,8,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ashiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:SI 4 ""))]
+ "TARGET_POWER && reload_completed"
+ [(parallel [(set (match_dup 0)
+ (ashiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ashiftrt:SI (match_dup 1) (match_dup 2)))]
+ "! TARGET_POWER"
+ "@
+ {sra|sraw}%I2. %0,%1,%h2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ashiftrt:SI (match_dup 1)
+ (match_dup 2)))]
+ "! TARGET_POWER && reload_completed"
+ [(set (match_dup 0)
+ (ashiftrt:SI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; Floating-point insns, excluding normal data motion.
+;;
+;; PowerPC has a full set of single-precision floating point instructions.
+;;
+;; For the POWER architecture, we pretend that we have both SFmode and
+;; DFmode insns, while, in fact, all fp insns are actually done in double.
+;; The only conversions we will do will be when storing to memory. In that
+;; case, we will use the "frsp" instruction before storing.
+;;
+;; Note that when we store into a single-precision memory location, we need to
+;; use the frsp insn first. If the register being stored isn't dead, we
+;; need a scratch register for the frsp. But this is difficult when the store
+;; is done by reload. It is not incorrect to do the frsp on the register in
+;; this case, we just lose precision that we would have otherwise gotten but
+;; is not guaranteed. Perhaps this should be tightened up at some point.
+
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (float_extend:DF (match_operand:SF 1 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "*
+{
+ if (REGNO (operands[0]) == REGNO (operands[1]))
+ return \"\";
+ else
+ return \"fmr %0,%1\";
+}"
+ [(set_attr "type" "fp")])
+
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (float_truncate:SF (match_operand:DF 1 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "frsp %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn "aux_truncdfsf2"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] 0))]
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "frsp %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (neg:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "fneg %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (abs:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "fabs %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (neg:SF (abs:SF (match_operand:SF 1 "gpc_reg_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "fnabs %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_expand "addsf3"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (plus:SF (match_operand:SF 1 "gpc_reg_operand" "")
+ (match_operand:SF 2 "gpc_reg_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (plus:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f")))]
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "fadds %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (plus:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f")))]
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "{fa|fadd} %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_expand "subsf3"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (minus:SF (match_operand:SF 1 "gpc_reg_operand" "")
+ (match_operand:SF 2 "gpc_reg_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (minus:SF (match_operand:SF 1 "gpc_reg_operand" "f")
+ (match_operand:SF 2 "gpc_reg_operand" "f")))]
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "fsubs %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (minus:SF (match_operand:SF 1 "gpc_reg_operand" "f")
+ (match_operand:SF 2 "gpc_reg_operand" "f")))]
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "{fs|fsub} %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_expand "mulsf3"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (mult:SF (match_operand:SF 1 "gpc_reg_operand" "")
+ (match_operand:SF 2 "gpc_reg_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f")))]
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "fmuls %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f")))]
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "{fm|fmul} %0,%1,%2"
+ [(set_attr "type" "dmul")])
+
+(define_expand "divsf3"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (div:SF (match_operand:SF 1 "gpc_reg_operand" "")
+ (match_operand:SF 2 "gpc_reg_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (div:SF (match_operand:SF 1 "gpc_reg_operand" "f")
+ (match_operand:SF 2 "gpc_reg_operand" "f")))]
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "fdivs %0,%1,%2"
+ [(set_attr "type" "sdiv")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (div:SF (match_operand:SF 1 "gpc_reg_operand" "f")
+ (match_operand:SF 2 "gpc_reg_operand" "f")))]
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "{fd|fdiv} %0,%1,%2"
+ [(set_attr "type" "ddiv")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f"))
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "fmadds %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f"))
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "{fma|fmadd} %0,%1,%2,%3"
+ [(set_attr "type" "dmul")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f"))
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "fmsubs %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f"))
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "{fms|fmsub} %0,%1,%2,%3"
+ [(set_attr "type" "dmul")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f"))
+ (match_operand:SF 3 "gpc_reg_operand" "f"))))]
+ "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "fnmadds %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f"))
+ (match_operand:SF 3 "gpc_reg_operand" "f"))))]
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "{fnma|fnmadd} %0,%1,%2,%3"
+ [(set_attr "type" "dmul")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (neg:SF (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f"))
+ (match_operand:SF 3 "gpc_reg_operand" "f"))))]
+ "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "fnmsubs %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (neg:SF (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
+ (match_operand:SF 2 "gpc_reg_operand" "f"))
+ (match_operand:SF 3 "gpc_reg_operand" "f"))))]
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "{fnms|fnmsub} %0,%1,%2,%3"
+ [(set_attr "type" "dmul")])
+
+(define_expand "sqrtsf2"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "")))]
+ "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT"
+ "")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GPOPT && TARGET_HARD_FLOAT"
+ "fsqrts %0,%1"
+ [(set_attr "type" "ssqrt")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
+ "TARGET_POWER2 && TARGET_HARD_FLOAT"
+ "fsqrt %0,%1"
+ [(set_attr "type" "dsqrt")])
+
+;; For MIN, MAX, and conditional move, we use DEFINE_EXPAND's that involve a
+;; fsel instruction and some auxiliary computations. Then we just have a
+;; single DEFINE_INSN for fsel and the define_splits to make them if made by
+;; combine.
+(define_expand "maxsf3"
+ [(set (match_dup 3)
+ (minus:SF (match_operand:SF 1 "gpc_reg_operand" "")
+ (match_operand:SF 2 "gpc_reg_operand" "")))
+ (set (match_operand:SF 0 "gpc_reg_operand" "")
+ (if_then_else:SF (ge (match_dup 3)
+ (const_int 0))
+ (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "
+{ operands[3] = gen_reg_rtx (SFmode); }")
+
+(define_split
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (smax:SF (match_operand:SF 1 "gpc_reg_operand" "")
+ (match_operand:SF 2 "gpc_reg_operand" "")))
+ (clobber (match_operand:SF 3 "gpc_reg_operand" ""))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ [(set (match_dup 3)
+ (minus:SF (match_dup 1) (match_dup 2)))
+ (set (match_dup 0)
+ (if_then_else:SF (ge (match_dup 3)
+ (const_int 0))
+ (match_dup 1)
+ (match_dup 2)))]
+ "")
+
+(define_expand "minsf3"
+ [(set (match_dup 3)
+ (minus:SF (match_operand:SF 2 "gpc_reg_operand" "")
+ (match_operand:SF 1 "gpc_reg_operand" "")))
+ (set (match_operand:SF 0 "gpc_reg_operand" "")
+ (if_then_else:SF (ge (match_dup 3)
+ (const_int 0))
+ (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "
+{ operands[3] = gen_reg_rtx (SFmode); }")
+
+(define_split
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (smin:SF (match_operand:SF 1 "gpc_reg_operand" "")
+ (match_operand:SF 2 "gpc_reg_operand" "")))
+ (clobber (match_operand:SF 3 "gpc_reg_operand" ""))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ [(set (match_dup 3)
+ (minus:SF (match_dup 2) (match_dup 1)))
+ (set (match_dup 0)
+ (if_then_else:SF (ge (match_dup 3)
+ (const_int 0))
+ (match_dup 1)
+ (match_dup 2)))]
+ "")
+
+(define_expand "movsfcc"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (if_then_else:SF (match_operand 1 "comparison_operator" "")
+ (match_operand:SF 2 "gpc_reg_operand" "f")
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "
+{
+ rtx temp, op0, op1;
+ enum rtx_code code = GET_CODE (operands[1]);
+ if (! rs6000_compare_fp_p)
+ FAIL;
+ switch (code)
+ {
+ case GE: case EQ: case NE:
+ op0 = rs6000_compare_op0;
+ op1 = rs6000_compare_op1;
+ break;
+ case GT:
+ op0 = rs6000_compare_op1;
+ op1 = rs6000_compare_op0;
+ temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+ break;
+ case LE:
+ op0 = rs6000_compare_op1;
+ op1 = rs6000_compare_op0;
+ break;
+ case LT:
+ op0 = rs6000_compare_op0;
+ op1 = rs6000_compare_op1;
+ temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+ break;
+ default:
+ FAIL;
+ }
+ if (GET_MODE (rs6000_compare_op0) == DFmode)
+ {
+ temp = gen_reg_rtx (DFmode);
+ emit_insn (gen_subdf3 (temp, op0, op1));
+ emit_insn (gen_fseldfsf4 (operands[0], temp, operands[2], operands[3]));
+ if (code == EQ)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfsf4 (operands[0], temp, operands[0], operands[3]));
+ }
+ else if (code == NE)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfsf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ else
+ {
+ temp = gen_reg_rtx (SFmode);
+ emit_insn (gen_subsf3 (temp, op0, op1));
+ emit_insn (gen_fselsfsf4 (operands[0], temp, operands[2], operands[3]));
+ if (code == EQ)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfsf4 (operands[0], temp, operands[0], operands[3]));
+ }
+ else if (code == NE)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfsf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ DONE;
+}")
+
+(define_insn "fselsfsf4"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (if_then_else:SF (ge (match_operand:SF 1 "gpc_reg_operand" "f")
+ (const_int 0))
+ (match_operand:SF 2 "gpc_reg_operand" "f")
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "fsel %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+(define_insn "fseldfsf4"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (if_then_else:SF (ge (match_operand:DF 1 "gpc_reg_operand" "f")
+ (const_int 0))
+ (match_operand:SF 2 "gpc_reg_operand" "f")
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "fsel %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+(define_insn "negdf2"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (neg:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "fneg %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn "absdf2"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (abs:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "fabs %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (neg:DF (abs:DF (match_operand:DF 1 "gpc_reg_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "fnabs %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (plus:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
+ (match_operand:DF 2 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "{fa|fadd} %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (minus:DF (match_operand:DF 1 "gpc_reg_operand" "f")
+ (match_operand:DF 2 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "{fs|fsub} %0,%1,%2"
+ [(set_attr "type" "fp")])
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
+ (match_operand:DF 2 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "{fm|fmul} %0,%1,%2"
+ [(set_attr "type" "dmul")])
+
+(define_insn "divdf3"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (div:DF (match_operand:DF 1 "gpc_reg_operand" "f")
+ (match_operand:DF 2 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "{fd|fdiv} %0,%1,%2"
+ [(set_attr "type" "ddiv")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (plus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
+ (match_operand:DF 2 "gpc_reg_operand" "f"))
+ (match_operand:DF 3 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "{fma|fmadd} %0,%1,%2,%3"
+ [(set_attr "type" "dmul")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (minus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
+ (match_operand:DF 2 "gpc_reg_operand" "f"))
+ (match_operand:DF 3 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "{fms|fmsub} %0,%1,%2,%3"
+ [(set_attr "type" "dmul")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (neg:DF (plus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
+ (match_operand:DF 2 "gpc_reg_operand" "f"))
+ (match_operand:DF 3 "gpc_reg_operand" "f"))))]
+ "TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "{fnma|fnmadd} %0,%1,%2,%3"
+ [(set_attr "type" "dmul")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (neg:DF (minus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
+ (match_operand:DF 2 "gpc_reg_operand" "f"))
+ (match_operand:DF 3 "gpc_reg_operand" "f"))))]
+ "TARGET_HARD_FLOAT && TARGET_FUSED_MADD"
+ "{fnms|fnmsub} %0,%1,%2,%3"
+ [(set_attr "type" "dmul")])
+
+(define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
+ "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT"
+ "fsqrt %0,%1"
+ [(set_attr "type" "dsqrt")])
+
+;; For MIN, MAX, and conditional move, we use DEFINE_EXPAND's that involve a
+;; fsel instruction and some auxiliary computations. Then we just have a
+;; single DEFINE_INSN for fsel and the define_splits to make them if made by
+;; combine.
+
+(define_expand "maxdf3"
+ [(set (match_dup 3)
+ (minus:DF (match_operand:DF 1 "gpc_reg_operand" "")
+ (match_operand:DF 2 "gpc_reg_operand" "")))
+ (set (match_operand:DF 0 "gpc_reg_operand" "")
+ (if_then_else:DF (ge (match_dup 3)
+ (const_int 0))
+ (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "
+{ operands[3] = gen_reg_rtx (DFmode); }")
+
+(define_split
+ [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (smax:DF (match_operand:DF 1 "gpc_reg_operand" "")
+ (match_operand:DF 2 "gpc_reg_operand" "")))
+ (clobber (match_operand:DF 3 "gpc_reg_operand" ""))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ [(set (match_dup 3)
+ (minus:DF (match_dup 1) (match_dup 2)))
+ (set (match_dup 0)
+ (if_then_else:DF (ge (match_dup 3)
+ (const_int 0))
+ (match_dup 1)
+ (match_dup 2)))]
+ "")
+
+(define_expand "mindf3"
+ [(set (match_dup 3)
+ (minus:DF (match_operand:DF 2 "gpc_reg_operand" "")
+ (match_operand:DF 1 "gpc_reg_operand" "")))
+ (set (match_operand:DF 0 "gpc_reg_operand" "")
+ (if_then_else:DF (ge (match_dup 3)
+ (const_int 0))
+ (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "
+{ operands[3] = gen_reg_rtx (DFmode); }")
+
+(define_split
+ [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (smin:DF (match_operand:DF 1 "gpc_reg_operand" "")
+ (match_operand:DF 2 "gpc_reg_operand" "")))
+ (clobber (match_operand:DF 3 "gpc_reg_operand" ""))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ [(set (match_dup 3)
+ (minus:DF (match_dup 2) (match_dup 1)))
+ (set (match_dup 0)
+ (if_then_else:DF (ge (match_dup 3)
+ (const_int 0))
+ (match_dup 1)
+ (match_dup 2)))]
+ "")
+
+(define_expand "movdfcc"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (if_then_else:DF (match_operand 1 "comparison_operator" "")
+ (match_operand:DF 2 "gpc_reg_operand" "f")
+ (match_operand:DF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "
+{
+ rtx temp, op0, op1;
+ enum rtx_code code = GET_CODE (operands[1]);
+ if (! rs6000_compare_fp_p)
+ FAIL;
+ switch (code)
+ {
+ case GE: case EQ: case NE:
+ op0 = rs6000_compare_op0;
+ op1 = rs6000_compare_op1;
+ break;
+ case GT:
+ op0 = rs6000_compare_op1;
+ op1 = rs6000_compare_op0;
+ temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+ break;
+ case LE:
+ op0 = rs6000_compare_op1;
+ op1 = rs6000_compare_op0;
+ break;
+ case LT:
+ op0 = rs6000_compare_op0;
+ op1 = rs6000_compare_op1;
+ temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+ break;
+ default:
+ FAIL;
+ }
+ if (GET_MODE (rs6000_compare_op0) == DFmode)
+ {
+ temp = gen_reg_rtx (DFmode);
+ emit_insn (gen_subdf3 (temp, op0, op1));
+ emit_insn (gen_fseldfdf4 (operands[0], temp, operands[2], operands[3]));
+ if (code == EQ)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfdf4 (operands[0], temp, operands[0], operands[3]));
+ }
+ else if (code == NE)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfdf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ else
+ {
+ temp = gen_reg_rtx (SFmode);
+ emit_insn (gen_subsf3 (temp, op0, op1));
+ emit_insn (gen_fselsfdf4 (operands[0], temp, operands[2], operands[3]));
+ if (code == EQ)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfdf4 (operands[0], temp, operands[0], operands[3]));
+ }
+ else if (code == NE)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfdf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ DONE;
+}")
+
+(define_insn "fseldfdf4"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "f")
+ (const_int 0))
+ (match_operand:DF 2 "gpc_reg_operand" "f")
+ (match_operand:DF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "fsel %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+(define_insn "fselsfdf4"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (if_then_else:DF (ge (match_operand:SF 1 "gpc_reg_operand" "f")
+ (const_int 0))
+ (match_operand:DF 2 "gpc_reg_operand" "f")
+ (match_operand:DF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT"
+ "fsel %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+;; Conversions to and from floating-point.
+
+(define_expand "floatsidf2"
+ [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (use (match_dup 2))
+ (use (match_dup 3))
+ (clobber (match_dup 4))
+ (clobber (match_dup 5))
+ (clobber (reg:DF 76))])]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ operands[2] = force_reg (SImode, GEN_INT (0x43300000));
+ operands[3] = force_reg (DFmode, rs6000_float_const (\"4503601774854144\", DFmode));
+ operands[4] = gen_reg_rtx (SImode);
+ operands[5] = gen_reg_rtx (Pmode);
+}")
+
+(define_insn "*floatsidf2_internal"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=&f")
+ (float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
+ (use (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (use (match_operand:DF 3 "gpc_reg_operand" "f"))
+ (clobber (match_operand:SI 4 "gpc_reg_operand" "=r"))
+ (clobber (match_operand 5 "gpc_reg_operand" "=b"))
+ (clobber (reg:DF 76))]
+ "TARGET_HARD_FLOAT"
+ "#"
+ [(set_attr "length" "24")])
+
+(define_split
+ [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (use (match_operand:SI 2 "gpc_reg_operand" ""))
+ (use (match_operand:DF 3 "gpc_reg_operand" ""))
+ (clobber (match_operand:SI 4 "gpc_reg_operand" ""))
+ (clobber (match_operand 5 "gpc_reg_operand" ""))
+ (clobber (reg:DF 76))]
+ "TARGET_HARD_FLOAT"
+ [(set (match_dup 4)
+ (xor:SI (match_dup 1)
+ (match_dup 6)))
+ (set (match_dup 5)
+ (unspec [(const_int 0)] 11))
+ (set (match_dup 7)
+ (unspec [(match_dup 4)
+ (match_dup 5)] 12)) ;; low word
+ (set (match_dup 7)
+ (unspec [(match_dup 2)
+ (match_dup 5)
+ (match_dup 7)] 13)) ;; high word
+ (set (match_dup 0)
+ (unspec [(match_dup 7)
+ (match_dup 5)] 14))
+ (set (match_dup 0)
+ (minus:DF (match_dup 0)
+ (match_dup 3)))]
+ "
+{
+ operands[6] = GEN_INT (0x80000000);
+ operands[7] = gen_rtx_REG (DFmode, FPMEM_REGNUM);
+}")
+
+(define_expand "floatunssidf2"
+ [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (use (match_dup 2))
+ (use (match_dup 3))
+ (clobber (match_dup 4))
+ (clobber (reg:DF 76))])]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ operands[2] = force_reg (SImode, GEN_INT (0x43300000));
+ operands[3] = force_reg (DFmode, rs6000_float_const (\"4503599627370496\", DFmode));
+ operands[4] = gen_reg_rtx (Pmode);
+}")
+
+(define_insn "*floatunssidf2_internal"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=&f")
+ (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
+ (use (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (use (match_operand:DF 3 "gpc_reg_operand" "f"))
+ (clobber (match_operand 4 "gpc_reg_operand" "=b"))
+ (clobber (reg:DF 76))]
+ "TARGET_HARD_FLOAT"
+ "#"
+ [(set_attr "length" "20")])
+
+(define_split
+ [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (use (match_operand:SI 2 "gpc_reg_operand" ""))
+ (use (match_operand:DF 3 "gpc_reg_operand" ""))
+ (clobber (match_operand 4 "gpc_reg_operand" ""))
+ (clobber (reg:DF 76))]
+ "TARGET_HARD_FLOAT"
+ [(set (match_dup 4)
+ (unspec [(const_int 0)] 11))
+ (set (match_dup 5)
+ (unspec [(match_dup 1)
+ (match_dup 4)] 12)) ;; low word
+ (set (match_dup 5)
+ (unspec [(match_dup 2)
+ (match_dup 4)
+ (match_dup 5)] 13)) ;; high word
+ (set (match_dup 0)
+ (unspec [(match_dup 5)
+ (match_dup 4)] 14))
+ (set (match_dup 0)
+ (minus:DF (match_dup 0)
+ (match_dup 3)))]
+ "operands[5] = gen_rtx_REG (DFmode, FPMEM_REGNUM);")
+
+;; Load up scratch register with base address + offset if needed
+(define_insn "*floatsidf2_loadaddr"
+ [(set (match_operand 0 "gpc_reg_operand" "=b")
+ (unspec [(const_int 0)] 11))]
+ "TARGET_HARD_FLOAT"
+ "*
+{
+ if (rs6000_fpmem_offset > 32760)
+ {
+ rtx xop[3];
+
+ xop[0] = operands[0];
+ xop[1] = (frame_pointer_needed) ? frame_pointer_rtx : stack_pointer_rtx;
+ xop[2] = GEN_INT ((rs6000_fpmem_offset >> 16) + ((rs6000_fpmem_offset & 0x8000) >> 15));
+ output_asm_insn (\"{cau|addis} %0,%1,%2\", xop);
+ }
+
+ return \"\";
+}"
+ [(set_attr "length" "4")])
+
+(define_insn "*floatsidf2_store1"
+ [(set (reg:DF 76)
+ (unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
+ (match_operand 1 "gpc_reg_operand" "b")] 12))]
+ "TARGET_HARD_FLOAT"
+ "*
+{
+ rtx indx;
+
+ if (rs6000_fpmem_offset > 32760)
+ indx = operands[1];
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx_MEM (SImode,
+ gen_rtx_PLUS (Pmode,
+ indx,
+ GEN_INT ((((rs6000_fpmem_offset & 0xffff) ^ 0x8000) - 0x8000)
+ + ((WORDS_BIG_ENDIAN != 0) * 4))));
+
+ return \"{st|stw} %0,%2\";
+}"
+ [(set_attr "type" "store")])
+
+(define_insn "*floatsidf2_store2"
+ [(set (reg:DF 76)
+ (unspec [(match_operand:SI 0 "gpc_reg_operand" "r")
+ (match_operand 1 "gpc_reg_operand" "b")
+ (reg:DF 76)] 13))]
+ "TARGET_HARD_FLOAT"
+ "*
+{
+ rtx indx;
+
+ if (rs6000_fpmem_offset > 32760)
+ indx = operands[1];
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx_MEM (SImode,
+ gen_rtx_PLUS (Pmode,
+ indx,
+ GEN_INT ((((rs6000_fpmem_offset & 0xffff) ^ 0x8000) - 0x8000)
+ + ((WORDS_BIG_ENDIAN == 0) * 4))));
+
+ return \"{st|stw} %0,%2\";
+}"
+ [(set_attr "type" "store")])
+
+(define_insn "*floatsidf2_load"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (unspec [(reg:DF 76)
+ (match_operand 1 "gpc_reg_operand" "b")] 14))]
+ "TARGET_HARD_FLOAT"
+ "*
+{
+ rtx indx;
+ HOST_WIDE_INT offset = rs6000_fpmem_offset;
+
+ if (rs6000_fpmem_offset > 32760)
+ {
+ indx = operands[1];
+ offset = (((offset & 0xffff) ^ 0x8000) - 0x8000);
+ }
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx_MEM (SImode,
+ gen_rtx_PLUS (Pmode, indx, GEN_INT (offset)));
+
+ return \"lfd %0,%2\";
+}"
+ [(set_attr "type" "fpload")])
+
+(define_expand "fix_truncdfsi2"
+ [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))
+ (clobber (match_dup 2))
+ (clobber (match_dup 3))
+ (clobber (match_dup 4))])]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ if (!TARGET_POWER2 && !TARGET_POWERPC)
+ {
+ emit_insn (gen_trunc_call (operands[0], operands[1],
+ gen_rtx_SYMBOL_REF (Pmode, RS6000_ITRUNC)));
+ DONE;
+ }
+
+ operands[2] = gen_reg_rtx (DImode);
+ operands[3] = gen_reg_rtx (Pmode);
+ operands[4] = gen_rtx_REG (DImode, FPMEM_REGNUM);
+}")
+
+(define_insn "*fix_truncdfsi2_internal"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
+ (clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))
+ (clobber (match_operand 3 "gpc_reg_operand" "=b"))
+ (clobber (reg:DI 76))]
+ "TARGET_HARD_FLOAT"
+ "#"
+ [(set_attr "length" "12")])
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
+ (clobber (match_operand:DI 2 "gpc_reg_operand" ""))
+ (clobber (match_operand 3 "gpc_reg_operand" ""))
+ (clobber (reg:DI 76))]
+ "TARGET_HARD_FLOAT"
+ [(set (match_dup 2)
+ (sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" ""))))
+ (set (match_dup 3)
+ (unspec [(const_int 0)] 11))
+ (set (match_dup 4)
+ (unspec [(match_dup 2)
+ (match_dup 3)] 15))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (unspec [(match_dup 4)
+ (match_dup 3)] 16))]
+ "operands[4] = gen_rtx_REG (DImode, FPMEM_REGNUM);")
+
+(define_insn "*fix_truncdfsi2_store"
+ [(set (reg:DI 76)
+ (unspec [(match_operand:DI 0 "gpc_reg_operand" "f")
+ (match_operand 1 "gpc_reg_operand" "b")] 15))]
+ "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
+ "*
+{
+ rtx indx;
+
+ if (rs6000_fpmem_offset > 32760)
+ indx = operands[1];
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx_MEM (DFmode,
+ gen_rtx_PLUS (Pmode,
+ indx,
+ GEN_INT ((((rs6000_fpmem_offset & 0xffff)
+ ^ 0x8000) - 0x8000))));
+
+ return \"stfd %0,%2\";
+}"
+ [(set_attr "type" "fpstore")])
+
+(define_insn "*fix_truncdfsi2_load"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (unspec [(reg:DI 76)
+ (match_operand 1 "gpc_reg_operand" "b")] 16))]
+ "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
+ "*
+{
+ rtx indx;
+
+ if (rs6000_fpmem_offset > 32760)
+ indx = operands[1];
+ else if (frame_pointer_needed)
+ indx = frame_pointer_rtx;
+ else
+ indx = stack_pointer_rtx;
+
+ operands[2] = gen_rtx_MEM (DFmode,
+ gen_rtx_PLUS (Pmode,
+ indx,
+ GEN_INT ((((rs6000_fpmem_offset & 0xffff) ^ 0x8000) - 0x8000)
+ + ((WORDS_BIG_ENDIAN) ? 4 : 0))));
+
+ return \"{l|lwz} %0,%2\";
+}"
+ [(set_attr "type" "load")])
+
+(define_expand "fixuns_truncdfsi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (unsigned_fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))]
+ "! TARGET_POWER2 && ! TARGET_POWERPC && TARGET_HARD_FLOAT"
+ "
+{
+ emit_insn (gen_trunc_call (operands[0], operands[1],
+ gen_rtx_SYMBOL_REF (Pmode, RS6000_UITRUNC)));
+ DONE;
+}")
+
+(define_expand "trunc_call"
+ [(parallel [(set (match_operand:SI 0 "" "")
+ (fix:SI (match_operand:DF 1 "" "")))
+ (use (match_operand:SI 2 "" ""))])]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ rtx insns = gen_trunc_call_rtl (operands[0], operands[1], operands[2]);
+ rtx first = XVECEXP (insns, 0, 0);
+ rtx last = XVECEXP (insns, 0, XVECLEN (insns, 0) - 1);
+
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
+
+ emit_insn (insns);
+ DONE;
+}")
+
+(define_expand "trunc_call_rtl"
+ [(set (reg:DF 33) (match_operand:DF 1 "gpc_reg_operand" ""))
+ (use (reg:DF 33))
+ (parallel [(set (reg:SI 3)
+ (call (mem:SI (match_operand 2 "" "")) (const_int 0)))
+ (use (const_int 0))
+ (clobber (scratch:SI))])
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (reg:SI 3))]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ rs6000_trunc_used = 1;
+}")
+
+(define_insn "*fctiwz"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
+ (sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))]
+ "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
+ "{fcirz|fctiwz} %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn "floatdidf2"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (float:DF (match_operand:DI 1 "gpc_reg_operand" "f")))]
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "fcfid %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn "fix_truncdfdi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
+ (fix:DI (match_operand:DF 1 "gpc_reg_operand" "f")))]
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT"
+ "fctidz %0,%1"
+ [(set_attr "type" "fp")])
+
+;; Define the DImode operations that can be done in a small number
+;; of instructions. The & constraints are to prevent the register
+;; allocator from allocating registers that overlap with the inputs
+;; (for example, having an input in 7,8 and an output in 6,7). We
+;; also allow for the output being the same as one of the inputs.
+
+(define_insn "*adddi3_noppc64"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,&r,r,r")
+ (plus:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,0,0")
+ (match_operand:DI 2 "reg_or_short_operand" "r,I,r,I")))]
+ "! TARGET_POWERPC64"
+ "*
+{
+ if (WORDS_BIG_ENDIAN)
+ return (GET_CODE (operands[2])) != CONST_INT
+ ? \"{a|addc} %L0,%L1,%L2\;{ae|adde} %0,%1,%2\"
+ : \"{ai|addic} %L0,%L1,%2\;{a%G2e|add%G2e} %0,%1\";
+ else
+ return (GET_CODE (operands[2])) != CONST_INT
+ ? \"{a|addc} %0,%1,%2\;{ae|adde} %L0,%L1,%L2\"
+ : \"{ai|addic} %0,%1,%2\;{a%G2e|add%G2e} %L0,%L1\";
+}"
+ [(set_attr "length" "8")])
+
+(define_insn "*subdi3_noppc64"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,&r,r,r,r")
+ (minus:DI (match_operand:DI 1 "reg_or_short_operand" "r,I,0,r,I")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r,r,0,0")))]
+ "! TARGET_POWERPC64"
+ "*
+{
+ if (WORDS_BIG_ENDIAN)
+ return (GET_CODE (operands[1]) != CONST_INT)
+ ? \"{sf|subfc} %L0,%L2,%L1\;{sfe|subfe} %0,%2,%1\"
+ : \"{sfi|subfic} %L0,%L2,%1\;{sf%G1e|subf%G1e} %0,%2\";
+ else
+ return (GET_CODE (operands[1]) != CONST_INT)
+ ? \"{sf|subfc} %0,%2,%1\;{sfe|subfe} %L0,%L2,%L1\"
+ : \"{sfi|subfic} %0,%2,%1\;{sf%G1e|subf%G1e} %L0,%L2\";
+}"
+ [(set_attr "length" "8")])
+
+(define_insn "*negdi2_noppc64"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r")
+ (neg:DI (match_operand:DI 1 "gpc_reg_operand" "r,0")))]
+ "! TARGET_POWERPC64"
+ "*
+{
+ return (WORDS_BIG_ENDIAN)
+ ? \"{sfi|subfic} %L0,%L1,0\;{sfze|subfze} %0,%1\"
+ : \"{sfi|subfic} %0,%1,0\;{sfze|subfze} %L0,%L1\";
+}"
+ [(set_attr "length" "8")])
+
+(define_expand "mulsidi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))]
+ "! TARGET_POWERPC64"
+ "
+{
+ if (! TARGET_POWER && ! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]);
+ emit_insn (gen_mull_call ());
+ if (WORDS_BIG_ENDIAN)
+ emit_move_insn (operands[0], gen_rtx_REG (DImode, 3));
+ else
+ {
+ emit_move_insn (operand_subword (operands[0], 0, 0, DImode),
+ gen_rtx_REG (SImode, 3));
+ emit_move_insn (operand_subword (operands[0], 1, 0, DImode),
+ gen_rtx_REG (SImode, 4));
+ }
+ DONE;
+ }
+ else if (TARGET_POWER)
+ {
+ emit_insn (gen_mulsidi3_mq (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+
+(define_insn "mulsidi3_mq"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))
+ (clobber (match_scratch:SI 3 "=q"))]
+ "TARGET_POWER"
+ "mul %0,%1,%2\;mfmq %L0"
+ [(set_attr "type" "imul")
+ (set_attr "length" "8")])
+
+(define_insn "*mulsidi3_no_mq"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
+ "TARGET_POWERPC && ! TARGET_POWER && ! TARGET_POWERPC64"
+ "*
+{
+ return (WORDS_BIG_ENDIAN)
+ ? \"mulhw %0,%1,%2\;mullw %L0,%1,%2\"
+ : \"mulhw %L0,%1,%2\;mullw %0,%1,%2\";
+}"
+ [(set_attr "type" "imul")
+ (set_attr "length" "8")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))]
+ "TARGET_POWERPC && ! TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (const_int 32))))
+ (set (match_dup 4)
+ (mult:SI (match_dup 1)
+ (match_dup 2)))]
+ "
+{
+ int endian = (WORDS_BIG_ENDIAN == 0);
+ operands[3] = operand_subword (operands[0], endian, 0, DImode);
+ operands[4] = operand_subword (operands[0], 1 - endian, 0, DImode);
+}")
+
+(define_expand "umulsidi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))]
+ "TARGET_POWERPC && ! TARGET_POWERPC64"
+ "
+{
+ if (TARGET_POWER)
+ {
+ emit_insn (gen_umulsidi3_mq (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+
+(define_insn "umulsidi3_mq"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))
+ (clobber (match_scratch:SI 3 "=q"))]
+ "TARGET_POWERPC && TARGET_POWER"
+ "*
+{
+ return (WORDS_BIG_ENDIAN)
+ ? \"mulhwu %0,%1,%2\;mullw %L0,%1,%2\"
+ : \"mulhwu %L0,%1,%2\;mullw %0,%1,%2\";
+}"
+ [(set_attr "type" "imul")
+ (set_attr "length" "8")])
+
+(define_insn "*umulsidi3_no_mq"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
+ "TARGET_POWERPC && ! TARGET_POWER && ! TARGET_POWERPC64"
+ "*
+{
+ return (WORDS_BIG_ENDIAN)
+ ? \"mulhwu %0,%1,%2\;mullw %L0,%1,%2\"
+ : \"mulhwu %L0,%1,%2\;mullw %0,%1,%2\";
+}"
+ [(set_attr "type" "imul")
+ (set_attr "length" "8")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))]
+ "TARGET_POWERPC && ! TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1))
+ (zero_extend:DI (match_dup 2)))
+ (const_int 32))))
+ (set (match_dup 4)
+ (mult:SI (match_dup 1)
+ (match_dup 2)))]
+ "
+{
+ int endian = (WORDS_BIG_ENDIAN == 0);
+ operands[3] = operand_subword (operands[0], endian, 0, DImode);
+ operands[4] = operand_subword (operands[0], 1 - endian, 0, DImode);
+}")
+
+(define_expand "smulsi3_highpart"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))]
+ ""
+ "
+{
+ if (! TARGET_POWER && ! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]);
+ emit_insn (gen_mulh_call ());
+ emit_move_insn (operands[0], gen_rtx_REG (SImode, 3));
+ DONE;
+ }
+ else if (TARGET_POWER)
+ {
+ emit_insn (gen_smulsi3_highpart_mq (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+
+(define_insn "smulsi3_highpart_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))
+ (clobber (match_scratch:SI 3 "=q"))]
+ "TARGET_POWER"
+ "mul %0,%1,%2"
+ [(set_attr "type" "imul")])
+
+(define_insn "*smulsi3_highpart_no_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))]
+ "TARGET_POWERPC && ! TARGET_POWER"
+ "mulhw %0,%1,%2"
+ [(set_attr "type" "imul")])
+
+(define_expand "umulsi3_highpart"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" ""))
+ (zero_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "")))
+ (const_int 32))))]
+ "TARGET_POWERPC"
+ "
+{
+ if (TARGET_POWER)
+ {
+ emit_insn (gen_umulsi3_highpart_mq (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+
+(define_insn "umulsi3_highpart_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (zero_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))
+ (clobber (match_scratch:SI 3 "=q"))]
+ "TARGET_POWERPC && TARGET_POWER"
+ "mulhwu %0,%1,%2"
+ [(set_attr "type" "imul")])
+
+(define_insn "*umulsi3_highpart_no_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (zero_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))]
+ "TARGET_POWERPC && ! TARGET_POWER"
+ "mulhwu %0,%1,%2"
+ [(set_attr "type" "imul")])
+
+;; If operands 0 and 2 are in the same register, we have a problem. But
+;; operands 0 and 1 (the usual case) can be in the same register. That's
+;; why we have the strange constraints below.
+(define_insn "ashldi3_power"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,&r")
+ (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,0,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "M,i,r,r")))
+ (clobber (match_scratch:SI 3 "=X,q,q,q"))]
+ "TARGET_POWER"
+ "@
+ {sli|slwi} %0,%L1,%h2\;{cal %L0,0(0)|li %L0,0}
+ sl%I2q %L0,%L1,%h2\;sll%I2q %0,%1,%h2
+ sl%I2q %L0,%L1,%h2\;sll%I2q %0,%1,%h2
+ sl%I2q %L0,%L1,%h2\;sll%I2q %0,%1,%h2"
+ [(set_attr "length" "8")])
+
+(define_insn "lshrdi3_power"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,&r")
+ (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,0,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "M,i,r,r")))
+ (clobber (match_scratch:SI 3 "=X,q,q,q"))]
+ "TARGET_POWER"
+ "@
+ {s%A2i|s%A2wi} %L0,%1,%h2\;{cal %0,0(0)|li %0,0}
+ sr%I2q %0,%1,%h2\;srl%I2q %L0,%L1,%h2
+ sr%I2q %0,%1,%h2\;srl%I2q %L0,%L1,%h2
+ sr%I2q %0,%1,%h2\;srl%I2q %L0,%L1,%h2"
+ [(set_attr "length" "8")])
+
+;; Shift by a variable amount is too complex to be worth open-coding. We
+;; just handle shifts by constants.
+(define_insn "ashrdi3_power"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r")
+ (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "const_int_operand" "M,i")))
+ (clobber (match_scratch:SI 3 "=X,q"))]
+ "TARGET_POWER"
+ "@
+ {srai|srawi} %0,%1,31\;{srai|srawi} %L0,%1,%h2
+ sraiq %0,%1,%h2\;srliq %L0,%L1,%h2"
+ [(set_attr "length" "8")])
+
+;; PowerPC64 DImode operations.
+
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (plus:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")))]
+ ""
+ "
+{
+ if (! TARGET_POWERPC64)
+ {
+ if (non_short_cint_operand (operands[2], DImode))
+ FAIL;
+ }
+ else
+ if (GET_CODE (operands[2]) == CONST_INT
+ && !add_operand (operands[2], DImode))
+ {
+ rtx tmp = ((reload_in_progress || reload_completed
+ || rtx_equal_p (operands[0], operands[1]))
+ ? operands[0] : gen_reg_rtx (DImode));
+
+ HOST_WIDE_INT low = INTVAL (operands[2]) & 0xffff;
+ HOST_WIDE_INT high = INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff);
+
+ if (low & 0x8000)
+ high += 0x10000, low |= ((HOST_WIDE_INT) -1) << 16;
+
+ emit_insn (gen_adddi3 (tmp, operands[1], GEN_INT (high)));
+ emit_insn (gen_adddi3 (operands[0], tmp, GEN_INT (low)));
+ DONE;
+ }
+}")
+
+;; Discourage ai/addic because of carry but provide it in an alternative
+;; allowing register zero as source.
+
+(define_insn "*adddi3_internal1"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,?r,r")
+ (plus:DI (match_operand:DI 1 "gpc_reg_operand" "%r,b,r,b")
+ (match_operand:DI 2 "add_operand" "r,I,I,J")))]
+ "TARGET_POWERPC64"
+ "@
+ add %0,%1,%2
+ addi %0,%1,%2
+ addic %0,%1,%2
+ addis %0,%1,%v2")
+
+(define_insn "*adddi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC (plus:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r")
+ (match_operand:DI 2 "reg_or_short_operand" "r,I,r,I"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r,r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ add. %3,%1,%2
+ addic. %3,%1,%2
+ #
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,4,8,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (plus:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_short_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (plus:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*adddi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC (plus:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r")
+ (match_operand:DI 2 "reg_or_short_operand" "r,I,r,I"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "@
+ add. %0,%1,%2
+ addic. %0,%1,%2
+ #
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,4,8,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (plus:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_short_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (plus:DI (match_dup 1)
+ (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (plus:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; Split an add that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine. Note that the low-order
+;; add should be last in case the result gets used in an address.
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (plus:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "non_add_cint_operand" "")))]
+ "TARGET_POWERPC64"
+ [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))]
+"
+{
+ HOST_WIDE_INT low = INTVAL (operands[2]) & 0xffff;
+ HOST_WIDE_INT high = INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff);
+
+ if (low & 0x8000)
+ high+=0x10000, low |= ((HOST_WIDE_INT) -1) << 16;
+
+ operands[3] = GEN_INT (high);
+ operands[4] = GEN_INT (low);
+}")
+
+(define_insn "one_cmpldi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (not:DI (match_operand:DI 1 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC64"
+ "nor %0,%1,%1")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 "=r,r"))]
+ "TARGET_POWERPC64"
+ "nor. %2,%1,%1"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 ""))]
+ "reload_completed"
+ [(set (match_dup 2)
+ (not:DI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (not:DI (match_dup 1)))]
+ "TARGET_POWERPC64"
+ "nor. %0,%1,%1"
+ [(set_attr "type" "compare")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (not:DI (match_dup 1)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (not:DI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (minus:DI (match_operand:DI 1 "reg_or_short_operand" "r,I")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r")))]
+ "TARGET_POWERPC64"
+ "@
+ subf %0,%2,%1
+ subfic %0,%2,%1")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (minus:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "subf. %3,%2,%1"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (minus:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (minus:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (minus:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (minus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "subf. %0,%2,%1"
+ [(set_attr "type" "compare")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (minus:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (minus:DI (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (minus:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "subdi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (minus:DI (match_operand:DI 1 "reg_or_short_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")))]
+ ""
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ emit_insn (gen_adddi3 (operands[0], operands[1],
+ negate_rtx (DImode, operands[2])));
+ DONE;
+ }
+}")
+
+(define_insn "absdi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r")
+ (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0")))
+ (clobber (match_scratch:DI 2 "=&r,&r"))]
+ "TARGET_POWERPC64"
+ "sradi %2,%1,63\;xor %0,%2,%1\;subf %0,%2,%0"
+ [(set_attr "length" "12")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r")
+ (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0")))
+ (clobber (match_scratch:DI 2 "=&r,&r"))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 63)))
+ (set (match_dup 0) (xor:DI (match_dup 2) (match_dup 1)))
+ (set (match_dup 0) (minus:DI (match_dup 0) (match_dup 2)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r")
+ (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0"))))
+ (clobber (match_scratch:DI 2 "=&r,&r"))]
+ "TARGET_POWERPC64"
+ "sradi %2,%1,63\;xor %0,%2,%1\;subf %0,%0,%2"
+ [(set_attr "length" "12")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r")
+ (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0"))))
+ (clobber (match_scratch:DI 2 "=&r,&r"))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 63)))
+ (set (match_dup 0) (xor:DI (match_dup 2) (match_dup 1)))
+ (set (match_dup 0) (minus:DI (match_dup 0) (match_dup 2)))]
+ "")
+
+(define_expand "negdi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (neg:DI (match_operand:DI 1 "gpc_reg_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (neg:DI (match_operand:DI 1 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC64"
+ "neg %0,%1")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (neg:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ neg. %2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (neg:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 2 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2)
+ (neg:DI (match_dup 1)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 2)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (neg:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (neg:DI (match_dup 1)))]
+ "TARGET_POWERPC64"
+ "@
+ neg. %0,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (neg:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (neg:DI (match_dup 1)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (neg:DI (match_dup 1)))
+ (set (match_dup 2)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "ffsdi2"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
+ (ffs:DI (match_operand:DI 1 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC64"
+ "neg %0,%1\;and %0,%0,%1\;cntlzd %0,%0\;subfic %0,%0,64"
+ [(set_attr "length" "16")])
+
+(define_insn "muldi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (mult:DI (match_operand:DI 1 "gpc_reg_operand" "%r")
+ (match_operand:DI 2 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC64"
+ "mulld %0,%1,%2"
+ [(set_attr "type" "imul")])
+
+(define_insn "smuldi3_highpart"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (truncate:DI
+ (lshiftrt:TI (mult:TI (sign_extend:TI
+ (match_operand:DI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:TI
+ (match_operand:DI 2 "gpc_reg_operand" "r")))
+ (const_int 64))))]
+ "TARGET_POWERPC64"
+ "mulhd %0,%1,%2"
+ [(set_attr "type" "imul")])
+
+(define_insn "umuldi3_highpart"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (truncate:DI
+ (lshiftrt:TI (mult:TI (zero_extend:TI
+ (match_operand:DI 1 "gpc_reg_operand" "%r"))
+ (zero_extend:TI
+ (match_operand:DI 2 "gpc_reg_operand" "r")))
+ (const_int 64))))]
+ "TARGET_POWERPC64"
+ "mulhdu %0,%1,%2"
+ [(set_attr "type" "imul")])
+
+(define_expand "divdi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (div:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")))]
+ "TARGET_POWERPC64"
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && exact_log2 (INTVAL (operands[2])) >= 0)
+ ;
+ else
+ operands[2] = force_reg (DImode, operands[2]);
+}")
+
+(define_expand "moddi3"
+ [(use (match_operand:DI 0 "gpc_reg_operand" ""))
+ (use (match_operand:DI 1 "gpc_reg_operand" ""))
+ (use (match_operand:DI 2 "reg_or_cint_operand" ""))]
+ "TARGET_POWERPC64"
+ "
+{
+ int i = exact_log2 (INTVAL (operands[2]));
+ rtx temp1;
+ rtx temp2;
+
+ if (GET_CODE (operands[2]) != CONST_INT || i < 0)
+ FAIL;
+
+ temp1 = gen_reg_rtx (DImode);
+ temp2 = gen_reg_rtx (DImode);
+
+ emit_insn (gen_divdi3 (temp1, operands[1], operands[2]));
+ emit_insn (gen_ashldi3 (temp2, temp1, GEN_INT (i)));
+ emit_insn (gen_subdi3 (operands[0], operands[1], temp2));
+ DONE;
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (div:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "const_int_operand" "N")))]
+ "TARGET_POWERPC64 && exact_log2 (INTVAL (operands[2])) >= 0"
+ "sradi %0,%1,%p2\;addze %0,%0"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (div:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "const_int_operand" "N,N"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64 && exact_log2 (INTVAL (operands[2])) >= 0"
+ "@
+ sradi %3,%1,%p2\;addze. %3,%3
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (div:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "const_int_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "TARGET_POWERPC64 && reload_completed && exact_log2 (INTVAL (operands[2])) >= 0"
+ [(set (match_dup 3)
+ (div:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (div:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "const_int_operand" "N,N"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (div:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64 && exact_log2 (INTVAL (operands[2])) >= 0"
+ "@
+ sradi %0,%1,%p2\;addze. %0,%0
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (div:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "const_int_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (div:DI (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_POWERPC64 && reload_completed && exact_log2 (INTVAL (operands[2])) >= 0"
+ [(set (match_dup 0)
+ (div:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (div:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC64"
+ "divd %0,%1,%2"
+ [(set_attr "type" "idiv")])
+
+(define_insn "udivdi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (udiv:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC64"
+ "divdu %0,%1,%2"
+ [(set_attr "type" "idiv")])
+
+(define_insn "rotldi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")))]
+ "TARGET_POWERPC64"
+ "rld%I2cl %0,%1,%H2,0")
+
+(define_insn "*rotldi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2cl. %3,%1,%H2,0
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (rotate:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotldi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (rotate:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2cl. %0,%1,%H2,0
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (rotate:DI (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (rotate:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotldi3_internal4"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (and:DI (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri"))
+ (match_operand:DI 3 "mask64_operand" "S")))]
+ "TARGET_POWERPC64"
+ "rld%I2c%B3 %0,%1,%H2,%S3")
+
+(define_insn "*rotldi3_internal5"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:DI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri"))
+ (match_operand:DI 3 "mask64_operand" "S,S"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 4 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2c%B3. %4,%1,%H2,%S3
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:DI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (match_operand:DI 3 "mask64_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 4 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 4)
+ (and:DI
+ (rotate:DI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 4)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotldi3_internal6"
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:DI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri"))
+ (match_operand:DI 3 "mask64_operand" "S,S"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (and:DI (rotate:DI (match_dup 1) (match_dup 2)) (match_dup 3)))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2c%B3. %0,%1,%H2,%S3
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:DI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (match_operand:DI 3 "mask64_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (and:DI
+ (rotate:DI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (and:DI
+ (rotate:DI (match_dup 1)
+ (match_dup 2))
+ (match_dup 3)))
+ (set (match_dup 4)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotldi3_internal7"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extend:DI
+ (subreg:QI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0)))]
+ "TARGET_POWERPC64"
+ "rld%I2cl %0,%1,%H2,56")
+
+(define_insn "*rotldi3_internal8"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI
+ (subreg:QI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2cl. %3,%1,%H2,56
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI
+ (subreg:QI
+ (rotate:DI
+ (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (zero_extend:DI
+ (subreg:QI
+ (rotate:DI
+ (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotldi3_internal9"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI
+ (subreg:QI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:DI (subreg:QI (rotate:DI (match_dup 1) (match_dup 2)) 0)))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2cl. %0,%1,%H2,56
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI
+ (subreg:QI
+ (rotate:DI
+ (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")) 0))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (zero_extend:DI
+ (subreg:QI
+ (rotate:DI
+ (match_dup 1)
+ (match_dup 2)) 0)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:DI
+ (subreg:QI
+ (rotate:DI
+ (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotldi3_internal10"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extend:DI
+ (subreg:HI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0)))]
+ "TARGET_POWERPC64"
+ "rld%I2cl %0,%1,%H2,48")
+
+(define_insn "*rotldi3_internal11"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI
+ (subreg:HI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2cl. %3,%1,%H2,48
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI
+ (subreg:HI
+ (rotate:DI
+ (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (zero_extend:DI
+ (subreg:HI
+ (rotate:DI
+ (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotldi3_internal12"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI
+ (subreg:HI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:DI (subreg:HI (rotate:DI (match_dup 1) (match_dup 2)) 0)))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2cl. %0,%1,%H2,48
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI
+ (subreg:HI
+ (rotate:DI
+ (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")) 0))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (zero_extend:DI
+ (subreg:HI
+ (rotate:DI
+ (match_dup 1)
+ (match_dup 2)) 0)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:DI
+ (subreg:QI
+ (rotate:DI
+ (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotldi3_internal13"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (zero_extend:DI
+ (subreg:SI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri")) 0)))]
+ "TARGET_POWERPC64"
+ "rld%I2cl %0,%1,%H2,32")
+
+(define_insn "*rotldi3_internal14"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI
+ (subreg:SI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2cl. %3,%1,%H2,32
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI
+ (subreg:SI
+ (rotate:DI
+ (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")) 0))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (zero_extend:DI
+ (subreg:SI
+ (rotate:DI
+ (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*rotldi3_internal15"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (zero_extend:DI
+ (subreg:SI
+ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "ri,ri")) 0))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (zero_extend:DI (subreg:SI (rotate:DI (match_dup 1) (match_dup 2)) 0)))]
+ "TARGET_POWERPC64"
+ "@
+ rld%I2cl. %0,%1,%H2,32
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (zero_extend:DI
+ (subreg:SI
+ (rotate:DI
+ (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")) 0))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (zero_extend:DI
+ (subreg:SI
+ (rotate:DI
+ (match_dup 1)
+ (match_dup 2)) 0)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (zero_extend:DI
+ (subreg:QI
+ (rotate:DI
+ (match_dup 1)
+ (match_dup 2)) 0)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "ashldi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ "TARGET_POWERPC64 || TARGET_POWER"
+ "
+{
+ if (TARGET_POWERPC64)
+ ;
+ else if (TARGET_POWER)
+ {
+ emit_insn (gen_ashldi3_power (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ else
+ FAIL;
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri")))]
+ "TARGET_POWERPC64"
+ "sld%I2 %0,%1,%H2"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ sld%I2. %3,%1,%H2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (ashift:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (ashift:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "@
+ sld%I2. %0,%1,%H2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ashift:DI (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (ashift:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "lshrdi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ "TARGET_POWERPC64 || TARGET_POWER"
+ "
+{
+ if (TARGET_POWERPC64)
+ ;
+ else if (TARGET_POWER)
+ {
+ emit_insn (gen_lshrdi3_power (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ else
+ FAIL;
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri")))]
+ "TARGET_POWERPC64"
+ "srd%I2 %0,%1,%H2")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ srd%I2. %3,%1,%H2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (lshiftrt:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (lshiftrt:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "@
+ srd%I2. %0,%1,%H2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (lshiftrt:DI (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (lshiftrt:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "ashrdi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "reg_or_cint_operand" "")))]
+ "TARGET_POWERPC64 || TARGET_POWER"
+ "
+{
+ if (TARGET_POWERPC64)
+ ;
+ else if (TARGET_POWER && GET_CODE (operands[2]) == CONST_INT)
+ {
+ emit_insn (gen_ashrdi3_power (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ else
+ FAIL;
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri")))]
+ "TARGET_POWERPC64"
+ "srad%I2 %0,%1,%H2")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ srad%I2. %3,%1,%H2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 3)
+ (ashiftrt:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "ri,ri"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (ashiftrt:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "@
+ srad%I2. %0,%1,%H2
+ #"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ashiftrt (match_dup 1)
+ (match_dup 2)))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 0)
+ (ashiftrt (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "anddi3"
+ [(parallel [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r")
+ (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r")
+ (match_operand:DI 2 "and_operand" "?r,L,K,J")))
+ (clobber (match_scratch:CC 3 "=X,X,x,x"))])]
+ "TARGET_POWERPC64"
+ "")
+
+;; If cr0 isn't available, and we want to do an andi, load the register into
+;; the destination first.
+
+(define_insn "anddi3_internal1"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,&??r,&??r")
+ (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r")
+ (match_operand:DI 2 "and_operand" "?r,L,K,J,K,J")))
+ (clobber (match_operand:CC 3 "scratch_operand" "=X,X,x,x,X,X"))]
+ "TARGET_POWERPC64"
+ "@
+ and %0,%1,%2
+ {rlinm|rlwinm} %0,%1,0,%m2,%M2
+ andil %0,%1,%b2
+ andis. %0,%1,%u2
+ #
+ #"
+ [(set_attr "length" "4,4,4,4,8,8")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (and:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "const_int_operand" "")))
+ (clobber (scratch:CC))]
+ "TARGET_POWERPC64 && reload_completed && !mask_constant (INTVAL (operands[2]))"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (parallel [(set (match_dup 0)
+ (and:DI (match_dup 0)
+ (match_dup 1)))
+ (clobber (scratch:CC))])]
+ "")
+
+;; Note to set cr's other than cr0 we do the and immediate and then
+;; the test again -- this avoids a mcrf which on the higher end
+;; machines causes an execution serialization
+
+(define_insn "*anddi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y,???y,???y")
+ (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r")
+ (match_operand:DI 2 "and_operand" "r,K,J,L,r,K,J,L,K,L"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r,r,r,r,r,r,r,&r,&r"))
+ (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X,X,X"))]
+ "TARGET_POWERPC64"
+ "@
+ and. %3,%1,%2
+ {andil.|andi.} %3,%1,%b2
+ {andiu.|andis.} %3,%1,%u2
+ {rlinm.|rlwinm.} %3,%1,0,%m2,%M2
+ #
+ #
+ #
+ #
+ #
+ #"
+ [(set_attr "type" "compare,compare,compare,delayed_compare,compare,compare,compare,compare,compare,compare")
+ (set_attr "length" "4,4,4,4,8,8,8,8,12,12")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "and_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))
+ (clobber (match_scratch:CC 4 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(parallel [(set (match_dup 3)
+ (and:DI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*anddi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y,???y,???y")
+ (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r")
+ (match_operand:DI 2 "and_operand" "r,K,J,L,r,K,J,L,K,J"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r,r,r,r,&r,&r")
+ (and:DI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X,X,X"))]
+ "TARGET_POWERPC64"
+ "@
+ and. %0,%1,%2
+ andi. %0,%1,%b2
+ andis. %0,%1,%u2
+ rldic%B2 %0,%1,0,%m2,%M2
+ #
+ #
+ #
+ #
+ #
+ #"
+ [(set_attr "type" "compare,compare,compare,delayed_compare,compare,compare,compare,compare,compare,compare")
+ (set_attr "length" "4,4,4,4,8,8,8,8,12,12")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "and_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (and:DI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_scratch:CC 4 ""))]
+ "TARGET_POWERPC64 && reload_completed"
+ [(parallel [(set (match_dup 0)
+ (and:DI (match_dup 1)
+ (match_dup 2)))
+ (clobber (match_dup 4))])
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_expand "iordi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ior:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")))]
+ "TARGET_POWERPC64"
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && !logical_operand (operands[2], DImode))
+ {
+ HOST_WIDE_INT value = INTVAL (operands[2]);
+ rtx tmp = ((reload_in_progress || reload_completed
+ || rtx_equal_p (operands[0], operands[1]))
+ ? operands[0] : gen_reg_rtx (DImode));
+
+ emit_insn (gen_iordi3 (tmp, operands[1],
+ GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff))));
+ emit_insn (gen_iordi3 (operands[0], tmp, GEN_INT (value & 0xffff)));
+ DONE;
+ }
+}")
+
+(define_insn "*iordi3_internal1"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r")
+ (ior:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r")
+ (match_operand:DI 2 "logical_operand" "r,K,J")))]
+ "TARGET_POWERPC64"
+ "@
+ or %0,%1,%2
+ ori %0,%1,%b2
+ oris %0,%1,%u2")
+
+(define_insn "*iordi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ or. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (ior:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*iordi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (ior:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "@
+ or. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ior:DI (match_dup 1) (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (ior:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; Split an IOR that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine.
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ior:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "non_logical_cint_operand" "")))]
+ "TARGET_POWERPC64"
+ [(set (match_dup 0) (ior:DI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (ior:DI (match_dup 0) (match_dup 4)))]
+"
+{
+ operands[3] = GEN_INT (INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff));
+ operands[4] = GEN_INT (INTVAL (operands[2]) & 0xffff);
+}")
+
+(define_expand "xordi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (xor:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_cint_operand" "")))]
+ "TARGET_POWERPC64"
+ "
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && !logical_operand (operands[2], DImode))
+ {
+ HOST_WIDE_INT value = INTVAL (operands[2]);
+ rtx tmp = ((reload_in_progress || reload_completed
+ || rtx_equal_p (operands[0], operands[1]))
+ ? operands[0] : gen_reg_rtx (DImode));
+
+ emit_insn (gen_xordi3 (tmp, operands[1],
+ GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff))));
+ emit_insn (gen_xordi3 (operands[0], tmp, GEN_INT (value & 0xffff)));
+ DONE;
+ }
+}")
+
+(define_insn "*xordi3_internal1"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r")
+ (xor:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r")
+ (match_operand:DI 2 "logical_operand" "r,K,J")))]
+ "TARGET_POWERPC64"
+ "@
+ xor %0,%1,%2
+ xori %0,%1,%b2
+ xoris %0,%1,%u2")
+
+(define_insn "*xordi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (xor:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ xor. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (xor:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (xor:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*xordi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (xor:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (xor:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "@
+ xor. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (xor:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (xor:DI (match_dup 1) (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (xor:DI (match_dup 1)
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+;; Split an XOR that we can't do in one insn into two insns, each of which
+;; does one 16-bit part. This is used by combine.
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (xor:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "non_logical_cint_operand" "")))]
+ "TARGET_POWERPC64"
+ [(set (match_dup 0) (xor:DI (match_dup 1) (match_dup 3)))
+ (set (match_dup 0) (xor:DI (match_dup 0) (match_dup 4)))]
+"
+{
+ operands[3] = GEN_INT (INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff));
+ operands[4] = GEN_INT (INTVAL (operands[2]) & 0xffff);
+}")
+
+(define_insn "*eqvdi3_internal1"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (not:DI (xor:DI (match_operand:DI 1 "gpc_reg_operand" "%r")
+ (match_operand:DI 2 "gpc_reg_operand" "r"))))]
+ "TARGET_POWERPC64"
+ "eqv %0,%1,%2")
+
+(define_insn "*eqvdi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (not:DI (xor:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ eqv. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (not:DI (xor:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (not:DI (xor:DI (match_dup 1)
+ (match_dup 2))))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*eqvdi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (not:DI (xor:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (match_operand:DI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (not:DI (xor:DI (match_dup 1) (match_dup 2))))]
+ "TARGET_POWERPC64"
+ "@
+ eqv. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (not:DI (xor:DI (match_operand:DI 1 "gpc_reg_operand" "")
+ (match_operand:DI 2 "reg_or_short_operand" "")))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (not:DI (xor:DI (match_dup 1)
+ (match_dup 2))))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (not:DI (xor:DI (match_dup 1)
+ (match_dup 2))))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*andcdi3_internal1"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
+ (match_operand:DI 2 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC64"
+ "andc %0,%2,%1")
+
+(define_insn "*andcdi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ andc. %3,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (and:DI (not:DI (match_dup 1))
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*andcdi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (and:DI (not:DI (match_dup 1)) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "@
+ andc. %0,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (and:DI (not:DI (match_dup 1))
+ (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (and:DI (not:DI (match_dup 1))
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*iorcdi3_internal1"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
+ (match_operand:DI 2 "gpc_reg_operand" "r")))]
+ "TARGET_POWERPC64"
+ "orc %0,%2,%1")
+
+(define_insn "*iorcdi3_inernal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ orc. %3,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (ior:DI (not:DI (match_dup 1))
+ (match_dup 2)))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*iorcdi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (ior:DI (not:DI (match_dup 1)) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "@
+ orc. %0,%2,%1
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (match_operand:DI 2 "gpc_reg_operand" ""))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ior:DI (not:DI (match_dup 1))
+ (match_dup 2)))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (ior:DI (not:DI (match_dup 1))
+ (match_dup 2)))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*nanddi3_internal1"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "r"))))]
+ "TARGET_POWERPC64"
+ "nand %0,%1,%2")
+
+(define_insn "*nanddi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ nand. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (ior:DI (not:DI (match_dup 1))
+ (not:DI (match_dup 2))))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*nanddi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (ior:DI (not:DI (match_dup 1)) (not:DI (match_dup 2))))]
+ "TARGET_POWERPC64"
+ "@
+ nand. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (ior:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (ior:DI (not:DI (match_dup 1))
+ (not:DI (match_dup 2))))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (ior:DI (not:DI (match_dup 1))
+ (not:DI (match_dup 2))))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+(define_insn "*nordi3_internal1"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r"))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "r"))))]
+ "TARGET_POWERPC64"
+ "nor %0,%1,%2")
+
+(define_insn "*nordi3_internal2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ nor. %3,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 ""))]
+ "reload_completed"
+ [(set (match_dup 3)
+ (and:DI (not:DI (match_dup 1))
+ (not:DI (match_dup 2))))
+ (set (match_dup 0)
+ (compare:CC (match_dup 3)
+ (const_int 0)))]
+ "")
+
+(define_insn "*nordi3_internal3"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "r,r")))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (and:DI (not:DI (match_dup 1)) (not:DI (match_dup 2))))]
+ "TARGET_POWERPC64"
+ "@
+ nor. %0,%1,%2
+ #"
+ [(set_attr "type" "compare")
+ (set_attr "length" "4,8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+ (compare:CC (and:DI (not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
+ (not:DI (match_operand:DI 2 "gpc_reg_operand" "")))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (and:DI (not:DI (match_dup 1))
+ (not:DI (match_dup 2))))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (and:DI (not:DI (match_dup 1))
+ (not:DI (match_dup 2))))
+ (set (match_dup 3)
+ (compare:CC (match_dup 0)
+ (const_int 0)))]
+ "")
+
+
+;; Now define ways of moving data around.
+
+;; Elf specific ways of loading addresses for non-PIC code.
+;; The output of this could be r0, but we limit it to base
+;; registers, since almost all uses of this will need it
+;; in a base register shortly.
+(define_insn "elf_high"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (high:SI (match_operand 1 "" "")))]
+ "TARGET_ELF && !TARGET_64BIT"
+ "{liu|lis} %0,%1@ha")
+
+(define_insn "elf_low"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "b")
+ (match_operand 2 "" "")))]
+ "TARGET_ELF && !TARGET_64BIT"
+ "{cal|la} %0,%2@l(%1)")
+
+;; Set up a register with a value from the GOT table
+
+(define_expand "movsi_got"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (unspec [(match_operand:SI 1 "got_operand" "")
+ (match_dup 2)] 8))]
+ "(DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && flag_pic == 1"
+ "
+{
+ if (GET_CODE (operands[1]) == CONST)
+ {
+ rtx offset = const0_rtx;
+ HOST_WIDE_INT value;
+
+ operands[1] = eliminate_constant_term (XEXP (operands[1], 0), &offset);
+ value = INTVAL (offset);
+ if (value != 0)
+ {
+ rtx tmp = ((reload_in_progress || reload_completed)
+ ? operands[0]
+ : gen_reg_rtx (Pmode));
+ emit_insn (gen_movsi_got (tmp, operands[1]));
+ emit_insn (gen_addsi3 (operands[0], tmp, offset));
+ DONE;
+ }
+ }
+
+ operands[2] = rs6000_got_register (operands[1]);
+}")
+
+(define_insn "*movsi_got_internal"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec [(match_operand:SI 1 "got_no_const_operand" "")
+ (match_operand:SI 2 "register_operand" "b")] 8))]
+ "(DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && flag_pic == 1"
+ "{l|lwz} %0,%a1@got(%2)"
+ [(set_attr "type" "load")])
+
+;; Sometimes, though, the GOT `register' will be on the stack. Deal with
+;; this case specially.
+;; Force final to split this insn (if it hasn't been split already) to
+;; avoid having to create a suitable output template.
+(define_insn "*movsi_got_internal_mem"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec [(match_operand:SI 1 "got_no_const_operand" "")
+ (match_operand:SI 2 "memory_operand" "m")] 8))]
+ "(DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && flag_pic == 1
+ && (reload_in_progress || reload_completed)"
+ "#"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+;; Used by sched, shorten_branches and final when the GOT pseudo reg
+;; didn't get allocated to a hard register.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec [(match_operand:SI 1 "got_no_const_operand" "")
+ (match_operand:SI 2 "memory_operand" "m")] 8))]
+ "(DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && flag_pic == 1
+ && (reload_in_progress || reload_completed)"
+ [(set (match_dup 0) (match_dup 2))
+ (set (match_dup 0) (unspec [(match_dup 1)(match_dup 0)] 8))]
+ "")
+
+;; For SI, we special-case integers that can't be loaded in one insn. We
+;; do the load 16-bits at a time. We could do this by loading from memory,
+;; and this is even supposed to be faster, but it is simpler not to get
+;; integers in the TOC.
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "any_operand" ""))]
+ ""
+ "
+{
+ if (GET_CODE (operands[0]) != REG)
+ operands[1] = force_reg (SImode, operands[1]);
+
+ /* Convert a move of a CONST_DOUBLE into a CONST_INT */
+ if (GET_CODE (operands[1]) == CONST_DOUBLE)
+ operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
+
+ /* Use default pattern for address of ELF small data */
+ if (TARGET_ELF
+ && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST)
+ && small_data_operand (operands[1], SImode))
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
+ DONE;
+ }
+
+ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && flag_pic == 1 && got_operand (operands[1], SImode))
+ {
+ emit_insn (gen_movsi_got (operands[0], operands[1]));
+ DONE;
+ }
+
+ if (TARGET_ELF && TARGET_NO_TOC && !TARGET_64BIT
+ && !flag_pic
+ && CONSTANT_P (operands[1])
+ && GET_CODE (operands[1]) != HIGH
+ && GET_CODE (operands[1]) != CONST_INT
+ && GET_CODE (operands[1]) != CONSTANT_P_RTX)
+ {
+ rtx target = (reload_completed || reload_in_progress)
+ ? operands[0] : gen_reg_rtx (SImode);
+
+ /* If this is a function address on -mcall-aixdesc or -mcall-nt,
+ convert it to the address of the descriptor. */
+ if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ && GET_CODE (operands[1]) == SYMBOL_REF
+ && XSTR (operands[1], 0)[0] == '.')
+ {
+ char *name = XSTR (operands[1], 0);
+ rtx new_ref;
+ while (*name == '.')
+ name++;
+ new_ref = gen_rtx_SYMBOL_REF (Pmode, name);
+ CONSTANT_POOL_ADDRESS_P (new_ref) = CONSTANT_POOL_ADDRESS_P (operands[1]);
+ SYMBOL_REF_FLAG (new_ref) = SYMBOL_REF_FLAG (operands[1]);
+ SYMBOL_REF_USED (new_ref) = SYMBOL_REF_USED (operands[1]);
+ operands[1] = new_ref;
+ }
+
+ emit_insn (gen_elf_high (target, operands[1]));
+ emit_insn (gen_elf_low (operands[0], target, operands[1]));
+ DONE;
+ }
+
+ if (GET_CODE (operands[1]) == CONST
+ && DEFAULT_ABI == ABI_NT
+ && !side_effects_p (operands[0]))
+ {
+ rtx const_term = const0_rtx;
+ rtx sym = eliminate_constant_term (XEXP (operands[1], 0), &const_term);
+ if (sym && GET_CODE (const_term) == CONST_INT
+ && (GET_CODE (sym) == SYMBOL_REF || GET_CODE (sym) == LABEL_REF))
+ {
+ unsigned HOST_WIDE_INT value = INTVAL (const_term);
+ int new_reg_p = (flag_expensive_optimizations
+ && !reload_completed
+ && !reload_in_progress);
+ rtx tmp1 = (new_reg_p && value != 0) ? gen_reg_rtx (SImode) : operands[0];
+
+ emit_insn (gen_movsi (tmp1, sym));
+ if (INTVAL (const_term) != 0)
+ emit_insn (gen_addsi3 (operands[0], tmp1, GEN_INT (value)));
+ DONE;
+ }
+ else
+ rs6000_fatal_bad_address (operands[1]);
+ }
+
+ if ((!TARGET_WINDOWS_NT || DEFAULT_ABI != ABI_NT)
+ && CONSTANT_P (operands[1])
+ && GET_CODE (operands[1]) != CONST_INT
+ && GET_CODE (operands[1]) != CONSTANT_P_RTX
+ && GET_CODE (operands[1]) != HIGH
+ && ! LEGITIMATE_CONSTANT_POOL_ADDRESS_P (operands[1]))
+ {
+ /* Emit a USE operation so that the constant isn't deleted if
+ expensive optimizations are turned on because nobody
+ references it. This should only be done for operands that
+ contain SYMBOL_REFs with CONSTANT_POOL_ADDRESS_P set.
+ This should not be done for operands that contain LABEL_REFs.
+ For now, we just handle the obvious case. */
+ if (GET_CODE (operands[1]) != LABEL_REF)
+ emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
+
+ /* If we are to limit the number of things we put in the TOC and
+ this is a symbol plus a constant we can add in one insn,
+ just put the symbol in the TOC and add the constant. Don't do
+ this if reload is in progress. */
+ if (GET_CODE (operands[1]) == CONST
+ && TARGET_NO_SUM_IN_TOC && ! reload_in_progress
+ && GET_CODE (XEXP (operands[1], 0)) == PLUS
+ && add_operand (XEXP (XEXP (operands[1], 0), 1), SImode)
+ && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
+ || GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
+ && ! side_effects_p (operands[0]))
+ {
+ rtx sym = force_const_mem (SImode, XEXP (XEXP (operands[1], 0), 0));
+ rtx other = XEXP (XEXP (operands[1], 0), 1);
+
+ emit_insn (gen_addsi3 (operands[0], force_reg (SImode, sym), other));
+ DONE;
+ }
+
+ operands[1] = force_const_mem (SImode, operands[1]);
+ if (! memory_address_p (SImode, XEXP (operands[1], 0))
+ && ! reload_in_progress)
+ operands[1] = change_address (operands[1], SImode,
+ XEXP (operands[1], 0));
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h")
+ (match_operand:SI 1 "input_operand" "r,U,m,r,I,J,n,R,*h,r,r,0"))]
+ "gpc_reg_operand (operands[0], SImode)
+ || gpc_reg_operand (operands[1], SImode)"
+ "@
+ mr %0,%1
+ {cal|la} %0,%a1
+ {l%U1%X1|lwz%U1%X1} %0,%1
+ {st%U0%X0|stw%U0%X0} %1,%0
+ {lil|li} %0,%1
+ {liu|lis} %0,%v1
+ #
+ {cal|la} %0,%1(%*)
+ mf%1 %0
+ mt%0 %1
+ mt%0 %1
+ cror 0,0,0"
+ [(set_attr "type" "*,*,load,store,*,*,*,*,*,*,mtjmpr,*")
+ (set_attr "length" "4,4,4,4,4,4,8,4,4,4,4,4")])
+
+;; Split a load of a large constant into the appropriate two-insn
+;; sequence.
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (match_operand:SI 1 "const_int_operand" ""))]
+ "(unsigned HOST_WIDE_INT) (INTVAL (operands[1]) + 0x8000) >= 0x10000
+ && (INTVAL (operands[1]) & 0xffff) != 0"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (ior:SI (match_dup 0)
+ (match_dup 3)))]
+ "
+{
+ operands[2] = GEN_INT (INTVAL (operands[1]) & 0xffff0000);
+ operands[3] = GEN_INT (INTVAL (operands[1]) & 0xffff);
+}")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") (match_dup 1))]
+ ""
+ "@
+ mr. %0,%1
+ #"
+ [(set_attr "type" "compare")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (match_operand:SI 1 "gpc_reg_operand" "")
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (match_dup 1))]
+ "reload_completed && rtx_equal_p (operands[0], operands[1])"
+ [(set (match_dup 2)
+ (compare:CC (match_dup 1)
+ (const_int 0)))]
+ "")
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (match_operand:SI 1 "gpc_reg_operand" "")
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (match_dup 1))]
+ "reload_completed && !rtx_equal_p (operands[0], operands[1])"
+ [(set (match_dup 2)
+ (compare:CC (match_dup 1)
+ (const_int 0)))
+ (set (match_dup 0)
+ (match_dup 1))]
+ "")
+
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "any_operand" ""))]
+ ""
+ "
+{
+ if (GET_CODE (operands[0]) != REG)
+ operands[1] = force_reg (HImode, operands[1]);
+
+ if (CONSTANT_P (operands[1])
+ && GET_CODE (operands[1]) != CONST_INT
+ && GET_CODE (operands[1]) != CONSTANT_P_RTX)
+ {
+ operands[1] = force_const_mem (HImode, operands[1]);
+ if (! memory_address_p (HImode, XEXP (operands[1], 0))
+ && ! reload_in_progress)
+ operands[1] = change_address (operands[1], HImode,
+ XEXP (operands[1], 0));
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r,r,*q,*c*l,*h")
+ (match_operand:HI 1 "input_operand" "r,m,r,i,*h,r,r,0"))]
+ "gpc_reg_operand (operands[0], HImode)
+ || gpc_reg_operand (operands[1], HImode)"
+ "@
+ mr %0,%1
+ lhz%U1%X1 %0,%1
+ sth%U0%X0 %1,%0
+ {lil|li} %0,%w1
+ mf%1 %0
+ mt%0 %1
+ mt%0 %1
+ cror 0,0,0"
+ [(set_attr "type" "*,load,store,*,*,*,mtjmpr,*")])
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "any_operand" ""))]
+ ""
+ "
+{
+ if (GET_CODE (operands[0]) != REG)
+ operands[1] = force_reg (QImode, operands[1]);
+
+ if (CONSTANT_P (operands[1])
+ && GET_CODE (operands[1]) != CONST_INT
+ && GET_CODE (operands[1]) != CONSTANT_P_RTX)
+ {
+ operands[1] = force_const_mem (QImode, operands[1]);
+ if (! memory_address_p (QImode, XEXP (operands[1], 0))
+ && ! reload_in_progress)
+ operands[1] = change_address (operands[1], QImode,
+ XEXP (operands[1], 0));
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,m,r,r,*q,*c*l,*h")
+ (match_operand:QI 1 "input_operand" "r,m,r,i,*h,r,r,0"))]
+ "gpc_reg_operand (operands[0], QImode)
+ || gpc_reg_operand (operands[1], QImode)"
+ "@
+ mr %0,%1
+ lbz%U1%X1 %0,%1
+ stb%U0%X0 %1,%0
+ {lil|li} %0,%1
+ mf%1 %0
+ mt%0 %1
+ mt%0 %1
+ cror 0,0,0"
+ [(set_attr "type" "*,load,store,*,*,*,mtjmpr,*")])
+
+;; Here is how to move condition codes around. When we store CC data in
+;; an integer register or memory, we store just the high-order 4 bits.
+;; This lets us not shift in the most common case of CR0.
+(define_expand "movcc"
+ [(set (match_operand:CC 0 "nonimmediate_operand" "")
+ (match_operand:CC 1 "nonimmediate_operand" ""))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:CC 0 "nonimmediate_operand" "=y,x,y,r,r,r,r,m")
+ (match_operand:CC 1 "nonimmediate_operand" "y,r,r,x,y,r,m,r"))]
+ "register_operand (operands[0], CCmode)
+ || register_operand (operands[1], CCmode)"
+ "@
+ mcrf %0,%1
+ mtcrf 128,%1
+ {rlinm|rlwinm} %1,%1,%F0,0xffffffff\;mtcrf %R0,%1\;{rlinm|rlwinm} %1,%1,%f0,0xffffffff
+ mfcr %0
+ mfcr %0\;{rlinm|rlwinm} %0,%0,%f1,0xf0000000
+ mr %0,%1
+ {l%U1%X1|lwz%U1%X1} %0,%1
+ {st%U0%U1|stw%U0%U1} %1,%0"
+ [(set_attr "type" "*,*,*,compare,*,*,load,store")
+ (set_attr "length" "*,*,12,*,8,*,*,*")])
+
+;; For floating-point, we normally deal with the floating-point registers
+;; unless -msoft-float is used. The sole exception is that parameter passing
+;; can produce floating-point values in fixed-point registers. Unless the
+;; value is a simple constant or already in memory, we deal with this by
+;; allocating memory and copying the value explicitly via that memory location.
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "")
+ (match_operand:SF 1 "any_operand" ""))]
+ ""
+ "
+{
+ /* If we are called from reload, we might be getting a SUBREG of a hard
+ reg. So expand it. */
+ if (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (SUBREG_REG (operands[0])) < FIRST_PSEUDO_REGISTER)
+ operands[0] = alter_subreg (operands[0]);
+ if (GET_CODE (operands[1]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[1])) == REG
+ && REGNO (SUBREG_REG (operands[1])) < FIRST_PSEUDO_REGISTER)
+ operands[1] = alter_subreg (operands[1]);
+
+ if (GET_CODE (operands[0]) == MEM)
+ {
+ /* If operands[1] is a register, it may have double-precision data
+ in it, so truncate it to single precision. We need not do
+ this for POWERPC. */
+ if (! TARGET_POWERPC && TARGET_HARD_FLOAT
+ && GET_CODE (operands[1]) == REG
+ && (FP_REGNO_P (REGNO (operands[1]))
+ || REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER))
+ {
+ rtx newreg
+ = reload_in_progress ? operands[1] : gen_reg_rtx (SFmode);
+ emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
+ operands[1] = newreg;
+ }
+
+ operands[1] = force_reg (SFmode, operands[1]);
+ }
+
+ if (CONSTANT_P (operands[1]) && TARGET_HARD_FLOAT)
+ {
+ operands[1] = force_const_mem (SFmode, operands[1]);
+ if (! memory_address_p (SFmode, XEXP (operands[1], 0))
+ && ! reload_in_progress)
+ operands[1] = change_address (operands[1], SFmode,
+ XEXP (operands[1], 0));
+ }
+}")
+
+(define_split
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (match_operand:SF 1 "const_double_operand" ""))]
+ "reload_completed
+ && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
+ || (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (SUBREG_REG (operands[0])) <= 31))"
+ [(set (match_dup 2) (match_dup 3))]
+ "
+{
+ long l;
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+
+ if (! TARGET_POWERPC64)
+ operands[2] = operand_subword (operands[0], 0, 0, SFmode);
+ else
+ operands[2] = gen_lowpart (SImode, operands[0]);
+
+ operands[3] = GEN_INT(l);
+}")
+
+(define_insn "*movsf_hardfloat"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=!r,!r,m,f,f,m,!r,!r")
+ (match_operand:SF 1 "input_operand" "r,m,r,f,m,f,G,Fn"))]
+ "(gpc_reg_operand (operands[0], SFmode)
+ || gpc_reg_operand (operands[1], SFmode)) && TARGET_HARD_FLOAT"
+ "@
+ mr %0,%1
+ {l%U1%X1|lwz%U1%X1} %0,%1
+ {st%U0%X0|stw%U0%X0} %1,%0
+ fmr %0,%1
+ lfs%U1%X1 %0,%1
+ stfs%U0%X0 %1,%0
+ #
+ #"
+ [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*")
+ (set_attr "length" "4,4,4,4,4,4,4,8")])
+
+(define_insn "*movsf_softfloat"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,r")
+ (match_operand:SF 1 "input_operand" "r,m,r,I,J,R,G,Fn"))]
+ "(gpc_reg_operand (operands[0], SFmode)
+ || gpc_reg_operand (operands[1], SFmode)) && TARGET_SOFT_FLOAT"
+ "@
+ mr %0,%1
+ {l%U1%X1|lwz%U1%X1} %0,%1
+ {st%U0%X0|stw%U0%X0} %1,%0
+ {lil|li} %0,%1
+ {liu|lis} %0,%v1
+ {cal|la} %0,%1(%*)
+ #
+ #"
+ [(set_attr "type" "*,load,store,*,*,*,*,*")
+ (set_attr "length" "4,4,4,4,4,4,4,8")])
+
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (match_operand:DF 1 "any_operand" ""))]
+ ""
+ "
+{
+ if (GET_CODE (operands[0]) != REG)
+ operands[1] = force_reg (DFmode, operands[1]);
+
+ if (CONSTANT_P (operands[1]) && ! easy_fp_constant (operands[1], DFmode))
+ {
+ operands[1] = force_const_mem (DFmode, operands[1]);
+ if (! memory_address_p (DFmode, XEXP (operands[1], 0))
+ && ! reload_in_progress)
+ operands[1] = change_address (operands[1], DFmode,
+ XEXP (operands[1], 0));
+ }
+}")
+
+(define_split
+ [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (match_operand:DF 1 "const_int_operand" ""))]
+ "! TARGET_POWERPC64 && reload_completed
+ && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
+ || (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (SUBREG_REG (operands[0])) <= 31))"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 1))]
+ "
+{
+ int endian = (WORDS_BIG_ENDIAN == 0);
+ operands[2] = operand_subword (operands[0], endian, 0, DFmode);
+ operands[3] = operand_subword (operands[0], 1 - endian, 0, DFmode);
+ operands[4] = (INTVAL (operands[1]) & 0x80000000) ? constm1_rtx : const0_rtx;
+}")
+
+(define_split
+ [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (match_operand:DF 1 "const_double_operand" ""))]
+ "! TARGET_POWERPC64 && reload_completed
+ && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
+ || (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (SUBREG_REG (operands[0])) <= 31))"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+ "
+{
+ int endian = (WORDS_BIG_ENDIAN == 0);
+ long l[2];
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
+
+ operands[2] = operand_subword (operands[0], endian, 0, DFmode);
+ operands[3] = operand_subword (operands[0], 1 - endian, 0, DFmode);
+ operands[4] = GEN_INT (l[endian]);
+ operands[5] = GEN_INT (l[1 - endian]);
+}")
+
+(define_split
+ [(set (match_operand:DF 0 "gpc_reg_operand" "")
+ (match_operand:DF 1 "easy_fp_constant" ""))]
+ "TARGET_POWERPC64 && reload_completed
+ && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
+ || (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (SUBREG_REG (operands[0])) <= 31))"
+ [(set (match_dup 2) (match_dup 3))]
+ "
+{
+ int endian = (WORDS_BIG_ENDIAN == 0);
+ long l[2];
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
+
+ operands[2] = gen_lowpart (DImode, operands[0]);
+ /* HIGHPART is lower memory address when WORDS_BIG_ENDIAN. */
+ operands[3] = immed_double_const (l[1 - endian], l[endian], DImode);
+}")
+
+;; Don't have reload use general registers to load a constant. First,
+;; it might not work if the output operand is the equivalent of
+;; a non-offsettable memref, but also it is less efficient than loading
+;; the constant into an FP register, since it will probably be used there.
+;; The "??" is a kludge until we can figure out a more reasonable way
+;; of handling these non-offsettable values.
+;; CYGNUS LOCAL -- meissner/add non-offsetable load
+(define_insn "*movdf_hardfloat32"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,&????r,o,!r,!r,!r,f,f,m")
+ (match_operand:DF 1 "input_operand" "r,o,m,r,G,H,F,f,m,f"))]
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT
+ && (register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
+ "*
+{
+ switch (which_alternative)
+ {
+ default:
+ abort ();
+ case 0:
+ /* We normally copy the low-numbered register first. However, if
+ the first register operand 0 is the same as the second register of
+ operand 1, we must copy in the opposite order. */
+ if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
+ return \"mr %L0,%L1\;mr %0,%1\";
+ else
+ return \"mr %0,%1\;mr %L0,%L1\";
+ case 1:
+ /* If the low-address word is used in the address, we must load it
+ last. Otherwise, load it first. Note that we cannot have
+ auto-increment in that case since the address register is known to be
+ dead. */
+ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+ operands [1], 0))
+ return \"{l|lwz} %L0,%L1\;{l|lwz} %0,%1\";
+ else
+ return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\";
+ /* We don't have an offsetable address for the load, use the bottom register
+ being loaded to hold the address. */
+ case 2:
+ {
+ rtx addr = XEXP (operands[1], 0);
+
+ if ((GET_CODE (addr) == PLUS || GET_CODE (addr) == LO_SUM)
+ && GET_CODE (XEXP (addr, 0)) == REG)
+ {
+ rtx left = XEXP (addr, 0);
+ rtx right = XEXP (addr, 1);
+
+ operands[2] = left;
+ operands[3] = right;
+
+ if (GET_CODE (right) == REG)
+ return \"{cax|add} %L0,%2,%3\;{l|lwz} %0,0(%L0)\;{l|lwz} %L0,4(%L0)\";
+
+ else if (TARGET_ELF && CONSTANT_P (right))
+ return \"{cal|la} %L0,%3@l(%2)\;{l|lwz} %0,0(%L0)\;{l|lwz} %L0,4(%L0)\";
+ }
+ fatal_insn (\"nonoffsetable movdf case not handled\", insn);
+ }
+ case 3:
+ return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\";
+ case 4:
+ case 5:
+ case 6:
+ return \"#\";
+ case 7:
+ return \"fmr %0,%1\";
+ case 8:
+ return \"lfd%U1%X1 %0,%1\";
+ case 9:
+ return \"stfd%U0%X0 %1,%0\";
+ }
+}"
+ [(set_attr "type" "*,load,load,store,*,*,*,fp,fpload,fpstore")
+ (set_attr "length" "8,8,12,8,8,12,16,*,*,*")])
+;; END CYGNUS LOCAL -- meissner/add non-offsetable load
+
+(define_insn "*movdf_softfloat32"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,r,r,r")
+ (match_operand:DF 1 "input_operand" "r,m,r,G,H,F"))]
+ "! TARGET_POWERPC64 && TARGET_SOFT_FLOAT
+ && (register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
+ "*
+{
+ switch (which_alternative)
+ {
+ default:
+ abort ();
+ case 0:
+ /* We normally copy the low-numbered register first. However, if
+ the first register operand 0 is the same as the second register of
+ operand 1, we must copy in the opposite order. */
+ if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
+ return \"mr %L0,%L1\;mr %0,%1\";
+ else
+ return \"mr %0,%1\;mr %L0,%L1\";
+ case 1:
+ /* If the low-address word is used in the address, we must load it
+ last. Otherwise, load it first. Note that we cannot have
+ auto-increment in that case since the address register is known to be
+ dead. */
+ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+ operands [1], 0))
+ return \"{l|lwz} %L0,%L1\;{l|lwz} %0,%1\";
+ else
+ return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\";
+ case 2:
+ return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\";
+ case 3:
+ case 4:
+ case 5:
+ return \"#\";
+ }
+}"
+ [(set_attr "type" "*,load,store,*,*,*")
+ (set_attr "length" "8,8,8,8,12,16")])
+
+(define_insn "*movdf_hardfloat64"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,m,!r,!r,!r,f,f,m")
+ (match_operand:DF 1 "input_operand" "r,m,r,G,H,F,f,m,f"))]
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT
+ && (register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
+ "@
+ mr %0,%1
+ ld%U1%X1 %0,%1
+ std%U0%X0 %1,%0
+ #
+ #
+ #
+ fmr %0,%1
+ lfd%U1%X1 %0,%1
+ stfd%U0%X0 %1,%0"
+ [(set_attr "type" "*,load,store,*,*,*,fp,fpload,fpstore")
+ (set_attr "length" "4,4,4,8,12,16,4,4,4")])
+
+(define_insn "*movdf_softfloat64"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,r,r,r")
+ (match_operand:DF 1 "input_operand" "r,m,r,G,H,F"))]
+ "TARGET_POWERPC64 && TARGET_SOFT_FLOAT
+ && (register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
+ "@
+ mr %0,%1
+ ld%U1%X1 %0,%1
+ std%U0%X0 %1,%0
+ #
+ #
+ #"
+ [(set_attr "type" "*,load,store,*,*,*")
+ (set_attr "length" "*,*,*,8,12,16")])
+
+;; Next come the multi-word integer load and store and the load and store
+;; multiple insns.
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "any_operand" ""))]
+ ""
+ "
+{
+ if (GET_CODE (operands[0]) != REG)
+ operands[1] = force_reg (DImode, operands[1]);
+
+ /* Convert a move of a CONST_DOUBLE into a CONST_INT
+ only if sign-extended lower-half for 32-bit host. */
+ 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]) == 0xffffffff
+ && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) != 0))
+#endif
+ )
+ operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
+
+ if (TARGET_64BIT
+ && CONSTANT_P (operands[1])
+#if HOST_BITS_PER_WIDE_INT == 32
+ && GET_CODE (operands[1]) != CONST_INT
+ && GET_CODE (operands[1]) != CONSTANT_P_RTX
+#endif
+ && ! easy_fp_constant (operands[1], DImode)
+ && ! LEGITIMATE_CONSTANT_POOL_ADDRESS_P (operands[1]))
+ {
+ /* Emit a USE operation so that the constant isn't deleted if
+ expensive optimizations are turned on because nobody
+ references it. This should only be done for operands that
+ contain SYMBOL_REFs with CONSTANT_POOL_ADDRESS_P set.
+ This should not be done for operands that contain LABEL_REFs.
+ For now, we just handle the obvious case. */
+ if (GET_CODE (operands[1]) != LABEL_REF)
+ emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
+
+ /* If we are to limit the number of things we put in the TOC and
+ this is a symbol plus a constant we can add in one insn,
+ just put the symbol in the TOC and add the constant. Don't do
+ this if reload is in progress. */
+ if (GET_CODE (operands[1]) == CONST
+ && TARGET_NO_SUM_IN_TOC && ! reload_in_progress
+ && GET_CODE (XEXP (operands[1], 0)) == PLUS
+ && add_operand (XEXP (XEXP (operands[1], 0), 1), DImode)
+ && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
+ || GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
+ && ! side_effects_p (operands[0]))
+ {
+ rtx sym = force_const_mem (DImode, XEXP (XEXP (operands[1], 0), 0));
+ rtx other = XEXP (XEXP (operands[1], 0), 1);
+
+ emit_insn (gen_adddi3 (operands[0], force_reg (DImode, sym), other));
+ DONE;
+ }
+
+ operands[1] = force_const_mem (DImode, operands[1]);
+ if (! memory_address_p (DImode, XEXP (operands[1], 0))
+ && ! reload_in_progress)
+ operands[1] = change_address (operands[1], DImode,
+ XEXP (operands[1], 0));
+ }
+}")
+
+(define_insn "*movdi_32"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m,r,r,r,r,r")
+ (match_operand:DI 1 "input_operand" "r,m,r,f,m,f,IJK,n,G,H,F"))]
+ "! TARGET_POWERPC64
+ && (gpc_reg_operand (operands[0], DImode)
+ || gpc_reg_operand (operands[1], DImode))"
+ "*
+{
+ switch (which_alternative)
+ {
+ default:
+ abort ();
+ case 0:
+ /* We normally copy the low-numbered register first. However, if
+ the first register operand 0 is the same as the second register of
+ operand 1, we must copy in the opposite order. */
+ if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
+ return \"mr %L0,%L1\;mr %0,%1\";
+ else
+ return \"mr %0,%1\;mr %L0,%L1\";
+ case 1:
+ /* If the low-address word is used in the address, we must load it
+ last. Otherwise, load it first. Note that we cannot have
+ auto-increment in that case since the address register is known to be
+ dead. */
+ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+ operands [1], 0))
+ return \"{l|lwz} %L0,%L1\;{l|lwz} %0,%1\";
+ else
+ return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\";
+ case 2:
+ return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\";
+ case 3:
+ return \"fmr %0,%1\";
+ case 4:
+ return \"lfd%U1%X1 %0,%1\";
+ case 5:
+ return \"stfd%U0%X0 %1,%0\";
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ return \"#\";
+ }
+}"
+ [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*,*,*,*")
+ (set_attr "length" "8,8,8,*,*,*,8,12,8,12,16")])
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_int_operand" ""))]
+ "! TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 1))]
+ "
+{
+ operands[2] = gen_rtx_SUBREG (SImode, operands[0], WORDS_BIG_ENDIAN == 0);
+ operands[3] = gen_rtx_SUBREG (SImode, operands[0], WORDS_BIG_ENDIAN != 0);
+#if HOST_BITS_PER_WIDE_INT == 32
+ operands[4] = (INTVAL (operands[1]) & 0x80000000) ? constm1_rtx : const0_rtx;
+#else
+ operands[4] = (HOST_WIDE_INT) INTVAL (operands[1]) >> 32;
+ operands[1] = INTVAL (operands[1]) & 0xffffffff;
+#endif
+}")
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_double_operand" ""))]
+ "HOST_BITS_PER_WIDE_INT == 32 && ! TARGET_POWERPC64 && reload_completed"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+ "
+{
+ operands[2] = gen_rtx_SUBREG (SImode, operands[0], WORDS_BIG_ENDIAN == 0);
+ operands[3] = gen_rtx_SUBREG (SImode, operands[0], WORDS_BIG_ENDIAN != 0);
+ operands[4] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
+ operands[5] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
+}")
+
+(define_insn "*movdi_64"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,f,f,m,r,*h,*h")
+ (match_operand:DI 1 "input_operand" "r,m,r,I,J,nF,R,f,m,f,*h,r,0"))]
+ "TARGET_POWERPC64
+ && (gpc_reg_operand (operands[0], DImode)
+ || gpc_reg_operand (operands[1], DImode))"
+ "@
+ mr %0,%1
+ ld%U1%X1 %0,%1
+ std%U0%X0 %1,%0
+ li %0,%1
+ lis %0,%v1
+ #
+ {cal|la} %0,%1(%*)
+ fmr %0,%1
+ lfd%U1%X1 %0,%1
+ stfd%U0%X0 %1,%0
+ mf%1 %0
+ mt%0 %1
+ cror 0,0,0"
+ [(set_attr "type" "*,load,store,*,*,*,*,fp,fpload,fpstore,*,mtjmpr,*")
+ (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (match_operand:DI 1 "const_double_operand" "F"))]
+ "TARGET_POWERPC64 && GET_CODE (operands[1]) == CONST_DOUBLE
+ && num_insns_constant (operands[1], DImode) == 1"
+ "*
+{
+ return ((unsigned HOST_WIDE_INT)
+ (CONST_DOUBLE_LOW (operands[1]) + 0x8000) < 0x10000)
+ ? \"li %0,%1\" : \"lis %0,%v1\";
+}")
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_int_operand" ""))]
+ "HOST_BITS_PER_WIDE_INT == 32 && TARGET_POWERPC64
+ && num_insns_constant (operands[1], DImode) > 1"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (ior:DI (match_dup 0)
+ (match_dup 3)))]
+ "
+{
+ operands[2] = GEN_INT (INTVAL (operands[1]) & 0xffff0000);
+ operands[3] = GEN_INT (INTVAL (operands[1]) & 0xffff);
+}")
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_double_operand" ""))]
+ "HOST_BITS_PER_WIDE_INT == 32 && TARGET_POWERPC64
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && ((CONST_DOUBLE_HIGH (operands[1]) == 0
+ && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) == 0)
+ || (CONST_DOUBLE_HIGH (operands[1]) == 0xffffffff
+ && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) != 0))"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (ior:DI (match_dup 0)
+ (match_dup 3)))]
+ "
+{
+ operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[1]) & 0xffff0000);
+ operands[3] = GEN_INT (CONST_DOUBLE_LOW (operands[1]) & 0xffff);
+}")
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_double_operand" ""))]
+ "HOST_BITS_PER_WIDE_INT == 32 && TARGET_POWERPC64
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && CONST_DOUBLE_HIGH (operands[1]) == 0
+ && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) != 0"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (zero_extend:DI (subreg:SI (match_dup 0) 0)))]
+ "
+{ operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); }")
+
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_double_operand" ""))]
+ "HOST_BITS_PER_WIDE_INT == 32 && TARGET_POWERPC64
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && CONST_DOUBLE_LOW (operands[1]) == 0"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (ashift:DI (match_dup 0)
+ (const_int 32)))]
+ "
+{ operands[2] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); }")
+
+;; Generate all one-bits and clear left or right.
+;; Use (and:DI (rotate:DI ...)) to avoid anddi3 unnecessary clobber.
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "mask64_operand" ""))]
+ "TARGET_POWERPC64 && num_insns_constant (operands[1], DImode) > 1"
+ [(set (match_dup 0) (const_int -1))
+ (set (match_dup 0)
+ (and:DI (rotate:DI (match_dup 0)
+ (const_int 0))
+ (match_dup 1)))]
+ "")
+
+;; Split a load of a large constant into the appropriate five-instruction
+;; sequence. Handle anything in a constant number of insns.
+;; When non-easy constants can go in the TOC, this should use
+;; easy_fp_constant predicate.
+(define_split
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "const_double_operand" ""))]
+ "TARGET_POWERPC64 && num_insns_constant (operands[1], DImode) > 1"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (ashift:DI (match_dup 0)
+ (const_int 32)))
+ (set (match_dup 0)
+ (ior:DI (match_dup 0)
+ (match_dup 3)))]
+ "
+{
+ HOST_WIDE_INT low;
+ HOST_WIDE_INT high;
+
+ if (GET_CODE (operands[1]) == CONST_DOUBLE)
+ {
+ low = CONST_DOUBLE_LOW (operands[1]);
+ high = CONST_DOUBLE_HIGH (operands[1]);
+ }
+ else
+#if HOST_BITS_PER_WIDE_INT == 32
+ {
+ low = INTVAL (operands[1]);
+ high = (low < 0) ? ~0 : 0;
+ }
+#else
+ {
+ low = INTVAL (operands[1]) & 0xffffffff;
+ high = (HOST_WIDE_INT) INTVAL (operands[1]) >> 32;
+ }
+#endif
+
+ operands[2] = GEN_INT (high);
+ operands[3] = GEN_INT (low);
+}")
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC (match_operand:DI 1 "gpc_reg_operand" "r,r")
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") (match_dup 1))]
+ "TARGET_POWERPC64"
+ "@
+ mr. %0,%1
+ #"
+ [(set_attr "type" "compare")])
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (match_operand:DI 1 "gpc_reg_operand" "")
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_dup 1))]
+ "reload_completed && rtx_equal_p (operands[0], operands[1])"
+ [(set (match_dup 2)
+ (compare:CC (match_dup 1)
+ (const_int 0)))]
+ "")
+
+(define_split
+ [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+ (compare:CC (match_operand:DI 1 "gpc_reg_operand" "")
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_dup 1))]
+ "reload_completed && !rtx_equal_p (operands[0], operands[1])"
+ [(set (match_dup 2)
+ (compare:CC (match_dup 1)
+ (const_int 0)))
+ (set (match_dup 0)
+ (match_dup 1))]
+ "")
+
+;; TImode is similar, except that we usually want to compute the address into
+;; a register and use lsi/stsi (the exception is during reload). MQ is also
+;; clobbered in stsi for POWER, so we need a SCRATCH for it.
+(define_expand "movti"
+ [(parallel [(set (match_operand:TI 0 "general_operand" "")
+ (match_operand:TI 1 "general_operand" ""))
+ (clobber (scratch:SI))])]
+ "TARGET_STRING || TARGET_POWERPC64"
+ "
+{
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (TImode, operands[1]);
+
+ if (GET_CODE (operands[0]) == MEM
+ && GET_CODE (XEXP (operands[0], 0)) != REG
+ && ! reload_in_progress)
+ operands[0] = change_address (operands[0], TImode,
+ copy_addr_to_reg (XEXP (operands[0], 0)));
+
+ if (GET_CODE (operands[1]) == MEM
+ && GET_CODE (XEXP (operands[1], 0)) != REG
+ && ! reload_in_progress)
+ operands[1] = change_address (operands[1], TImode,
+ copy_addr_to_reg (XEXP (operands[1], 0)));
+}")
+
+;; We say that MQ is clobbered in the last alternative because the first
+;; alternative would never get used otherwise since it would need a reload
+;; while the 2nd alternative would not. We put memory cases first so they
+;; are preferred. Otherwise, we'd try to reload the output instead of
+;; giving the SCRATCH mq.
+(define_insn "*movti_power"
+ [(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
+ (match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))
+ (clobber (match_scratch:SI 2 "=q,q#X,X,X,X"))]
+ "TARGET_STRING && TARGET_POWER && ! TARGET_POWERPC64
+ && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
+ "*
+{
+ switch (which_alternative)
+ {
+ default:
+ abort ();
+
+ case 0:
+ return \"{stsi|stswi} %1,%P0,16\";
+
+ case 1:
+ return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\;{st|stw} %Y1,%Y0\;{st|stw} %Z1,%Z0\";
+
+ case 2:
+ /* Normally copy registers with lowest numbered register copied first.
+ But copy in the other order if the first register of the output
+ is the second, third, or fourth register in the input. */
+ if (REGNO (operands[0]) >= REGNO (operands[1]) + 1
+ && REGNO (operands[0]) <= REGNO (operands[1]) + 3)
+ return \"mr %Z0,%Z1\;mr %Y0,%Y1\;mr %L0,%L1\;mr %0,%1\";
+ else
+ return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
+ case 3:
+ /* If the address is not used in the output, we can use lsi. Otherwise,
+ fall through to generating four loads. */
+ if (! reg_overlap_mentioned_p (operands[0], operands[1]))
+ return \"{lsi|lswi} %0,%P1,16\";
+ /* ... fall through ... */
+ case 4:
+ /* If the address register is the same as the register for the lowest-
+ addressed word, load it last. Similarly for the next two words.
+ Otherwise load lowest address to highest. */
+ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+ operands[1], 0))
+ return \"{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %0,%1\";
+ else if (refers_to_regno_p (REGNO (operands[0]) + 1,
+ REGNO (operands[0]) + 2, operands[1], 0))
+ return \"{l|lwz} %0,%1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %L0,%L1\";
+ else if (refers_to_regno_p (REGNO (operands[0]) + 2,
+ REGNO (operands[0]) + 3, operands[1], 0))
+ return \"{l|lwz} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Z0,%Z1\;{l|lwz} %Y0,%Y1\";
+ else
+ return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\";
+ }
+}"
+ [(set_attr "type" "store,store,*,load,load")
+ (set_attr "length" "*,16,16,*,16")])
+
+(define_insn "*movti_string"
+ [(set (match_operand:TI 0 "reg_or_mem_operand" "=m,????r,????r")
+ (match_operand:TI 1 "reg_or_mem_operand" "r,r,m"))
+ (clobber (match_scratch:SI 2 "=X,X,X"))]
+ "TARGET_STRING && !TARGET_POWER && ! TARGET_POWERPC64
+ && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
+ "*
+{
+ switch (which_alternative)
+ {
+ default:
+ abort ();
+
+ case 0:
+ return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\;{st|stw} %Y1,%Y0\;{st|stw} %Z1,%Z0\";
+
+ case 1:
+ /* Normally copy registers with lowest numbered register copied first.
+ But copy in the other order if the first register of the output
+ is the second, third, or fourth register in the input. */
+ if (REGNO (operands[0]) >= REGNO (operands[1]) + 1
+ && REGNO (operands[0]) <= REGNO (operands[1]) + 3)
+ return \"mr %Z0,%Z1\;mr %Y0,%Y1\;mr %L0,%L1\;mr %0,%1\";
+ else
+ return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
+ case 2:
+ /* If the address register is the same as the register for the lowest-
+ addressed word, load it last. Similarly for the next two words.
+ Otherwise load lowest address to highest. */
+ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+ operands[1], 0))
+ return \"{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %0,%1\";
+ else if (refers_to_regno_p (REGNO (operands[0]) + 1,
+ REGNO (operands[0]) + 2, operands[1], 0))
+ return \"{l|lwz} %0,%1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %L0,%L1\";
+ else if (refers_to_regno_p (REGNO (operands[0]) + 2,
+ REGNO (operands[0]) + 3, operands[1], 0))
+ return \"{l|lwz} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Z0,%Z1\;{l|lwz} %Y0,%Y1\";
+ else
+ return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\";
+ }
+}"
+ [(set_attr "type" "store,*,load")
+ (set_attr "length" "16,16,16")])
+
+(define_insn "*movti_ppc64"
+ [(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m")
+ (match_operand:TI 1 "input_operand" "r,m,r"))]
+ "TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
+ || gpc_reg_operand (operands[1], TImode))"
+ "*
+{
+ switch (which_alternative)
+ {
+ default:
+ abort ();
+ case 0:
+ /* We normally copy the low-numbered register first. However, if
+ the first register operand 0 is the same as the second register of
+ operand 1, we must copy in the opposite order. */
+ if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
+ return \"mr %L0,%L1\;mr %0,%1\";
+ else
+ return \"mr %0,%1\;mr %L0,%L1\";
+ case 1:
+ /* If the low-address word is used in the address, we must load it
+ last. Otherwise, load it first. Note that we cannot have
+ auto-increment in that case since the address register is known to be
+ dead. */
+ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+ operands [1], 0))
+ return \"ld %L0,%L1\;ld %0,%1\";
+ else
+ return \"ld%U1 %0,%1\;ld %L0,%L1\";
+ case 2:
+ return \"std%U0 %1,%0\;std %L1,%L0\";
+ }
+}"
+ [(set_attr "type" "*,load,store")
+ (set_attr "length" "8,8,8")])
+
+(define_expand "load_multiple"
+ [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" ""))
+ (use (match_operand:SI 2 "" ""))])]
+ "TARGET_STRING"
+ "
+{
+ int regno;
+ int count;
+ rtx from;
+ int i;
+
+ /* Support only loading a constant number of fixed-point registers from
+ memory and only bother with this if more than two; the machine
+ doesn't support more than eight. */
+ if (GET_CODE (operands[2]) != CONST_INT
+ || INTVAL (operands[2]) <= 2
+ || INTVAL (operands[2]) > 8
+ || GET_CODE (operands[1]) != MEM
+ || GET_CODE (operands[0]) != REG
+ || REGNO (operands[0]) >= 32)
+ FAIL;
+
+ count = INTVAL (operands[2]);
+ regno = REGNO (operands[0]);
+
+ operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
+ from = force_reg (SImode, XEXP (operands[1], 0));
+
+ for (i = 0; i < count; i++)
+ XVECEXP (operands[3], 0, i)
+ = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, regno + i),
+ change_address (operands[1], SImode,
+ plus_constant (from, i * 4)));
+}")
+
+(define_insn ""
+ [(match_parallel 0 "load_multiple_operation"
+ [(set (match_operand:SI 1 "gpc_reg_operand" "=r")
+ (mem:SI (match_operand:SI 2 "register_operand" "b")))])]
+ "TARGET_STRING"
+ "*
+{
+ /* We have to handle the case where the pseudo used to contain the address
+ is assigned to one of the output registers. */
+ int i, j;
+ int words = XVECLEN (operands[0], 0);
+ rtx xop[10];
+
+ if (XVECLEN (operands[0], 0) == 1)
+ return \"{l|lwz} %1,0(%2)\";
+
+ for (i = 0; i < words; i++)
+ if (refers_to_regno_p (REGNO (operands[1]) + i,
+ REGNO (operands[1]) + i + 1, operands[2], 0))
+ {
+ if (i == words-1)
+ {
+ xop[0] = operands[1];
+ xop[1] = operands[2];
+ xop[2] = GEN_INT (4 * (words-1));
+ output_asm_insn (\"{lsi|lswi} %0,%1,%2\;{l|lwz} %1,%2(%1)\", xop);
+ return \"\";
+ }
+ else if (i == 0)
+ {
+ xop[0] = operands[1];
+ xop[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
+ xop[2] = GEN_INT (4 * (words-1));
+ output_asm_insn (\"{cal %0,4(%0)|addi %0,%0,4}\;{lsi|lswi} %1,%0,%2\;{l|lwz} %0,-4(%0)\", xop);
+ return \"\";
+ }
+ else
+ {
+ for (j = 0; j < words; j++)
+ if (j != i)
+ {
+ xop[0] = gen_rtx_REG (SImode, REGNO (operands[1]) + j);
+ xop[1] = operands[2];
+ xop[2] = GEN_INT (j * 4);
+ output_asm_insn (\"{l|lwz} %0,%2(%1)\", xop);
+ }
+ xop[0] = operands[2];
+ xop[1] = GEN_INT (i * 4);
+ output_asm_insn (\"{l|lwz} %0,%1(%0)\", xop);
+ return \"\";
+ }
+ }
+
+ return \"{lsi|lswi} %1,%2,%N0\";
+}"
+ [(set_attr "type" "load")
+ (set_attr "length" "32")])
+
+
+(define_expand "store_multiple"
+ [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" ""))
+ (clobber (scratch:SI))
+ (use (match_operand:SI 2 "" ""))])]
+ "TARGET_STRING"
+ "
+{
+ int regno;
+ int count;
+ rtx to;
+ int i;
+
+ /* Support only storing a constant number of fixed-point registers to
+ memory and only bother with this if more than two; the machine
+ doesn't support more than eight. */
+ if (GET_CODE (operands[2]) != CONST_INT
+ || INTVAL (operands[2]) <= 2
+ || INTVAL (operands[2]) > 8
+ || GET_CODE (operands[0]) != MEM
+ || GET_CODE (operands[1]) != REG
+ || REGNO (operands[1]) >= 32)
+ FAIL;
+
+ count = INTVAL (operands[2]);
+ regno = REGNO (operands[1]);
+
+ operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1));
+ to = force_reg (SImode, XEXP (operands[0], 0));
+
+ XVECEXP (operands[3], 0, 0)
+ = gen_rtx_SET (VOIDmode, change_address (operands[0], SImode, to),
+ operands[1]);
+ XVECEXP (operands[3], 0, 1) = gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_SCRATCH (SImode));
+
+ for (i = 1; i < count; i++)
+ XVECEXP (operands[3], 0, i + 1)
+ = gen_rtx_SET (VOIDmode,
+ change_address (operands[0], SImode,
+ plus_constant (to, i * 4)),
+ gen_rtx_REG (SImode, regno + i));
+}")
+
+(define_insn ""
+ [(match_parallel 0 "store_multiple_operation"
+ [(set (match_operand:SI 1 "indirect_operand" "=Q")
+ (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (clobber (match_scratch:SI 3 "=q"))])]
+ "TARGET_STRING && TARGET_POWER"
+ "{stsi|stswi} %2,%P1,%O0"
+ [(set_attr "type" "store")])
+
+(define_insn ""
+ [(match_parallel 0 "store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 1 "register_operand" "b"))
+ (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (clobber (match_scratch:SI 3 "X"))])]
+ "TARGET_STRING && !TARGET_POWER"
+ "{stsi|stswi} %2,%1,%O0"
+ [(set_attr "type" "store")])
+
+
+;; String/block move insn.
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+
+(define_expand "movstrsi"
+ [(parallel [(set (match_operand:BLK 0 "" "")
+ (match_operand:BLK 1 "" ""))
+ (use (match_operand:SI 2 "" ""))
+ (use (match_operand:SI 3 "" ""))])]
+ ""
+ "
+{
+ if (expand_block_move (operands))
+ DONE;
+ else
+ FAIL;
+}")
+
+;; Move up to 32 bytes at a time. The fixed registers are needed because the
+;; register allocator doesn't have a clue about allocating 8 word registers
+(define_expand "movstrsi_8reg"
+ [(parallel [(set (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (use (match_operand 3 "" ""))
+ (clobber (reg:SI 5))
+ (clobber (reg:SI 6))
+ (clobber (reg:SI 7))
+ (clobber (reg:SI 8))
+ (clobber (reg:SI 9))
+ (clobber (reg:SI 10))
+ (clobber (reg:SI 11))
+ (clobber (reg:SI 12))
+ (clobber (match_scratch:SI 4 ""))])]
+ "TARGET_STRING"
+ "")
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_operand:SI 4 "register_operand" "=r"))
+ (clobber (reg:SI 6))
+ (clobber (reg:SI 7))
+ (clobber (reg:SI 8))
+ (clobber (reg:SI 9))
+ (clobber (reg:SI 10))
+ (clobber (reg:SI 11))
+ (clobber (reg:SI 12))
+ (clobber (match_scratch:SI 5 "=q"))]
+ "TARGET_STRING && TARGET_POWER
+ && ((INTVAL (operands[2]) > 24 && INTVAL (operands[2]) < 32) || INTVAL (operands[2]) == 0)
+ && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 12)
+ && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 12)
+ && REGNO (operands[4]) == 5"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_operand:SI 4 "register_operand" "=r"))
+ (clobber (reg:SI 6))
+ (clobber (reg:SI 7))
+ (clobber (reg:SI 8))
+ (clobber (reg:SI 9))
+ (clobber (reg:SI 10))
+ (clobber (reg:SI 11))
+ (clobber (reg:SI 12))
+ (clobber (match_scratch:SI 5 "X"))]
+ "TARGET_STRING && !TARGET_POWER
+ && ((INTVAL (operands[2]) > 24 && INTVAL (operands[2]) < 32) || INTVAL (operands[2]) == 0)
+ && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 12)
+ && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 12)
+ && REGNO (operands[4]) == 5"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+;; Move up to 24 bytes at a time. The fixed registers are needed because the
+;; register allocator doesn't have a clue about allocating 6 word registers
+(define_expand "movstrsi_6reg"
+ [(parallel [(set (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (use (match_operand 3 "" ""))
+ (clobber (reg:SI 7))
+ (clobber (reg:SI 8))
+ (clobber (reg:SI 9))
+ (clobber (reg:SI 10))
+ (clobber (reg:SI 11))
+ (clobber (reg:SI 12))
+ (clobber (match_scratch:SI 4 ""))])]
+ "TARGET_STRING"
+ "")
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_operand:SI 4 "register_operand" "=r"))
+ (clobber (reg:SI 8))
+ (clobber (reg:SI 9))
+ (clobber (reg:SI 10))
+ (clobber (reg:SI 11))
+ (clobber (reg:SI 12))
+ (clobber (match_scratch:SI 5 "=q"))]
+ "TARGET_STRING && TARGET_POWER
+ && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24
+ && (REGNO (operands[0]) < 7 || REGNO (operands[0]) > 12)
+ && (REGNO (operands[1]) < 7 || REGNO (operands[1]) > 12)
+ && REGNO (operands[4]) == 7"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_operand:SI 4 "register_operand" "=r"))
+ (clobber (reg:SI 8))
+ (clobber (reg:SI 9))
+ (clobber (reg:SI 10))
+ (clobber (reg:SI 11))
+ (clobber (reg:SI 12))
+ (clobber (match_scratch:SI 5 "X"))]
+ "TARGET_STRING && !TARGET_POWER
+ && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 32
+ && (REGNO (operands[0]) < 7 || REGNO (operands[0]) > 12)
+ && (REGNO (operands[1]) < 7 || REGNO (operands[1]) > 12)
+ && REGNO (operands[4]) == 7"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+;; Move up to 16 bytes at a time, using 4 fixed registers to avoid spill problems
+;; with TImode
+(define_expand "movstrsi_4reg"
+ [(parallel [(set (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (use (match_operand 3 "" ""))
+ (clobber (reg:SI 9))
+ (clobber (reg:SI 10))
+ (clobber (reg:SI 11))
+ (clobber (reg:SI 12))
+ (clobber (match_scratch:SI 4 ""))])]
+ "TARGET_STRING"
+ "")
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_operand:SI 4 "register_operand" "=r"))
+ (clobber (reg:SI 10))
+ (clobber (reg:SI 11))
+ (clobber (reg:SI 12))
+ (clobber (match_scratch:SI 5 "=q"))]
+ "TARGET_STRING && TARGET_POWER
+ && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16
+ && (REGNO (operands[0]) < 9 || REGNO (operands[0]) > 12)
+ && (REGNO (operands[1]) < 9 || REGNO (operands[1]) > 12)
+ && REGNO (operands[4]) == 9"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_operand:SI 4 "register_operand" "=r"))
+ (clobber (reg:SI 10))
+ (clobber (reg:SI 11))
+ (clobber (reg:SI 12))
+ (clobber (match_scratch:SI 5 "X"))]
+ "TARGET_STRING && !TARGET_POWER
+ && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16
+ && (REGNO (operands[0]) < 9 || REGNO (operands[0]) > 12)
+ && (REGNO (operands[1]) < 9 || REGNO (operands[1]) > 12)
+ && REGNO (operands[4]) == 9"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+;; Move up to 8 bytes at a time.
+(define_expand "movstrsi_2reg"
+ [(parallel [(set (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (use (match_operand 3 "" ""))
+ (clobber (match_scratch:DI 4 ""))
+ (clobber (match_scratch:SI 5 ""))])]
+ "TARGET_STRING && !TARGET_64BIT"
+ "")
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_scratch:DI 4 "=&r"))
+ (clobber (match_scratch:SI 5 "=q"))]
+ "TARGET_STRING && TARGET_POWER && !TARGET_64BIT
+ && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_scratch:DI 4 "=&r"))
+ (clobber (match_scratch:SI 5 "X"))]
+ "TARGET_STRING && !TARGET_POWER && !TARGET_64BIT
+ && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+;; Move up to 4 bytes at a time.
+(define_expand "movstrsi_1reg"
+ [(parallel [(set (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (use (match_operand 3 "" ""))
+ (clobber (match_scratch:SI 4 ""))
+ (clobber (match_scratch:SI 5 ""))])]
+ "TARGET_STRING"
+ "")
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_scratch:SI 4 "=&r"))
+ (clobber (match_scratch:SI 5 "=q"))]
+ "TARGET_STRING && TARGET_POWER
+ && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "register_operand" "b"))
+ (mem:BLK (match_operand:SI 1 "register_operand" "b")))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "immediate_operand" "i"))
+ (clobber (match_scratch:SI 4 "=&r"))
+ (clobber (match_scratch:SI 5 "X"))]
+ "TARGET_STRING && !TARGET_POWER
+ && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4"
+ "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
+ [(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+
+;; Define insns that do load or store with update. Some of these we can
+;; get by using pre-decrement or pre-increment, but the hardware can also
+;; do cases where the increment is not the size of the object.
+;;
+;; In all these cases, we use operands 0 and 1 for the register being
+;; incremented because those are the operands that local-alloc will
+;; tie and these are the pair most likely to be tieable (and the ones
+;; that will benefit the most).
+
+(define_insn "*movdi_update1"
+ [(set (match_operand:DI 3 "gpc_reg_operand" "=r,r")
+ (mem:DI (plus:DI (match_operand:DI 1 "gpc_reg_operand" "0,0")
+ (match_operand:DI 2 "reg_or_short_operand" "r,I"))))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=b,b")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64 && TARGET_UPDATE"
+ "@
+ ldux %3,%0,%2
+ ldu %3,%2(%0)"
+ [(set_attr "type" "load")])
+
+(define_insn "*movdi_update2"
+ [(set (match_operand:DI 3 "gpc_reg_operand" "=r")
+ (sign_extend:DI
+ (mem:SI (plus:DI (match_operand:DI 1 "gpc_reg_operand" "0")
+ (match_operand:DI 2 "gpc_reg_operand" "r")))))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=b")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64"
+ "lwaux %3,%0,%2"
+ [(set_attr "type" "load")])
+
+(define_insn "movdi_update"
+ [(set (mem:DI (plus:DI (match_operand:DI 1 "gpc_reg_operand" "0,0")
+ (match_operand:DI 2 "reg_or_short_operand" "r,I")))
+ (match_operand:DI 3 "gpc_reg_operand" "r,r"))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=b,b")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWERPC64 && TARGET_UPDATE"
+ "@
+ stdux %3,%0,%2
+ stdu %3,%2(%0)"
+ [(set_attr "type" "store")])
+
+(define_insn "*movsi_update1"
+ [(set (match_operand:SI 3 "gpc_reg_operand" "=r,r")
+ (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I"))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ {lux|lwzux} %3,%0,%2
+ {lu|lwzu} %3,%2(%0)"
+ [(set_attr "type" "load")])
+
+(define_insn "movsi_update"
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_UPDATE"
+ "@
+ {stux|stwux} %3,%0,%2
+ {stu|stwu} %3,%2(%0)"
+ [(set_attr "type" "store")])
+
+(define_insn "*movhi_update"
+ [(set (match_operand:HI 3 "gpc_reg_operand" "=r,r")
+ (mem:HI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I"))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_UPDATE"
+ "@
+ lhzux %3,%0,%2
+ lhzu %3,%2(%0)"
+ [(set_attr "type" "load")])
+
+(define_insn "*movhi_update2"
+ [(set (match_operand:SI 3 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI
+ (mem:HI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_UPDATE"
+ "@
+ lhzux %3,%0,%2
+ lhzu %3,%2(%0)"
+ [(set_attr "type" "load")])
+
+(define_insn "*movhi_update3"
+ [(set (match_operand:SI 3 "gpc_reg_operand" "=r,r")
+ (sign_extend:SI
+ (mem:HI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_UPDATE"
+ "@
+ lhaux %3,%0,%2
+ lhau %3,%2(%0)"
+ [(set_attr "type" "load")])
+
+(define_insn "*movhi_update4"
+ [(set (mem:HI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))
+ (match_operand:HI 3 "gpc_reg_operand" "r,r"))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_UPDATE"
+ "@
+ sthux %3,%0,%2
+ sthu %3,%2(%0)"
+ [(set_attr "type" "store")])
+
+(define_insn "*movqi_update1"
+ [(set (match_operand:QI 3 "gpc_reg_operand" "=r,r")
+ (mem:QI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I"))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_UPDATE"
+ "@
+ lbzux %3,%0,%2
+ lbzu %3,%2(%0)"
+ [(set_attr "type" "load")])
+
+(define_insn "*movqi_update2"
+ [(set (match_operand:SI 3 "gpc_reg_operand" "=r,r")
+ (zero_extend:SI
+ (mem:QI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_UPDATE"
+ "@
+ lbzux %3,%0,%2
+ lbzu %3,%2(%0)"
+ [(set_attr "type" "load")])
+
+(define_insn "*movqi_update3"
+ [(set (mem:QI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))
+ (match_operand:QI 3 "gpc_reg_operand" "r,r"))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_UPDATE"
+ "@
+ stbux %3,%0,%2
+ stbu %3,%2(%0)"
+ [(set_attr "type" "store")])
+
+(define_insn "*movsf_update1"
+ [(set (match_operand:SF 3 "gpc_reg_operand" "=f,f")
+ (mem:SF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I"))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_HARD_FLOAT && TARGET_UPDATE"
+ "@
+ lfsux %3,%0,%2
+ lfsu %3,%2(%0)"
+ [(set_attr "type" "fpload")])
+
+(define_insn "*movsf_update2"
+ [(set (mem:SF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))
+ (match_operand:SF 3 "gpc_reg_operand" "f,f"))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_HARD_FLOAT && TARGET_UPDATE"
+ "@
+ stfsux %3,%0,%2
+ stfsu %3,%2(%0)"
+ [(set_attr "type" "fpstore")])
+
+(define_insn "*movsf_update3"
+ [(set (match_operand:SF 3 "gpc_reg_operand" "=r,r")
+ (mem:SF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I"))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_SOFT_FLOAT && TARGET_UPDATE"
+ "@
+ {lux|lwzux} %3,%0,%2
+ {lu|lwzu} %3,%2(%0)"
+ [(set_attr "type" "load")])
+
+(define_insn "*movsf_update4"
+ [(set (mem:SF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))
+ (match_operand:SF 3 "gpc_reg_operand" "r,r"))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_SOFT_FLOAT && TARGET_UPDATE"
+ "@
+ {stux|stwux} %3,%0,%2
+ {stu|stwu} %3,%2(%0)"
+ [(set_attr "type" "store")])
+
+(define_insn "*movdf_update1"
+ [(set (match_operand:DF 3 "gpc_reg_operand" "=f,f")
+ (mem:DF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I"))))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_HARD_FLOAT && TARGET_UPDATE"
+ "@
+ lfdux %3,%0,%2
+ lfdu %3,%2(%0)"
+ [(set_attr "type" "fpload")])
+
+(define_insn "*movdf_update2"
+ [(set (mem:DF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I")))
+ (match_operand:DF 3 "gpc_reg_operand" "f,f"))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_HARD_FLOAT && TARGET_UPDATE"
+ "@
+ stfdux %3,%0,%2
+ stfdu %3,%2(%0)"
+ [(set_attr "type" "fpstore")])
+
+;; Peephole to convert two consecutive FP loads or stores into lfq/stfq.
+
+(define_peephole
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (match_operand:DF 1 "memory_operand" ""))
+ (set (match_operand:DF 2 "gpc_reg_operand" "=f")
+ (match_operand:DF 3 "memory_operand" ""))]
+ "TARGET_POWER2
+ && TARGET_HARD_FLOAT
+ && registers_ok_for_quad_peep (operands[0], operands[2])
+ && ! MEM_VOLATILE_P (operands[1]) && ! MEM_VOLATILE_P (operands[3])
+ && addrs_ok_for_quad_peep (XEXP (operands[1], 0), XEXP (operands[3], 0))"
+ "lfq%U1%X1 %0,%1")
+
+(define_peephole
+ [(set (match_operand:DF 0 "memory_operand" "")
+ (match_operand:DF 1 "gpc_reg_operand" "f"))
+ (set (match_operand:DF 2 "memory_operand" "")
+ (match_operand:DF 3 "gpc_reg_operand" "f"))]
+ "TARGET_POWER2
+ && TARGET_HARD_FLOAT
+ && registers_ok_for_quad_peep (operands[1], operands[3])
+ && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[2])
+ && addrs_ok_for_quad_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))"
+ "stfq%U0%X0 %1,%0")
+
+;; Next come insns related to the calling sequence.
+;;
+;; First, an insn to allocate new stack space for dynamic use (e.g., alloca).
+;; We move the back-chain and decrement the stack pointer.
+
+(define_expand "allocate_stack"
+ [(set (match_operand 0 "register_operand" "=r")
+ (minus (reg 1) (match_operand 1 "reg_or_short_operand" "")))
+ (set (reg 1)
+ (minus (reg 1) (match_dup 1)))]
+ ""
+ "
+{ rtx chain = gen_reg_rtx (Pmode);
+ rtx stack_bot = gen_rtx_MEM (Pmode, stack_pointer_rtx);
+ rtx neg_op0;
+
+ emit_move_insn (chain, stack_bot);
+
+ /* Under Windows NT, we need to add stack probes for large/variable
+ allocations, so do it via a call to the external function alloca
+ instead of doing it inline. */
+ if (DEFAULT_ABI == ABI_NT
+ && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) > 4096))
+ {
+ rtx tmp = gen_reg_rtx (Pmode);
+ emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, \"__allocate_stack\"),
+ tmp, 0, Pmode, 1, operands[1], Pmode);
+ emit_insn (gen_set_sp (tmp));
+ emit_move_insn (operands[0], tmp);
+ DONE;
+ }
+
+ if (GET_CODE (operands[1]) != CONST_INT
+ || INTVAL (operands[1]) < -32767
+ || INTVAL (operands[1]) > 32768)
+ {
+ neg_op0 = gen_reg_rtx (Pmode);
+ if (TARGET_32BIT)
+ emit_insn (gen_negsi2 (neg_op0, operands[1]));
+ else
+ emit_insn (gen_negdi2 (neg_op0, operands[1]));
+ }
+ else
+ neg_op0 = GEN_INT (- INTVAL (operands[1]));
+
+ if (TARGET_UPDATE)
+ emit_insn ((* ((TARGET_32BIT) ? gen_movsi_update : gen_movdi_update))
+ (stack_pointer_rtx, stack_pointer_rtx, neg_op0, chain));
+
+ else
+ {
+ emit_insn ((* ((TARGET_32BIT) ? gen_addsi3 : gen_adddi3))
+ (stack_pointer_rtx, stack_pointer_rtx, neg_op0));
+ emit_move_insn (gen_rtx_MEM (Pmode, stack_pointer_rtx), chain);
+ }
+
+ emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
+ DONE;
+}")
+
+;; Marker to indicate that the stack pointer was changed under NT in
+;; ways not known to the compiler
+
+(define_insn "set_sp"
+ [(set (reg:SI 1)
+ (unspec [(match_operand:SI 0 "register_operand" "r")] 7))]
+ ""
+ ""
+ [(set_attr "length" "0")])
+
+;; These patterns say how to save and restore the stack pointer. We need not
+;; save the stack pointer at function level since we are careful to
+;; preserve the backchain. At block level, we have to restore the backchain
+;; when we restore the stack pointer.
+;;
+;; For nonlocal gotos, we must save both the stack pointer and its
+;; backchain and restore both. Note that in the nonlocal case, the
+;; save area is a memory location.
+
+(define_expand "save_stack_function"
+ [(match_operand 0 "any_operand" "")
+ (match_operand 1 "any_operand" "")]
+ ""
+ "DONE;")
+
+(define_expand "restore_stack_function"
+ [(match_operand 0 "any_operand" "")
+ (match_operand 1 "any_operand" "")]
+ ""
+ "DONE;")
+
+(define_expand "restore_stack_block"
+ [(use (match_operand 0 "register_operand" ""))
+ (set (match_dup 2) (match_dup 3))
+ (set (match_dup 0) (match_operand 1 "register_operand" ""))
+ (set (match_dup 3) (match_dup 2))]
+ ""
+ "
+{
+ operands[2] = gen_reg_rtx (Pmode);
+ operands[3] = gen_rtx_MEM (Pmode, operands[0]);
+}")
+
+(define_expand "save_stack_nonlocal"
+ [(match_operand 0 "memory_operand" "")
+ (match_operand 1 "register_operand" "")]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx (Pmode);
+
+ /* Copy the backchain to the first word, sp to the second. */
+ emit_move_insn (temp, gen_rtx_MEM (Pmode, operands[1]));
+ emit_move_insn (operand_subword (operands[0], 0, 0, (TARGET_32BIT ? DImode : TImode)),
+ temp);
+ emit_move_insn (operand_subword (operands[0], 1, 0, (TARGET_32BIT ? DImode : TImode)),
+ operands[1]);
+ DONE;
+}")
+
+(define_expand "restore_stack_nonlocal"
+ [(match_operand 0 "register_operand" "")
+ (match_operand 1 "memory_operand" "")]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx (Pmode);
+
+ /* Restore the backchain from the first word, sp from the second. */
+ emit_move_insn (temp,
+ operand_subword (operands[1], 0, 0, (TARGET_32BIT ? DImode : TImode)));
+ emit_move_insn (operands[0],
+ operand_subword (operands[1], 1, 0, (TARGET_32BIT ? DImode : TImode)));
+ emit_move_insn (gen_rtx_MEM (Pmode, operands[0]), temp);
+ DONE;
+}")
+
+;; If we have -mminimal-toc, we need to reload r30 after a nonlocal goto.
+
+;; NB. Kenner removed the '&& get_pool_size() != 0' part of the condition
+;; on Oct 18, 1997 for an as yet undetermined reason. Without this condition,
+;; the powerpc-eabi targets mistakenly force a load of r30 at the beginning
+;; of exception handlers in functions which have no constant section.
+;; Presumably the original reason for the change will re-surface at some
+;; point, and this comment will help sort out the right thing to do.
+;; If this needs to be changed back again, it may be that the rs6000
+;; prologue code should have the equivilent change made so that there is
+;; a TOC value to restore. (It currently uses the get_pool_size() check).
+
+(define_insn "nonlocal_goto_receiver"
+ [(unspec_volatile [(const_int 0)] 1)]
+ "TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size() != 0"
+ "*
+{
+ rs6000_output_load_toc_table (asm_out_file, 30, FALSE);
+ return \"\";
+}"
+ [(set_attr "type" "load")])
+
+;; A function pointer under AIX is a pointer to a data area whose first word
+;; contains the actual address of the function, whose second word contains a
+;; pointer to its TOC, and whose third word contains a value to place in the
+;; static chain register (r11). Note that if we load the static chain, our
+;; "trampoline" need not have any executable code.
+;;
+;; operands[0] is a register pointing to the 3 word descriptor (aka, the function address)
+;; operands[1] is the stack size to clean up
+;; operands[2] is the value FUNCTION_ARG returns for the VOID argument (must be 0 for AIX)
+;; operands[3] is location to store the TOC
+;; operands[4] is the TOC register
+;; operands[5] is the static chain register
+;;
+;; We do not break this into separate insns, so that the scheduler will not try
+;; to move the load of the new TOC before any loads from the TOC.
+
+(define_insn "call_indirect_aix32"
+ [(call (mem:SI (match_operand:SI 0 "register_operand" "b"))
+ (match_operand 1 "const_int_operand" "n"))
+ (use (match_operand 2 "const_int_operand" "n"))
+ (use (match_operand 3 "offsettable_addr_operand" "p"))
+ (use (match_operand 4 "register_operand" "r"))
+ (clobber (match_operand 5 "register_operand" "=r"))
+ (clobber (match_scratch:SI 6 "=&r"))
+ (clobber (match_scratch:SI 7 "=l"))]
+ "DEFAULT_ABI == ABI_AIX
+ && (INTVAL (operands[2]) == CALL_NORMAL || (INTVAL (operands[2]) & CALL_LONG) != 0)"
+ "{st|stw} %4,%a3\;{l|lwz} %6,0(%0)\;{l|lwz} %4,4(%0)\;mt%7 %6\;{l|lwz} %5,8(%0)\;{brl|blrl}\;{l|lwz} %4,%a3"
+ [(set_attr "type" "load")
+ (set_attr "length" "28")])
+
+(define_insn "call_indirect_aix64"
+ [(call (mem:SI (match_operand:DI 0 "register_operand" "b"))
+ (match_operand 1 "const_int_operand" "n"))
+ (use (match_operand 2 "const_int_operand" "n"))
+ (use (match_operand 3 "offsettable_addr_operand" "p"))
+ (use (match_operand 4 "register_operand" "r"))
+ (clobber (match_operand 5 "register_operand" "=r"))
+ (clobber (match_scratch:SI 6 "=&r"))
+ (clobber (match_scratch:SI 7 "=l"))]
+ "TARGET_64BIT && DEFAULT_ABI == ABI_AIX
+ && (INTVAL (operands[2]) == CALL_NORMAL || (INTVAL (operands[2]) & CALL_LONG) != 0)"
+ "std %4,%a3\;ld %6,0(%0)\;ld %4,8(%0)\;mt%7 %6\;ld %5,16(%0)\;blrl\;ld %4,%a3"
+ [(set_attr "type" "load")
+ (set_attr "length" "28")])
+
+(define_insn "call_value_indirect_aix32"
+ [(set (match_operand 0 "register_operand" "fg")
+ (call (mem:SI (match_operand:SI 1 "register_operand" "b"))
+ (match_operand 2 "const_int_operand" "n")))
+ (use (match_operand 3 "const_int_operand" "n"))
+ (use (match_operand 4 "offsettable_addr_operand" "p"))
+ (use (match_operand 5 "register_operand" "r"))
+ (clobber (match_operand 6 "register_operand" "=r"))
+ (clobber (match_scratch:SI 7 "=&r"))
+ (clobber (match_scratch:SI 8 "=l"))]
+ "DEFAULT_ABI == ABI_AIX
+ && (INTVAL (operands[3]) == CALL_NORMAL || (INTVAL (operands[3]) & CALL_LONG) != 0)"
+ "{st|stw} %5,%a4\;{l|lwz} %7,0(%1)\;{l|lwz} %5,4(%1)\;mt%8 %7\;{l|lwz} %6,8(%1)\;{brl|blrl}\;{l|lwz} %5,%a4"
+ [(set_attr "type" "load")
+ (set_attr "length" "28")])
+
+(define_insn "call_value_indirect_aix64"
+ [(set (match_operand 0 "register_operand" "fg")
+ (call (mem:SI (match_operand:DI 1 "register_operand" "b"))
+ (match_operand 2 "const_int_operand" "n")))
+ (use (match_operand 3 "const_int_operand" "n"))
+ (use (match_operand 4 "offsettable_addr_operand" "p"))
+ (use (match_operand 5 "register_operand" "r"))
+ (clobber (match_operand 6 "register_operand" "=r"))
+ (clobber (match_scratch:SI 7 "=&r"))
+ (clobber (match_scratch:SI 8 "=l"))]
+ "TARGET_64BIT && DEFAULT_ABI == ABI_AIX
+ && (INTVAL (operands[3]) == CALL_NORMAL || (INTVAL (operands[3]) & CALL_LONG) != 0)"
+ "std %5,%a4\;ld %7,0(%1)\;ld %5,8(%1)\;mt%8 %7\;ld %6,16(%1)\;blrl\;ld %5,%a4"
+ [(set_attr "type" "load")
+ (set_attr "length" "28")])
+
+;; A function pointer undef NT is a pointer to a data area whose first word
+;; contains the actual address of the function, whose second word contains a
+;; pointer to its TOC. The static chain is not stored under NT, which means
+;; that we need a trampoline.
+;;
+;; operands[0] is an SImode pseudo in which we place the address of the function.
+;; operands[1] is the stack size to clean up
+;; operands[2] is the value FUNCTION_ARG returns for the VOID argument (must be 0 for NT)
+;; operands[3] is location to store the TOC
+;; operands[4] is the TOC register
+;;
+;; We do not break this into separate insns, so that the scheduler will not try
+;; to move the load of the new TOC before any loads from the TOC.
+
+(define_insn "call_indirect_nt"
+ [(call (mem:SI (match_operand:SI 0 "register_operand" "b"))
+ (match_operand 1 "const_int_operand" "n"))
+ (use (match_operand 2 "const_int_operand" "n"))
+ (use (match_operand 3 "offsettable_addr_operand" "p"))
+ (use (match_operand 4 "register_operand" "r"))
+ (clobber (match_scratch:SI 5 "=&r"))
+ (clobber (match_scratch:SI 6 "=l"))]
+ "DEFAULT_ABI == ABI_NT
+ && (INTVAL (operands[2]) == CALL_NORMAL || (INTVAL (operands[2]) & CALL_LONG) != 0)"
+ "{st|stw} %4,%a3\;{l|lwz} %5,0(%0)\;{l|lwz} %4,4(%0)\;mt%6 %5\;{brl|blrl}\;{l|lwz} %4,%a3"
+ [(set_attr "type" "load")
+ (set_attr "length" "24")])
+
+(define_insn "call_value_indirect_nt"
+ [(set (match_operand 0 "register_operand" "fg")
+ (call (mem:SI (match_operand:SI 1 "register_operand" "b"))
+ (match_operand 2 "const_int_operand" "n")))
+ (use (match_operand 3 "const_int_operand" "n"))
+ (use (match_operand 4 "offsettable_addr_operand" "p"))
+ (use (match_operand 5 "register_operand" "r"))
+ (clobber (match_scratch:SI 6 "=&r"))
+ (clobber (match_scratch:SI 7 "=l"))]
+ "DEFAULT_ABI == ABI_NT
+ && (INTVAL (operands[3]) == CALL_NORMAL || (INTVAL (operands[3]) & CALL_LONG) != 0)"
+ "{st|stw} %5,%a4\;{l|lwz} %6,0(%1)\;{l|lwz} %5,4(%1)\;mt%7 %6\;{brl|blrl}\;{l|lwz} %5,%a4"
+ [(set_attr "type" "load")
+ (set_attr "length" "24")])
+
+;; A function pointer under System V is just a normal pointer
+;; operands[0] is the function pointer
+;; operands[1] is the stack size to clean up
+;; operands[2] is the value FUNCTION_ARG returns for the VOID argument which indicates how to set cr1
+
+(define_insn "call_indirect_sysv"
+ [(call (mem:SI (match_operand:SI 0 "register_operand" "l,l"))
+ (match_operand 1 "const_int_operand" "n,n"))
+ (use (match_operand 2 "const_int_operand" "O,n"))
+ (clobber (match_scratch:SI 3 "=l,l"))]
+ "DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS || DEFAULT_ABI == ABI_AIX_NODESC"
+ "*
+{
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return \"{brl|blrl}\";
+}"
+ [(set_attr "type" "jmpreg")
+ (set_attr "length" "4,8")])
+
+(define_insn "call_value_indirect_sysv"
+ [(set (match_operand 0 "register_operand" "=fg,fg")
+ (call (mem:SI (match_operand:SI 1 "register_operand" "l,l"))
+ (match_operand 2 "const_int_operand" "n,n")))
+ (use (match_operand 3 "const_int_operand" "O,n"))
+ (clobber (match_scratch:SI 4 "=l,l"))]
+ "DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS || DEFAULT_ABI == ABI_AIX_NODESC"
+ "*
+{
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return \"{brl|blrl}\";
+}"
+ [(set_attr "type" "jmpreg")
+ (set_attr "length" "4,8")])
+
+;; Now the definitions for the call and call_value insns
+(define_expand "call"
+ [(parallel [(call (mem:SI (match_operand 0 "address_operand" ""))
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (clobber (scratch:SI))])]
+ ""
+ "
+{
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != CONST_INT)
+ abort ();
+
+ operands[0] = XEXP (operands[0], 0);
+
+ /* Convert NT DLL imports into an indirect call. */
+ if (GET_CODE (operands[0]) == SYMBOL_REF
+ && (INTVAL (operands[2]) & CALL_NT_DLLIMPORT) != 0)
+ {
+ operands[0] = rs6000_dll_import_ref (operands[0]);
+ operands[2] = GEN_INT ((int)CALL_NORMAL);
+ }
+
+ if (GET_CODE (operands[0]) != SYMBOL_REF
+ || (INTVAL (operands[2]) & CALL_LONG) != 0)
+ {
+ if (INTVAL (operands[2]) & CALL_LONG)
+ operands[0] = rs6000_longcall_ref (operands[0]);
+
+ if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_SOLARIS)
+ emit_call_insn (gen_call_indirect_sysv (force_reg (Pmode, operands[0]),
+ operands[1], operands[2]));
+ else
+ {
+ rtx toc_reg = gen_rtx_REG (Pmode, 2);
+ rtx toc_addr = RS6000_SAVE_TOC;
+
+ if (DEFAULT_ABI == ABI_AIX)
+ {
+ /* AIX function pointers are really pointers to a three word area */
+ rtx static_chain = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+ emit_call_insn (TARGET_32BIT
+ ? gen_call_indirect_aix32 (force_reg (Pmode, operands[0]),
+ operands[1], operands[2],
+ toc_addr, toc_reg, static_chain)
+ : gen_call_indirect_aix64 (force_reg (Pmode, operands[0]),
+ operands[1], operands[2],
+ toc_addr, toc_reg, static_chain));
+ }
+ else if (DEFAULT_ABI == ABI_NT)
+ {
+ /* NT function pointers are really pointers to a two word area */
+ emit_call_insn (gen_call_indirect_nt (force_reg (Pmode, operands[0]),
+ operands[1], operands[2],
+ toc_addr, toc_reg));
+ }
+ else
+ abort ();
+ }
+ DONE;
+ }
+}")
+
+(define_expand "call_value"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand 1 "address_operand" ""))
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (clobber (scratch:SI))])]
+ ""
+ "
+{
+ if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != CONST_INT)
+ abort ();
+
+ operands[1] = XEXP (operands[1], 0);
+
+ /* Convert NT DLL imports into an indirect call. */
+ if (GET_CODE (operands[1]) == SYMBOL_REF
+ && (INTVAL (operands[3]) & CALL_NT_DLLIMPORT) != 0)
+ {
+ operands[1] = rs6000_dll_import_ref (operands[1]);
+ operands[3] = GEN_INT ((int)CALL_NORMAL);
+ }
+
+ if (GET_CODE (operands[1]) != SYMBOL_REF
+ || (INTVAL (operands[3]) & CALL_LONG) != 0)
+ {
+ if (INTVAL (operands[2]) & CALL_LONG)
+ operands[1] = rs6000_longcall_ref (operands[1]);
+
+ if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_SOLARIS)
+ emit_call_insn (gen_call_value_indirect_sysv (operands[0], operands[1],
+ operands[2], operands[3]));
+ else
+ {
+ rtx toc_reg = gen_rtx_REG (Pmode, 2);
+ rtx toc_addr = RS6000_SAVE_TOC;
+
+ if (DEFAULT_ABI == ABI_AIX)
+ {
+ /* AIX function pointers are really pointers to a three word area */
+ rtx static_chain = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+ emit_call_insn (TARGET_32BIT
+ ? gen_call_value_indirect_aix32 (operands[0],
+ force_reg (Pmode, operands[1]),
+ operands[2], operands[3],
+ toc_addr, toc_reg, static_chain)
+ : gen_call_value_indirect_aix64 (operands[0],
+ force_reg (Pmode, operands[1]),
+ operands[2], operands[3],
+ toc_addr, toc_reg, static_chain));
+ }
+ else if (DEFAULT_ABI == ABI_NT)
+ {
+ /* NT function pointers are really pointers to a two word area */
+ emit_call_insn (gen_call_value_indirect_nt (operands[0],
+ force_reg (Pmode, operands[1]),
+ operands[2], operands[3],
+ toc_addr, toc_reg));
+ }
+ else
+ abort ();
+ }
+ DONE;
+ }
+}")
+
+;; Call to function in current module. No TOC pointer reload needed.
+;; Operand2 is non-zero if we are using the V.4 calling sequence and
+;; either the function was not prototyped, or it was prototyped as a
+;; variable argument function. It is > 0 if FP registers were passed
+;; and < 0 if they were not.
+
+(define_insn "*call_local32"
+ [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s"))
+ (match_operand 1 "" "g,g"))
+ (use (match_operand:SI 2 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 3 "=l,l"))]
+ "(INTVAL (operands[2]) & CALL_LONG) == 0"
+ "*
+{
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z0@local\" : \"bl %z0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8")])
+
+(define_insn "*call_local64"
+ [(call (mem:SI (match_operand:DI 0 "current_file_function_operand" "s,s"))
+ (match_operand 1 "" "g,g"))
+ (use (match_operand:SI 2 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 3 "=l,l"))]
+ "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0"
+ "*
+{
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z0@local\" : \"bl %z0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8")])
+
+(define_insn "*ret_call_local32"
+ [(set (match_operand 0 "" "=fg,fg")
+ (call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
+ (match_operand 2 "" "g,g")))
+ (use (match_operand:SI 3 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 4 "=l,l"))]
+ "(INTVAL (operands[3]) & CALL_LONG) == 0"
+ "*
+{
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z1@local\" : \"bl %z1\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8")])
+
+
+(define_insn "*ret_call_local64"
+ [(set (match_operand 0 "" "=fg,fg")
+ (call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s"))
+ (match_operand 2 "" "g,g")))
+ (use (match_operand:SI 3 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 4 "=l,l"))]
+ "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0"
+ "*
+{
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z1@local\" : \"bl %z1\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8")])
+
+;; Call to function which may be in another module. Restore the TOC
+;; pointer (r2) after the call unless this is System V.
+;; Operand2 is non-zero if we are using the V.4 calling sequence and
+;; either the function was not prototyped, or it was prototyped as a
+;; variable argument function. It is > 0 if FP registers were passed
+;; and < 0 if they were not.
+
+(define_insn "*call_nonlocal_aix32"
+ [(call (mem:SI (match_operand:SI 0 "call_operand" "s,s"))
+ (match_operand 1 "" "fg,fg"))
+ (use (match_operand:SI 2 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 3 "=l,l"))]
+ "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ && (INTVAL (operands[2]) & CALL_LONG) == 0"
+ "*
+{
+ /* Indirect calls should go through call_indirect */
+ if (GET_CODE (operands[0]) == REG)
+ abort ();
+
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (TARGET_WINDOWS_NT) ? \"bl %z0\;.znop %z0\" : \"bl %z0\;%.\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "8,12")])
+
+(define_insn "*call_nonlocal_aix64"
+ [(call (mem:SI (match_operand:DI 0 "call_operand" "s,s"))
+ (match_operand 1 "" "fg,fg"))
+ (use (match_operand:SI 2 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 3 "=l,l"))]
+ "TARGET_64BIT && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ && (INTVAL (operands[2]) & CALL_LONG) == 0"
+ "*
+{
+ /* Indirect calls should go through call_indirect */
+ if (GET_CODE (operands[0]) == REG)
+ abort ();
+
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (TARGET_WINDOWS_NT) ? \"bl %z0\;.znop %z0\" : \"bl %z0\;%.\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "8,12")])
+
+(define_insn "*call_nonlocal_sysv"
+ [(call (mem:SI (match_operand:SI 0 "call_operand" "s,s"))
+ (match_operand 1 "" "fg,fg"))
+ (use (match_operand:SI 2 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 3 "=l,l"))]
+ "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && (INTVAL (operands[2]) & CALL_LONG) == 0"
+ "*
+{
+ /* Indirect calls should go through call_indirect */
+ if (GET_CODE (operands[0]) == REG)
+ abort ();
+
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z0@plt\" : \"bl %z0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8")])
+
+(define_insn "*ret_call_nonlocal_aix32"
+ [(set (match_operand 0 "" "=fg,fg")
+ (call (mem:SI (match_operand:SI 1 "call_operand" "s,s"))
+ (match_operand 2 "" "fg,fg")))
+ (use (match_operand:SI 3 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 4 "=l,l"))]
+ "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ && (INTVAL (operands[3]) & CALL_LONG) == 0"
+ "*
+{
+ /* This should be handled by call_value_indirect */
+ if (GET_CODE (operands[1]) == REG)
+ abort ();
+
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (TARGET_WINDOWS_NT) ? \"bl %z1\;.znop %z1\" : \"bl %z1\;%.\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "8,12")])
+
+(define_insn "*ret_call_nonlocal_aix64"
+ [(set (match_operand 0 "" "=fg,fg")
+ (call (mem:SI (match_operand:DI 1 "call_operand" "s,s"))
+ (match_operand 2 "" "fg,fg")))
+ (use (match_operand:SI 3 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 4 "=l,l"))]
+ "TARGET_64BIT && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ && (INTVAL (operands[3]) & CALL_LONG) == 0"
+ "*
+{
+ /* This should be handled by call_value_indirect */
+ if (GET_CODE (operands[1]) == REG)
+ abort ();
+
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (TARGET_WINDOWS_NT) ? \"bl %z1\;.znop %z1\" : \"bl %z1\;%.\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "8,12")])
+
+(define_insn "*ret_call_nonlocal_sysv"
+ [(set (match_operand 0 "" "=fg,fg")
+ (call (mem:SI (match_operand:SI 1 "call_operand" "s,s"))
+ (match_operand 2 "" "fg,fg")))
+ (use (match_operand:SI 3 "immediate_operand" "O,n"))
+ (clobber (match_scratch:SI 4 "=l,l"))]
+ "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
+ && (INTVAL (operands[3]) & CALL_LONG) == 0"
+ "*
+{
+ /* This should be handled by call_value_indirect */
+ if (GET_CODE (operands[1]) == REG)
+ abort ();
+
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
+
+ return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z1@plt\" : \"bl %z1\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4,8")])
+
+;; Call subroutine returning any type.
+(define_expand "untyped_call"
+ [(parallel [(call (match_operand 0 "" "")
+ (const_int 0))
+ (match_operand 1 "" "")
+ (match_operand 2 "" "")])]
+ ""
+ "
+{
+ int i;
+
+ emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx, const0_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));
+ }
+
+ /* The optimizer does not know that the call sets the function value
+ registers we stored in the result block. We avoid problems by
+ claiming that all hard registers are used and clobbered at this
+ point. */
+ emit_insn (gen_blockage ());
+
+ DONE;
+}")
+
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory. This blocks insns from being moved across this point.
+
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] 0)]
+ ""
+ "")
+
+;; V.4 specific code to initialize the PIC register
+
+(define_insn "init_v4_pic"
+ [(set (match_operand:SI 0 "register_operand" "=l")
+ (unspec [(const_int 0)] 7))]
+ "DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS"
+ "bl _GLOBAL_OFFSET_TABLE_@local-4"
+ [(set_attr "type" "branch")
+ (set_attr "length" "4")])
+
+
+;; Compare insns are next. Note that the RS/6000 has two types of compares,
+;; signed & unsigned, and one type of branch.
+;;
+;; Start with the DEFINE_EXPANDs to generate the rtl for compares, scc
+;; insns, and branches. We store the operands of compares until we see
+;; how it is used.
+(define_expand "cmpsi"
+ [(set (cc0)
+ (compare (match_operand:SI 0 "gpc_reg_operand" "")
+ (match_operand:SI 1 "reg_or_short_operand" "")))]
+ ""
+ "
+{
+ /* Take care of the possibility that operands[1] might be negative but
+ this might be a logical operation. That insn doesn't exist. */
+ if (GET_CODE (operands[1]) == CONST_INT
+ && INTVAL (operands[1]) < 0)
+ operands[1] = force_reg (SImode, operands[1]);
+
+ rs6000_compare_op0 = operands[0];
+ rs6000_compare_op1 = operands[1];
+ rs6000_compare_fp_p = 0;
+ DONE;
+}")
+
+(define_expand "cmpdi"
+ [(set (cc0)
+ (compare (match_operand:DI 0 "gpc_reg_operand" "")
+ (match_operand:DI 1 "reg_or_short_operand" "")))]
+ "TARGET_POWERPC64"
+ "
+{
+ /* Take care of the possibility that operands[1] might be negative but
+ this might be a logical operation. That insn doesn't exist. */
+ if (GET_CODE (operands[1]) == CONST_INT
+ && INTVAL (operands[1]) < 0)
+ operands[1] = force_reg (DImode, operands[1]);
+
+ rs6000_compare_op0 = operands[0];
+ rs6000_compare_op1 = operands[1];
+ rs6000_compare_fp_p = 0;
+ DONE;
+}")
+
+(define_expand "cmpsf"
+ [(set (cc0) (compare (match_operand:SF 0 "gpc_reg_operand" "")
+ (match_operand:SF 1 "gpc_reg_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ rs6000_compare_op0 = operands[0];
+ rs6000_compare_op1 = operands[1];
+ rs6000_compare_fp_p = 1;
+ DONE;
+}")
+
+(define_expand "cmpdf"
+ [(set (cc0) (compare (match_operand:DF 0 "gpc_reg_operand" "")
+ (match_operand:DF 1 "gpc_reg_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ rs6000_compare_op0 = operands[0];
+ rs6000_compare_op1 = operands[1];
+ rs6000_compare_fp_p = 1;
+ DONE;
+}")
+
+(define_expand "beq"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (eq (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+(define_expand "bne"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (ne (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+(define_expand "blt"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (lt (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+(define_expand "bgt"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (gt (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+(define_expand "ble"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (le (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+(define_expand "bge"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (ge (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+(define_expand "bgtu"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (gtu (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (CCUNSmode);
+}")
+
+(define_expand "bltu"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (ltu (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (CCUNSmode);
+}")
+
+(define_expand "bgeu"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (geu (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (CCUNSmode);
+}")
+
+(define_expand "bleu"
+ [(set (match_dup 2) (match_dup 1))
+ (set (pc)
+ (if_then_else (leu (match_dup 2)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (CCUNSmode);
+}")
+
+;; For SNE, we would prefer that the xor/abs sequence be used for integers.
+;; For SEQ, likewise, except that comparisons with zero should be done
+;; with an scc insns. However, due to the order that combine see the
+;; resulting insns, we must, in fact, allow SEQ for integers. Fail in
+;; the cases we don't want to handle.
+(define_expand "seq"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (eq:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+(define_expand "sne"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ne:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ if (! rs6000_compare_fp_p)
+ FAIL;
+
+ operands[1] = gen_rtx_COMPARE (CCFPmode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (CCFPmode);
+}")
+
+;; A > 0 is best done using the portable sequence, so fail in that case.
+(define_expand "sgt"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (gt:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+
+ if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
+ FAIL;
+
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+;; A < 0 is best done in the portable way for A an integer.
+(define_expand "slt"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (lt:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+
+ if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
+ FAIL;
+
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+(define_expand "sge"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ge:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+;; A <= 0 is best done the portable way for A an integer.
+(define_expand "sle"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (le:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
+
+ if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
+ FAIL;
+
+ operands[1] = gen_rtx_COMPARE (mode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (mode);
+}")
+
+(define_expand "sgtu"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (gtu:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (CCUNSmode);
+}")
+
+(define_expand "sltu"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (ltu:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (CCUNSmode);
+}")
+
+(define_expand "sgeu"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (geu:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (CCUNSmode);
+}")
+
+(define_expand "sleu"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (leu:SI (match_dup 2) (const_int 0)))]
+ ""
+ "
+{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
+ rs6000_compare_op0, rs6000_compare_op1);
+ operands[2] = gen_reg_rtx (CCUNSmode);
+}")
+
+;; Here are the actual compare insns.
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=y")
+ (compare:CC (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI")))]
+ ""
+ "{cmp%I2|cmpw%I2} %0,%1,%2"
+ [(set_attr "type" "compare")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=y")
+ (compare:CC (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_short_operand" "rI")))]
+ "TARGET_POWERPC64"
+ "cmpd%I2 %0,%1,%2"
+ [(set_attr "type" "compare")])
+
+;; If we are comparing a register for equality with a large constant,
+;; we can do this with an XOR followed by a compare. But we need a scratch
+;; register for the result of the XOR.
+
+(define_split
+ [(set (match_operand:CC 0 "cc_reg_operand" "")
+ (compare:CC (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "non_short_cint_operand" "")))
+ (clobber (match_operand:SI 3 "gpc_reg_operand" ""))]
+ "find_single_use (operands[0], insn, 0)
+ && (GET_CODE (*find_single_use (operands[0], insn, 0)) == EQ
+ || GET_CODE (*find_single_use (operands[0], insn, 0)) == NE)"
+ [(set (match_dup 3) (xor:SI (match_dup 1) (match_dup 4)))
+ (set (match_dup 0) (compare:CC (match_dup 3) (match_dup 5)))]
+ "
+{
+ /* Get the constant we are comparing against, C, and see what it looks like
+ sign-extended to 16 bits. Then see what constant could be XOR'ed
+ with C to get the sign-extended value. */
+
+ int c = INTVAL (operands[2]);
+ int sextc = (c << 16) >> 16;
+ int xorv = c ^ sextc;
+
+ operands[4] = GEN_INT (xorv);
+ operands[5] = GEN_INT (sextc);
+}")
+
+(define_insn ""
+ [(set (match_operand:CCUNS 0 "cc_reg_operand" "=y")
+ (compare:CCUNS (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_u_short_operand" "rI")))]
+ ""
+ "{cmpl%I2|cmplw%I2} %0,%1,%W2"
+ [(set_attr "type" "compare")])
+
+(define_insn ""
+ [(set (match_operand:CCUNS 0 "cc_reg_operand" "=y")
+ (compare:CCUNS (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "reg_or_u_short_operand" "rI")))]
+ ""
+ "cmpld%I2 %0,%1,%W2"
+ [(set_attr "type" "compare")])
+
+;; The following two insns don't exist as single insns, but if we provide
+;; them, we can swap an add and compare, which will enable us to overlap more
+;; of the required delay between a compare and branch. We generate code for
+;; them by splitting.
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=y")
+ (compare:CC (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "short_cint_operand" "i")))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (plus:SI (match_dup 1) (match_operand:SI 4 "short_cint_operand" "i")))]
+ ""
+ "#"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:CCUNS 3 "cc_reg_operand" "=y")
+ (compare:CCUNS (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "u_short_cint_operand" "i")))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (plus:SI (match_dup 1) (match_operand:SI 4 "short_cint_operand" "i")))]
+ ""
+ "#"
+ [(set_attr "length" "8")])
+
+(define_split
+ [(set (match_operand:CC 3 "cc_reg_operand" "")
+ (compare:CC (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "short_cint_operand" "")))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (plus:SI (match_dup 1) (match_operand:SI 4 "short_cint_operand" "")))]
+ ""
+ [(set (match_dup 3) (compare:CC (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 4)))])
+
+(define_split
+ [(set (match_operand:CCUNS 3 "cc_reg_operand" "")
+ (compare:CCUNS (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "u_short_cint_operand" "")))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (plus:SI (match_dup 1) (match_operand:SI 4 "short_cint_operand" "")))]
+ ""
+ [(set (match_dup 3) (compare:CCUNS (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 4)))])
+
+(define_insn ""
+ [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
+ (compare:CCFP (match_operand:SF 1 "gpc_reg_operand" "f")
+ (match_operand:SF 2 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "fcmpu %0,%1,%2"
+ [(set_attr "type" "fpcompare")])
+
+(define_insn ""
+ [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
+ (compare:CCFP (match_operand:DF 1 "gpc_reg_operand" "f")
+ (match_operand:DF 2 "gpc_reg_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "fcmpu %0,%1,%2"
+ [(set_attr "type" "fpcompare")])
+
+;; Now we have the scc insns. We can do some combinations because of the
+;; way the machine works.
+;;
+;; Note that this is probably faster if we can put an insn between the
+;; mfcr and rlinm, but this is tricky. Let's leave it for now. In most
+;; cases the insns below which don't use an intermediate CR field will
+;; be used instead.
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (match_operator:SI 1 "scc_comparison_operator"
+ [(match_operand 2 "cc_reg_operand" "y")
+ (const_int 0)]))]
+ ""
+ "%D1mfcr %0\;{rlinm|rlwinm} %0,%0,%J1,1"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x")
+ (compare:CC (match_operator:SI 1 "scc_comparison_operator"
+ [(match_operand 2 "cc_reg_operand" "y")
+ (const_int 0)])
+ (const_int 0)))
+ (set (match_operand:SI 3 "gpc_reg_operand" "=r")
+ (match_op_dup 1 [(match_dup 2) (const_int 0)]))]
+ ""
+ "%D1mfcr %3\;{rlinm.|rlwinm.} %3,%3,%J1,1"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ashift:SI (match_operator:SI 1 "scc_comparison_operator"
+ [(match_operand 2 "cc_reg_operand" "y")
+ (const_int 0)])
+ (match_operand:SI 3 "const_int_operand" "n")))]
+ ""
+ "*
+{
+ int is_bit = ccr_bit (operands[1], 1);
+ int put_bit = 31 - (INTVAL (operands[3]) & 31);
+ int count;
+
+ if (is_bit >= put_bit)
+ count = is_bit - put_bit;
+ else
+ count = 32 - (put_bit - is_bit);
+
+ operands[4] = GEN_INT (count);
+ operands[5] = GEN_INT (put_bit);
+
+ return \"%D1mfcr %0\;{rlinm|rlwinm} %0,%0,%4,%5,%5\";
+}"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x")
+ (compare:CC
+ (ashift:SI (match_operator:SI 1 "scc_comparison_operator"
+ [(match_operand 2 "cc_reg_operand" "y")
+ (const_int 0)])
+ (match_operand:SI 3 "const_int_operand" "n"))
+ (const_int 0)))
+ (set (match_operand:SI 4 "gpc_reg_operand" "=r")
+ (ashift:SI (match_op_dup 1 [(match_dup 2) (const_int 0)])
+ (match_dup 3)))]
+ ""
+ "*
+{
+ int is_bit = ccr_bit (operands[1], 1);
+ int put_bit = 31 - (INTVAL (operands[3]) & 31);
+ int count;
+
+ if (is_bit >= put_bit)
+ count = is_bit - put_bit;
+ else
+ count = 32 - (put_bit - is_bit);
+
+ operands[5] = GEN_INT (count);
+ operands[6] = GEN_INT (put_bit);
+
+ return \"%D1mfcr %4\;{rlinm.|rlwinm.} %4,%4,%5,%6,%6\";
+}"
+ [(set_attr "type" "delayed_compare")
+ (set_attr "length" "12")])
+
+;; If we are comparing the result of two comparisons, this can be done
+;; using creqv or crxor.
+
+(define_insn ""
+ [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
+ (compare:CCEQ (match_operator 1 "scc_comparison_operator"
+ [(match_operand 2 "cc_reg_operand" "y")
+ (const_int 0)])
+ (match_operator 3 "scc_comparison_operator"
+ [(match_operand 4 "cc_reg_operand" "y")
+ (const_int 0)])))]
+ "REGNO (operands[2]) != REGNO (operands[4])"
+ "*
+{
+ enum rtx_code code1, code2;
+
+ code1 = GET_CODE (operands[1]);
+ code2 = GET_CODE (operands[3]);
+
+ if ((code1 == EQ || code1 == LT || code1 == GT
+ || code1 == LTU || code1 == GTU
+ || (code1 != NE && GET_MODE (operands[2]) == CCFPmode))
+ !=
+ (code2 == EQ || code2 == LT || code2 == GT
+ || code2 == LTU || code2 == GTU
+ || (code2 != NE && GET_MODE (operands[4]) == CCFPmode)))
+ return \"%C1%C3crxor %E0,%j1,%j3\";
+ else
+ return \"%C1%C3creqv %E0,%j1,%j3\";
+}"
+ [(set_attr "length" "12")])
+
+;; There is a 3 cycle delay between consecutive mfcr instructions
+;; so it is useful to combine 2 scc instructions to use only one mfcr.
+
+(define_peephole
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (match_operator:SI 1 "scc_comparison_operator"
+ [(match_operand 2 "cc_reg_operand" "y")
+ (const_int 0)]))
+ (set (match_operand:SI 3 "gpc_reg_operand" "=r")
+ (match_operator:SI 4 "scc_comparison_operator"
+ [(match_operand 5 "cc_reg_operand" "y")
+ (const_int 0)]))]
+ "REGNO (operands[2]) != REGNO (operands[5])"
+ "%D1%D4mfcr %3\;{rlinm|rlwinm} %0,%3,%J1,1\;{rlinm|rlwinm} %3,%3,%J4,1"
+ [(set_attr "length" "20")])
+
+;; There are some scc insns that can be done directly, without a compare.
+;; These are faster because they don't involve the communications between
+;; the FXU and branch units. In fact, we will be replacing all of the
+;; integer scc insns here or in the portable methods in emit_store_flag.
+;;
+;; Also support (neg (scc ..)) since that construct is used to replace
+;; branches, (plus (scc ..) ..) since that construct is common and
+;; takes no more insns than scc, and (and (neg (scc ..)) ..) in the
+;; cases where it is no more expensive than (neg (scc ..)).
+
+;; Have reload force a constant into a register for the simple insns that
+;; otherwise won't accept constants. We do this because it is faster than
+;; the cmp/mfcr sequence we would otherwise generate.
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r")
+ (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,J,I")))
+ (clobber (match_scratch:SI 3 "=r,&r,r,r,r"))]
+ ""
+ "@
+ xor %0,%1,%2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0
+ {sfi|subfic} %3,%1,0\;{ae|adde} %0,%3,%1
+ {xoril|xori} %0,%1,%b2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0
+ {xoriu|xoris} %0,%1,%u2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0
+ {sfi|subfic} %0,%1,%2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0"
+ [(set_attr "length" "12,8,12,12,12")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r")
+ (eq:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "r,O,K,J,I")))
+ (clobber (match_scratch:DI 3 "=r,&r,r,r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ xor %0,%1,%2\;subfic %3,%0,0\;adde %0,%3,%0
+ subfic %3,%1,0\;adde %0,%3,%1
+ xori %0,%1,%b2\;subfic %3,%0,0\;adde %0,%3,%0
+ xoris %0,%1,%u2\;subfic %3,%0,0\;adde %0,%3,%0
+ subfic %0,%1,%2\;subfic %3,%0,0\;adde %0,%3,%0"
+ [(set_attr "length" "12,8,12,12,12")])
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,x,x,x,?y,?y,?y,?y,?y")
+ (compare:CC
+ (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,J,I,r,O,K,J,I"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r,r,r,r,r,r")
+ (eq:SI (match_dup 1) (match_dup 2)))
+ (clobber (match_scratch:SI 3 "=r,&r,r,r,r,r,&r,r,r,r"))]
+ ""
+ "@
+ xor %0,%1,%2\;{sfi|subfic} %3,%0,0\;{ae.|adde.} %0,%3,%0
+ {sfi|subfic} %3,%1,0\;{ae.|adde.} %0,%3,%1
+ {xoril|xori} %0,%1,%b2\;{sfi|subfic} %3,%0,0\;{ae.|adde.} %0,%3,%0
+ {xoriu|xoris} %0,%1,%u2\;{sfi|subfic} %3,%0,0\;{ae.|adde.} %0,%3,%0
+ {sfi|subfic} %0,%1,%2\;{sfi|subfic} %3,%0,0\;{ae.|adde.} %0,%3,%0
+ xor %0,%1,%2\;{sfi|subfic} %3,%0,0\;{ae.|adde.} %0,%3,%0
+ {sfi|subfic} %3,%1,0\;{ae|adde} %0,%3,%1\;cmpli %4,%0,0
+ {xoril|xori} %0,%1,%b2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0\;cmpli %4,%0,0
+ {xoriu|xoris} %0,%1,%u2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0\;cmpli %4,%0,0
+ {sfi|subfic} %0,%1,%2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0\;cmpli %4,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,8,12,12,12,16,12,16,16,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,x,x,x,?y,?y,?y,?y,?y")
+ (compare:CC
+ (eq:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r")
+ (match_operand:DI 2 "reg_or_cint_operand" "r,O,K,J,I,r,O,K,J,I"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r,r,r,r,r,r")
+ (eq:DI (match_dup 1) (match_dup 2)))
+ (clobber (match_scratch:DI 3 "=r,&r,r,r,r,r,&r,r,r,r"))]
+ "TARGET_POWERPC64"
+ "@
+ xor %0,%1,%2\;subfic %3,%0,0\;adde. %0,%3,%0
+ subfic %3,%1,0\;adde. %0,%3,%1
+ xori %0,%1,%b2\;subfic %3,%0,0\;adde. %0,%3,%0
+ xoris %0,%1,%u2\;subfic %3,%0,0\;adde. %0,%3,%0
+ subfic %0,%1,%2\;subfic %3,%0,0\;adde. %0,%3,%0
+ xor %0,%1,%2\;subfic %3,%0,0\;adde. %0,%3,%0
+ subfic %3,%1,0\;adde %0,%3,%1\;cmpli %4,%0,0
+ xori %0,%1,%b2\;subfic %3,%0,0\;adde %0,%3,%0\;cmpli %4,%0,0
+ xoris %0,%1,%u2\;subfic %3,%0,0\;adde %0,%3,%0\;cmpli %4,%0,0
+ subfic %0,%1,%2\;subfic %3,%0,0\;adde %0,%3,%0\;cmpli %4,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,8,12,12,12,16,12,16,16,16")])
+
+;; We have insns of the form shown by the first define_insn below. If
+;; there is something inside the comparison operation, we must split it.
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (plus:SI (match_operator 1 "comparison_operator"
+ [(match_operand:SI 2 "" "")
+ (match_operand:SI 3
+ "reg_or_cint_operand" "")])
+ (match_operand:SI 4 "gpc_reg_operand" "")))
+ (clobber (match_operand:SI 5 "register_operand" ""))]
+ "! gpc_reg_operand (operands[2], SImode)"
+ [(set (match_dup 5) (match_dup 2))
+ (set (match_dup 2) (plus:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)])
+ (match_dup 4)))])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r")
+ (plus:SI (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,J,I"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r,r")))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r,&r"))]
+ ""
+ "@
+ xor %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze|addze} %0,%3
+ {sfi|subfic} %4,%1,0\;{aze|addze} %0,%3
+ {xoril|xori} %4,%1,%b2\;{sfi|subfic} %4,%4,0\;{aze|addze} %0,%3
+ {xoriu|xoris} %4,%1,%u2\;{sfi|subfic} %4,%4,0\;{aze|addze} %0,%3
+ {sfi|subfic} %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze|addze} %0,%3"
+ [(set_attr "length" "12,8,12,12,12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,x,?y,?y,?y,?y,?y")
+ (compare:CC
+ (plus:SI
+ (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,J,I,r,O,K,J,I"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r,r,r,r,r,r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r,&r,&r,&r,&r,&r,&r"))]
+ ""
+ "@
+ xor %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3
+ {sfi|subfic} %4,%1,0\;{aze.|addze.} %4,%3
+ {xoril|xori} %4,%1,%b2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3
+ {xoriu|xoris} %4,%1,%u2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3
+ {sfi|subfic} %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3
+ xor %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3\;cmpli %0,%4,0
+ {sfi|subfic} %4,%1,0\;{aze|addze} %0,%3\;cmpli %0,%4,0
+ {xoril|xori} %4,%1,%b2\;{sfi|subfic} %4,%4,0\;{aze|addze} %4,%3\;cmpli %0,%4,0
+ {xoriu|xoris} %4,%1,%u2\;{sfi|subfic} %4,%4,0\;{aze|addze} %4,%3\;cmpli %0,%4,0
+ {sfi|subfic} %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze|addze} %4,%3\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,8,12,12,12,16,12,16,16,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,x,x,x,x,?y,?y,?y,?y,?y")
+ (compare:CC
+ (plus:SI
+ (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,J,I,r,O,K,J,I"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r,r,r,r,r,r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r,r,r,r,r,r")
+ (plus:SI (eq:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r,&r,&r,&r,&r,&r,&r"))]
+ ""
+ "@
+ xor %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3
+ {sfi|subfic} %4,%1,0\;{aze.|addze.} %4,%3
+ {xoril|xori} %4,%1,%b2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3
+ {xoriu|xoris} %4,%1,%u2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3
+ {sfi|subfic} %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3
+ xor %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3\;cmpli %5,%0,0
+ {sfi|subfic} %4,%1,0\;{aze.|addze.} %4,%3\;cmpli %5,%0,0
+ {xoril|xori} %4,%1,%b2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3\;cmpli %5,%0,0
+ {xoriu|xoris} %4,%1,%u2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3\;cmpli %5,%0,0
+ {sfi|subfic} %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,8,12,12,12,16,12,16,16,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r")
+ (neg:SI (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r")
+ (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,J,I"))))]
+ ""
+ "@
+ xor %0,%1,%2\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0
+ {ai|addic} %0,%1,-1\;{sfe|subfe} %0,%0,%0
+ {xoril|xori} %0,%1,%b2\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0
+ {xoriu|xoris} %0,%1,%u2\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0
+ {sfi|subfic} %0,%1,%2\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0"
+ [(set_attr "length" "12,8,12,12,12")])
+
+;; Simplify (ne X (const_int 0)) on the PowerPC. No need to on the Power,
+;; since it nabs/sr is just as fast.
+(define_insn "*ne0"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
+ (lshiftrt:SI (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))
+ (const_int 31)))
+ (clobber (match_scratch:SI 2 "=&r"))]
+ "!TARGET_POWER"
+ "{ai|addic} %2,%1,-1\;{sfe|subfe} %0,%2,%1"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (lshiftrt:DI (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r")))
+ (const_int 63)))
+ (clobber (match_scratch:DI 2 "=&r"))]
+ "TARGET_POWERPC64"
+ "addic %2,%1,-1\;subfe %0,%2,%1"
+ [(set_attr "length" "8")])
+
+;; This is what (plus (ne X (const_int 0)) Y) looks like.
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (plus:SI (lshiftrt:SI
+ (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))
+ (const_int 31))
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ ""
+ "{ai|addic} %3,%1,-1\;{aze|addze} %0,%2"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (plus:DI (lshiftrt:DI
+ (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r")))
+ (const_int 63))
+ (match_operand:DI 2 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:DI 3 "=&r"))]
+ "TARGET_POWERPC64"
+ "addic %3,%1,-1\;addze %0,%2"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (lshiftrt:SI
+ (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")))
+ (const_int 31))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=&r,&r"))]
+ ""
+ "@
+ {ai|addic} %3,%1,-1\;{aze.|addze.} %3,%2
+ {ai|addic} %3,%1,-1\;{aze|addze} %3,%2\;cmpli %0,%3,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:DI (lshiftrt:DI
+ (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")))
+ (const_int 63))
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 3 "=&r,&r"))]
+ "TARGET_POWERPC64"
+ "@
+ addic %3,%1,-1\;addze. %3,%2
+ addic %3,%1,-1\;addze. %3,%2\;cmpdi %0,%3,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (lshiftrt:SI
+ (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")))
+ (const_int 31))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (plus:SI (lshiftrt:SI (neg:SI (abs:SI (match_dup 1))) (const_int 31))
+ (match_dup 2)))
+ (clobber (match_scratch:SI 3 "=&r,&r"))]
+ ""
+ "@
+ {ai|addic} %3,%1,-1\;{aze.|addze.} %0,%2
+ {ai|addic} %3,%1,-1\;{aze|addze} %0,%2\;cmpli %4,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:DI (lshiftrt:DI
+ (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")))
+ (const_int 63))
+ (match_operand:DI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+ (plus:DI (lshiftrt:DI (neg:DI (abs:DI (match_dup 1))) (const_int 63))
+ (match_dup 2)))
+ (clobber (match_scratch:DI 3 "=&r,&r"))]
+ "TARGET_POWERPC64"
+ "@
+ addic %3,%1,-1\;addze. %0,%2
+ addic %3,%1,-1\;addze. %0,%2\;cmpdi %4,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,O")))
+ (clobber (match_scratch:SI 3 "=r,X"))]
+ "TARGET_POWER"
+ "@
+ doz %3,%2,%1\;{sfi|subfic} %0,%3,0\;{ae|adde} %0,%0,%3
+ {ai|addic} %0,%1,-1\;{aze|addze} %0,%0\;{sri|srwi} %0,%0,31"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,O,r,O"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (le:SI (match_dup 1) (match_dup 2)))
+ (clobber (match_scratch:SI 3 "=r,X,r,X"))]
+ "TARGET_POWER"
+ "@
+ doz %3,%2,%1\;{sfi|subfic} %0,%3,0\;{ae.|adde.} %0,%0,%3
+ {ai|addic} %0,%1,-1\;{aze|addze} %0,%0\;{sri.|srwi.} %0,%0,31
+ doz %3,%2,%1\;{sfi|subfic} %0,%3,0\;{ae|adde} %0,%0,%3\;cmpli %4,%0,0
+ {ai|addic} %0,%1,-1\;{aze|addze} %0,%0\;{sri.|srwi.} %0,%0,31\;cmpli %4,%0,0"
+ [(set_attr "type" "compare,delayed_compare,compare,compare")
+ (set_attr "length" "12,12,16,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (plus:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,O"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r")))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ "TARGET_POWER"
+ "@
+ doz %4,%2,%1\;{sfi|subfic} %4,%4,0\;{aze|addze} %0,%3
+ {srai|srawi} %4,%1,31\;{sf|subfc} %4,%1,%4\;{aze|addze} %0,%3"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (plus:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,O,r,O"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ "TARGET_POWER"
+ "@
+ doz %4,%2,%1\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3
+ {srai|srawi} %4,%1,31\;{sf|subfc} %4,%1,%4\;{aze.|addze.} %4,%3
+ doz %4,%2,%1\;{sfi|subfic} %4,%4,0\;{aze|addze} %4,%3\;cmpli %0,%4,0
+ {srai|srawi} %4,%1,31\;{sf|subfc} %4,%1,%4\;{aze.|addze.} %4,%3\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,12,16,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (plus:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,O,r,O"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (plus:SI (le:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ "TARGET_POWER"
+ "@
+ doz %4,%2,%1\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3
+ {srai|srawi} %4,%1,31\;{sf|subfc} %4,%1,%4\;{aze.|addze.} %0,%3
+ doz %4,%2,%1\;{sfi|subfic} %4,%4,0\;{aze|addze} %0,%3\;cmpli %5,%0,0
+ {srai|srawi} %4,%1,31\;{sf|subfc} %4,%1,%4\;{aze.|addze.} %0,%3\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,12,16,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (neg:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,O"))))]
+ "TARGET_POWER"
+ "@
+ doz %0,%2,%1\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0
+ {ai|addic} %0,%1,-1\;{aze|addze} %0,%0\;{srai|srawi} %0,%0,31"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI")))]
+ ""
+ "{sf%I2|subf%I2c} %0,%1,%2\;{cal %0,0(0)|li %0,0}\;{ae|adde} %0,%0,%0"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (leu:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ {sf%I2|subf%I2c} %0,%1,%2\;{cal %0,0(0)|li %0,0}\;{ae.|adde.} %0,%0,%0
+ {sf%I2|subf%I2c} %0,%1,%2\;{cal %0,0(0)|li %0,0}\;{ae|adde} %0,%0,%0\;cmpli %3,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (plus:SI (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI"))
+ (match_operand:SI 3 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 4 "=&r"))]
+ ""
+ "{sf%I2|subf%I2c} %4,%1,%2\;{aze|addze} %0,%3"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ ""
+ "@
+ {sf%I2|subf%I2c} %4,%1,%2\;{aze.|addze.} %4,%3
+ {sf%I2|subf%I2c} %4,%1,%2\;{aze|addze} %4,%3\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (plus:SI (leu:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ ""
+ "@
+ {sf%I2|subf%I2c} %4,%1,%2\;{aze.|addze.} %0,%3
+ {sf%I2|subf%I2c} %4,%1,%2\;{aze|addze} %0,%3\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (neg:SI (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI"))))]
+ ""
+ "{sf%I2|subf%I2c} %0,%1,%2\;{sfe|subfe} %0,%0,%0\;nand %0,%0,%0"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (and:SI (neg:SI
+ (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI")))
+ (match_operand:SI 3 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 4 "=&r"))]
+ ""
+ "{sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;andc %0,%3,%4"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (and:SI (neg:SI
+ (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI")))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ ""
+ "@
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;andc. %4,%3,%4
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;andc %4,%3,%4\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (and:SI (neg:SI
+ (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI")))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (and:SI (neg:SI (leu:SI (match_dup 1) (match_dup 2))) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ ""
+ "@
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;andc. %0,%3,%4
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;andc %0,%3,%4\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI")))]
+ "TARGET_POWER"
+ "doz%I2 %0,%1,%2\;nabs %0,%0\;{sri|srwi} %0,%0,31"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (lt:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWER"
+ "@
+ doz%I2 %0,%1,%2\;nabs %0,%0\;{sri.|srwi.} %0,%0,31
+ doz%I2 %0,%1,%2\;nabs %0,%0\;{sri|srwi} %0,%0,31\;cmpli %3,%0,0"
+ [(set_attr "type" "delayed_compare,compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (plus:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI"))
+ (match_operand:SI 3 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 4 "=&r"))]
+ "TARGET_POWER"
+ "doz%I2 %4,%1,%2\;{ai|addic} %4,%4,-1\;{aze|addze} %0,%3"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ "TARGET_POWER"
+ "@
+ doz%I2 %4,%1,%2\;{ai|addic} %4,%4,-1\;{aze.|addze.} %4,%3
+ doz%I2 %4,%1,%2\;{ai|addic} %4,%4,-1\;{aze|addze} %4,%3\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (plus:SI (lt:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ "TARGET_POWER"
+ "@
+ doz%I2 %4,%1,%2\;{ai|addic} %4,%4,-1\;{aze.|addze.} %0,%3
+ doz%I2 %4,%1,%2\;{ai|addic} %4,%4,-1\;{aze|addze} %0,%3\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (neg:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI"))))]
+ "TARGET_POWER"
+ "doz%I2 %0,%1,%2\;nabs %0,%0\;{srai|srawi} %0,%0,31"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ltu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P")))]
+ ""
+ "@
+ {sf|subfc} %0,%2,%1\;{sfe|subfe} %0,%0,%0\;neg %0,%0
+ {ai|addic} %0,%1,%n2\;{sfe|subfe} %0,%0,%0\;neg %0,%0"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (ltu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (ltu:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ {sf|subfc} %0,%2,%1\;{sfe|subfe} %0,%0,%0\;neg. %0,%0
+ {ai|addic} %0,%1,%n2\;{sfe|subfe} %0,%0,%0\;neg. %0,%0
+ {sf|subfc} %0,%2,%1\;{sfe|subfe} %0,%0,%0\;neg %0,%0\;cmpli %3,%0,0
+ {ai|addic} %0,%1,%n2\;{sfe|subfe} %0,%0,%0\;neg %0,%0\;cmpli %3,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,12,16,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (plus:SI (ltu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,r,P,P"))
+ (match_operand:SI 3 "reg_or_short_operand" "r,I,r,I")))
+ (clobber (match_scratch:SI 4 "=&r,r,&r,r"))]
+ ""
+ "@
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;{sf%I3|subf%I3c} %0,%4,%3
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;{sf%I3|subf%I3c} %0,%4,%3
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;{sf%I3|subf%I3c} %0,%4,%3
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;{sf%I3|subf%I3c} %0,%4,%3"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (plus:SI (ltu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ ""
+ "@
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;{sf.|subfc.} %4,%4,%3
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;{sf.|subfc.} %4,%4,%3
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;{sf|subfc} %4,%4,%3\;cmpli %0,%4,0
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;{sf|subfc} %4,%4,%3\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,12,16,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (plus:SI (ltu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (plus:SI (ltu:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ ""
+ "@
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;{sf.|subfc.} %0,%4,%3
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;{sf.|subfc.} %0,%4,%3
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;{sf|subfc} %0,%4,%3\;cmpli %5,%0,0
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;{sf|subfc} %0,%4,%3\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,12,16,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (neg:SI (ltu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P"))))]
+ ""
+ "@
+ {sf|subfc} %0,%2,%1\;{sfe|subfe} %0,%0,%0
+ {ai|addic} %0,%1,%n2\;{sfe|subfe} %0,%0,%0"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI")))
+ (clobber (match_scratch:SI 3 "=r"))]
+ "TARGET_POWER"
+ "doz%I2 %3,%1,%2\;{sfi|subfic} %0,%3,0\;{ae|adde} %0,%0,%3"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (ge:SI (match_dup 1) (match_dup 2)))
+ (clobber (match_scratch:SI 3 "=r,r"))]
+ "TARGET_POWER"
+ "@
+ doz%I2 %3,%1,%2\;{sfi|subfic} %0,%3,0\;{ae.|adde.} %0,%0,%3
+ doz%I2 %3,%1,%2\;{sfi|subfic} %0,%3,0\;{ae|adde} %0,%0,%3\;cmpli %4,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (plus:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI"))
+ (match_operand:SI 3 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 4 "=&r"))]
+ "TARGET_POWER"
+ "doz%I2 %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze|addze} %0,%3"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ "TARGET_POWER"
+ "@
+ doz%I2 %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3
+ doz%I2 %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze|addze} %4,%3\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (plus:SI (ge:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ "TARGET_POWER"
+ "@
+ doz%I2 %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %0,%3
+ doz%I2 %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze|addze} %0,%3\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (neg:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI"))))]
+ "TARGET_POWER"
+ "doz%I2 %0,%1,%2\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0"
+ [(set_attr "length" "12")])
+
+;; This is (and (neg (ge X (const_int 0))) Y).
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (and:SI (neg:SI
+ (lshiftrt:SI
+ (not:SI (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (const_int 31)))
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ ""
+ "{srai|srawi} %3,%1,31\;andc %0,%2,%3"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (and:SI (neg:SI
+ (lshiftrt:SI
+ (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 31)))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=&r,&r"))]
+ ""
+ "@
+ {srai|srawi} %3,%1,31\;andc. %3,%2,%3
+ {srai|srawi} %3,%1,31\;andc %3,%2,%3\;cmpli %0,%3,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (and:SI (neg:SI
+ (lshiftrt:SI
+ (not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (const_int 31)))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (and:SI (neg:SI (lshiftrt:SI (not:SI (match_dup 1))
+ (const_int 31)))
+ (match_dup 2)))
+ (clobber (match_scratch:SI 3 "=&r,&r"))]
+ ""
+ "@
+ {srai|srawi} %3,%1,31\;andc. %0,%2,%3
+ {srai|srawi} %3,%1,31\;andc %0,%2,%3\;cmpli %4,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P")))]
+ ""
+ "@
+ {sf|subfc} %0,%2,%1\;{cal %0,0(0)|li %0,0}\;{ae|adde} %0,%0,%0
+ {ai|addic} %0,%1,%n2\;{cal %0,0(0)|li %0,0}\;{ae|adde} %0,%0,%0"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (geu:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ {sf|subfc} %0,%2,%1\;{cal %0,0(0)|li %0,0}\;{ae.|adde.} %0,%0,%0
+ {ai|addic} %0,%1,%n2\;{cal %0,0(0)|li %0,0}\;{ae.|adde.} %0,%0,%0
+ {sf|subfc} %0,%2,%1\;{cal %0,0(0)|li %0,0}\;{ae|adde} %0,%0,%0\;cmpli %3,%0,0
+ {ai|addic} %0,%1,%n2\;{cal %0,0(0)|li %0,0}\;{ae|adde} %0,%0,%0\;cmpli %3,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,12,16,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (plus:SI (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r")))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ ""
+ "@
+ {sf|subfc} %4,%2,%1\;{aze|addze} %0,%3
+ {ai|addic} %4,%1,%n2\;{aze|addze} %0,%3"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (plus:SI (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ ""
+ "@
+ {sf|subfc} %4,%2,%1\;{aze.|addze.} %4,%3
+ {ai|addic} %4,%1,%n2\;{aze.|addze.} %4,%3
+ {sf|subfc} %4,%2,%1\;{aze|addze} %4,%3\;cmpli %0,%4,0
+ {ai|addic} %4,%1,%n2\;{aze|addze} %4,%3\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,8,12,12")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (plus:SI (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (plus:SI (geu:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ ""
+ "@
+ {sf|subfc} %4,%2,%1\;{aze.|addze.} %0,%3
+ {ai|addic} %4,%1,%n2\;{aze.|addze.} %4,%3
+ {sf|subfc} %4,%2,%1\;{aze|addze} %0,%3\;cmpli %5,%0,0
+ {ai|addic} %4,%1,%n2\;{aze|addze} %4,%3\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,8,12,12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (neg:SI (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,I"))))]
+ ""
+ "@
+ {sf|subfc} %0,%2,%1\;{sfe|subfe} %0,%0,%0\;nand %0,%0,%0
+ {sfi|subfic} %0,%1,-1\;{a%I2|add%I2c} %0,%0,%2\;{sfe|subfe} %0,%0,%0"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (and:SI (neg:SI
+ (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P")))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r")))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ ""
+ "@
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;andc %0,%3,%4
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;andc %0,%3,%4"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (and:SI (neg:SI
+ (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P")))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ ""
+ "@
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;andc. %4,%3,%4
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;andc. %4,%3,%4
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;andc %4,%3,%4\;cmpli %0,%4,0
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;andc. %4,%3,%4\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,12,16,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (and:SI (neg:SI
+ (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P")))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (and:SI (neg:SI (geu:SI (match_dup 1) (match_dup 2))) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ ""
+ "@
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;andc. %0,%3,%4
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;andc. %0,%3,%4
+ {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;andc %0,%3,%4\;cmpli %5,%0,0
+ {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;andc %0,%3,%4\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,12,16,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (const_int 0)))]
+ ""
+ "{sfi|subfic} %0,%1,0\;{ame|addme} %0,%0\;{sri|srwi} %0,%0,31"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (const_int 0))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (gt:SI (match_dup 1) (const_int 0)))]
+ ""
+ "@
+ {sfi|subfic} %0,%1,0\;{ame|addme} %0,%0\;{sri.|srwi.} %0,%0,31
+ {sfi|subfic} %0,%1,0\;{ame|addme} %0,%0\;{sri|srwi} %0,%0,31\;cmpli %2,%0,0"
+ [(set_attr "type" "delayed_compare,compare")
+ (set_attr "length" "12,8")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "r")))]
+ "TARGET_POWER"
+ "doz %0,%2,%1\;nabs %0,%0\;{sri|srwi} %0,%0,31"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (gt:SI (match_dup 1) (match_dup 2)))]
+ "TARGET_POWER"
+ "@
+ doz %0,%2,%1\;nabs %0,%0\;{sri.|srwi.} %0,%0,31
+ doz %0,%2,%1\;nabs %0,%0\;{sri|srwi} %0,%0,31\;cmpli %3,%0,0"
+ [(set_attr "type" "delayed_compare,compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (const_int 0))
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ ""
+ "{a|addc} %3,%1,%1\;{sfe|subfe} %3,%1,%3\;{aze|addze} %0,%2"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (const_int 0))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=&r,&r"))]
+ ""
+ "@
+ {a|addc} %3,%1,%1\;{sfe|subfe} %3,%1,%3\;{aze.|addze.} %3,%2
+ {a|addc} %3,%1,%1\;{sfe|subfe} %3,%1,%3\;{aze|addze} %3,%2\;cmpli %0,%3"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (const_int 0))
+ (match_operand:SI 2 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (plus:SI (gt:SI (match_dup 1) (const_int 0)) (match_dup 2)))
+ (clobber (match_scratch:SI 3 "=&r,&r"))]
+ ""
+ "@
+ {a|addc} %3,%1,%1\;{sfe|subfe} %3,%1,%3\;{aze.|addze.} %3,%2
+ {a|addc} %3,%1,%1\;{sfe|subfe} %3,%1,%3\;{aze|addze} %3,%2\;cmpli %4,%3"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "r"))
+ (match_operand:SI 3 "gpc_reg_operand" "r")))
+ (clobber (match_scratch:SI 4 "=&r"))]
+ "TARGET_POWER"
+ "doz %4,%2,%1\;{ai|addic} %4,%4,-1\;{aze|addze} %0,%3"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,r"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ "TARGET_POWER"
+ "@
+ doz %4,%2,%1\;{ai|addic} %4,%4,-1\;{aze.|addze.} %4,%3
+ doz %4,%2,%1\;{ai|addic} %4,%4,-1\;{aze|addze} %4,%3\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "r,r"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (plus:SI (gt:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r"))]
+ "TARGET_POWER"
+ "@
+ doz %4,%2,%1\;{ai|addic} %4,%4,-1\;{aze.|addze.} %0,%3
+ doz %4,%2,%1\;{ai|addic} %4,%4,-1\;{aze|addze} %0,%3\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (neg:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (const_int 0))))]
+ ""
+ "{sfi|subfic} %0,%1,0\;{ame|addme} %0,%0\;{srai|srawi} %0,%0,31"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (neg:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "r"))))]
+ "TARGET_POWER"
+ "doz %0,%2,%1\;nabs %0,%0\;{srai|srawi} %0,%0,31"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (gtu:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI")))]
+ ""
+ "{sf%I2|subf%I2c} %0,%1,%2\;{sfe|subfe} %0,%0,%0\;neg %0,%0"
+ [(set_attr "length" "12")])
+
+(define_insn ""
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
+ (compare:CC
+ (gtu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+ (gtu:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ {sf%I2|subf%I2c} %0,%1,%2\;{sfe|subfe} %0,%0,%0\;neg. %0,%0
+ {sf%I2|subf%I2c} %0,%1,%2\;{sfe|subfe} %0,%0,%0\;neg %0,%0\;cmpli %3,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r")
+ (plus:SI (gtu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "I,r,rI"))
+ (match_operand:SI 3 "reg_or_short_operand" "r,r,I")))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r"))]
+ ""
+ "@
+ {ai|addic} %4,%1,%k2\;{aze|addze} %0,%3
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;{sf%I3|subf%I3c} %0,%4,%3
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;{sf%I3|subf%I3c} %0,%4,%3"
+ [(set_attr "length" "8,12,12")])
+
+(define_insn ""
+ [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (plus:SI (gtu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "I,r,I,r"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ ""
+ "@
+ {ai|addic} %4,%1,%k2\;{aze.|addze.} %4,%3
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;{sf.|subfc.} %4,%4,%3
+ {ai|addic} %4,%1,%k2\;{aze|addze} %0,%3\;cmpli %0,%4,0
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;{sf.|subfc.} %4,%4,%3\;cmpli %0,%4,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12,12,16")])
+
+(define_insn ""
+ [(set (match_operand:CC 5 "cc_reg_operand" "=x,x,?y,?y")
+ (compare:CC
+ (plus:SI (gtu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
+ (match_operand:SI 2 "reg_or_short_operand" "I,r,I,r"))
+ (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
+ (plus:SI (gtu:SI (match_dup 1) (match_dup 2)) (match_dup 3)))
+ (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))]
+ ""
+ "@
+ {ai|addic} %4,%1,%k2\;{aze.|addze.} %0,%3
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;{sf.|subfc.} %0,%4,%3
+ {ai|addic} %4,%1,%k2\;{aze|addze} %0,%3\;cmpli %5,%0,0
+ {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;{sf|subfc} %0,%4,%3\;cmpli %5,%0,0"
+ [(set_attr "type" "compare")
+ (set_attr "length" "8,12,12,16")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (neg:SI (gtu:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI"))))]
+ ""
+ "{sf%I2|subf%I2c} %0,%1,%2\;{sfe|subfe} %0,%0,%0"
+ [(set_attr "length" "8")])
+
+;; Define both directions of branch and return. If we need a reload
+;; register, we'd rather use CR0 since it is much easier to copy a
+;; register CC value to there.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (match_operator 1 "branch_comparison_operator"
+ [(match_operand 2
+ "cc_reg_operand" "x,?y")
+ (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ if (get_attr_length (insn) == 8)
+ return \"%C1bc %t1,%j1,%l0\";
+ else
+ return \"%C1bc %T1,%j1,%$+8\;b %l0\";
+
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (match_operator 0 "branch_comparison_operator"
+ [(match_operand 1
+ "cc_reg_operand" "x,?y")
+ (const_int 0)])
+ (return)
+ (pc)))]
+ "direct_return ()"
+ "{%C0bcr|%C0bclr} %t0,%j0"
+ [(set_attr "type" "branch")
+ (set_attr "length" "8")])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (match_operator 1 "branch_comparison_operator"
+ [(match_operand 2
+ "cc_reg_operand" "x,?y")
+ (const_int 0)])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "*
+{
+ if (get_attr_length (insn) == 8)
+ return \"%C1bc %T1,%j1,%l0\";
+ else
+ return \"%C1bc %t1,%j1,%$+8\;b %l0\";
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (match_operator 0 "branch_comparison_operator"
+ [(match_operand 1
+ "cc_reg_operand" "x,?y")
+ (const_int 0)])
+ (pc)
+ (return)))]
+ "direct_return ()"
+ "{%C0bcr|%C0bclr} %T0,%j0"
+ [(set_attr "type" "branch")
+ (set_attr "length" "8")])
+
+;; Unconditional branch and return.
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "b %l0"
+ [(set_attr "type" "branch")])
+
+(define_insn "return"
+ [(return)]
+ "direct_return ()"
+ "{br|blr}"
+ [(set_attr "type" "jmpreg")])
+
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "register_operand" "c,l"))]
+ ""
+ "@
+ bctr
+ {br|blr}"
+ [(set_attr "type" "jmpreg")])
+
+(define_insn ""
+ [(set (pc) (match_operand:DI 0 "register_operand" "c,l"))]
+ "TARGET_POWERPC64"
+ "@
+ bctr
+ {br|blr}"
+ [(set_attr "type" "jmpreg")])
+
+;; Table jump for switch statements:
+(define_expand "tablejump"
+ [(use (match_operand 0 "" ""))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "
+{
+ if (TARGET_32BIT)
+ emit_jump_insn (gen_tablejumpsi (operands[0], operands[1]));
+ else
+ emit_jump_insn (gen_tablejumpdi (operands[0], operands[1]));
+ DONE;
+}")
+
+(define_expand "tablejumpsi"
+ [(set (match_dup 3)
+ (plus:SI (match_operand:SI 0 "" "")
+ (match_dup 2)))
+ (parallel [(set (pc) (match_dup 3))
+ (use (label_ref (match_operand 1 "" "")))])]
+ ""
+ "
+{ operands[0] = force_reg (SImode, operands[0]);
+ operands[2] = force_reg (SImode, gen_rtx_LABEL_REF (VOIDmode, operands[1]));
+ operands[3] = gen_reg_rtx (SImode);
+}")
+
+(define_expand "tablejumpdi"
+ [(set (match_dup 3)
+ (plus:DI (match_operand:DI 0 "" "")
+ (match_dup 2)))
+ (parallel [(set (pc) (match_dup 3))
+ (use (label_ref (match_operand 1 "" "")))])]
+ ""
+ "
+{ operands[0] = force_reg (DImode, operands[0]);
+ operands[2] = force_reg (DImode, gen_rtx_LABEL_REF (VOIDmode, operands[1]));
+ operands[3] = gen_reg_rtx (DImode);
+}")
+
+(define_insn ""
+ [(set (pc)
+ (match_operand:SI 0 "register_operand" "c,l"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "@
+ bctr
+ {br|blr}"
+ [(set_attr "type" "jmpreg")])
+
+(define_insn ""
+ [(set (pc)
+ (match_operand:DI 0 "register_operand" "c,l"))
+ (use (label_ref (match_operand 1 "" "")))]
+ "TARGET_POWERPC64"
+ "@
+ bctr
+ {br|blr}"
+ [(set_attr "type" "jmpreg")])
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "{cror 0,0,0|nop}")
+
+;; Define the subtract-one-and-jump insns, starting with the template
+;; so loop.c knows what to generate.
+
+(define_expand "decrement_and_branch_on_count"
+ [(parallel [(set (pc) (if_then_else (ne (match_operand:SI 0 "register_operand" "")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int -1)))
+ (clobber (match_scratch:CC 2 ""))
+ (clobber (match_scratch:SI 3 ""))])]
+ ""
+ "")
+
+;; We need to be able to do this for any operand, including MEM, or we
+;; will cause reload to blow up since we don't allow output reloads on
+;; JUMP_INSNs.
+;; In order that the length attribute is calculated correctly, the
+;; label MUST be operand 0.
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 1 "register_operand" "c,*r,*r")
+ (const_int 1))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:SI 2 "register_operand" "=1,*r,m*q*c*l")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:CC 3 "=X,&x,&x"))
+ (clobber (match_scratch:SI 4 "=X,X,r"))]
+ ""
+ "*
+{
+ if (which_alternative != 0)
+ return \"#\";
+ else if (get_attr_length (insn) == 8)
+ return \"{bdn|bdnz} %l0\";
+ else
+ return \"bdz %$+8\;b %l0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "*,12,16")])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 1 "register_operand" "c,*r,*r")
+ (const_int 1))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))
+ (set (match_operand:SI 2 "register_operand" "=1,*r,m*q*c*l")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:CC 3 "=X,&x,&x"))
+ (clobber (match_scratch:SI 4 "=X,X,r"))]
+ ""
+ "*
+{
+ if (which_alternative != 0)
+ return \"#\";
+ else if (get_attr_length (insn) == 8)
+ return \"bdz %l0\";
+ else
+ return \"{bdn|bdnz} %$+8\;b %l0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "*,12,16")])
+
+;; Similar, but we can use GE since we have a REG_NONNEG.
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ge (match_operand:SI 1 "register_operand" "c,*r,*r")
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:SI 2 "register_operand" "=1,*r,m*q*c*l")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:CC 3 "=X,&x,&X"))
+ (clobber (match_scratch:SI 4 "=X,X,r"))]
+ "find_reg_note (insn, REG_NONNEG, 0)"
+ "*
+{
+ if (which_alternative != 0)
+ return \"#\";
+ else if (get_attr_length (insn) == 8)
+ return \"{bdn|bdnz} %l0\";
+ else
+ return \"bdz %$+8\;b %l0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "*,12,16")])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ge (match_operand:SI 1 "register_operand" "c,*r,*r")
+ (const_int 0))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))
+ (set (match_operand:SI 2 "register_operand" "=1,*r,m*q*c*l")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:CC 3 "=X,&x,&X"))
+ (clobber (match_scratch:SI 4 "=X,X,r"))]
+ "find_reg_note (insn, REG_NONNEG, 0)"
+ "*
+{
+ if (which_alternative != 0)
+ return \"#\";
+ else if (get_attr_length (insn) == 8)
+ return \"bdz %l0\";
+ else
+ return \"{bdn|bdnz} %$+8\;b %l0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "*,12,16")])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (eq (match_operand:SI 1 "register_operand" "c,*r,*r")
+ (const_int 1))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:SI 2 "register_operand" "=1,*r,m*q*c*l")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:CC 3 "=X,&x,&x"))
+ (clobber (match_scratch:SI 4 "=X,X,r"))]
+ ""
+ "*
+{
+ if (which_alternative != 0)
+ return \"#\";
+ else if (get_attr_length (insn) == 8)
+ return \"bdz %l0\";
+ else
+ return \"{bdn|bdnz} %$+8\;b %l0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "*,12,16")])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (eq (match_operand:SI 1 "register_operand" "c,*r,*r")
+ (const_int 1))
+ (pc)
+ (label_ref (match_operand 0 "" ""))))
+ (set (match_operand:SI 2 "register_operand" "=1,*r,m*q*c*l")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:CC 3 "=X,&x,&x"))
+ (clobber (match_scratch:SI 4 "=X,X,r"))]
+ ""
+ "*
+{
+ if (which_alternative != 0)
+ return \"#\";
+ else if (get_attr_length (insn) == 8)
+ return \"{bdn|bdnz} %l0\";
+ else
+ return \"bdz %$+8\;b %l0\";
+}"
+ [(set_attr "type" "branch")
+ (set_attr "length" "*,12,16")])
+
+(define_split
+ [(set (pc)
+ (if_then_else (match_operator 2 "comparison_operator"
+ [(match_operand:SI 1 "gpc_reg_operand" "")
+ (const_int 1)])
+ (match_operand 5 "" "")
+ (match_operand 6 "" "")))
+ (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (plus:SI (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:CC 3 ""))
+ (clobber (match_scratch:SI 4 ""))]
+ "reload_completed"
+ [(parallel [(set (match_dup 3)
+ (compare:CC (plus:SI (match_dup 1)
+ (const_int -1))
+ (const_int 0)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 1)
+ (const_int -1)))])
+ (set (pc) (if_then_else (match_dup 7)
+ (match_dup 5)
+ (match_dup 6)))]
+ "
+{ operands[7] = gen_rtx (GET_CODE (operands[2]), VOIDmode, operands[3],
+ const0_rtx); }")
+
+(define_split
+ [(set (pc)
+ (if_then_else (match_operator 2 "comparison_operator"
+ [(match_operand:SI 1 "gpc_reg_operand" "")
+ (const_int 1)])
+ (match_operand 5 "" "")
+ (match_operand 6 "" "")))
+ (set (match_operand:SI 0 "general_operand" "")
+ (plus:SI (match_dup 1) (const_int -1)))
+ (clobber (match_scratch:CC 3 ""))
+ (clobber (match_scratch:SI 4 ""))]
+ "reload_completed && ! gpc_reg_operand (operands[0], SImode)"
+ [(parallel [(set (match_dup 3)
+ (compare:CC (plus:SI (match_dup 1)
+ (const_int -1))
+ (const_int 0)))
+ (set (match_dup 4)
+ (plus:SI (match_dup 1)
+ (const_int -1)))])
+ (set (match_dup 0)
+ (match_dup 4))
+ (set (pc) (if_then_else (match_dup 7)
+ (match_dup 5)
+ (match_dup 6)))]
+ "
+{ operands[7] = gen_rtx (GET_CODE (operands[2]), VOIDmode, operands[3],
+ const0_rtx); }")
+
+(define_insn "trap"
+ [(trap_if (const_int 1) (const_int 0))]
+ ""
+ "{t 31,0,0|trap}")
+
+(define_expand "conditional_trap"
+ [(trap_if (match_operator 0 "trap_comparison_operator"
+ [(match_dup 2) (match_dup 3)])
+ (match_operand 1 "const_int_operand" ""))]
+ ""
+ "if (rs6000_compare_fp_p || operands[1] != const0_rtx) FAIL;
+ operands[2] = rs6000_compare_op0;
+ operands[3] = rs6000_compare_op1;")
+
+(define_insn ""
+ [(trap_if (match_operator 0 "trap_comparison_operator"
+ [(match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "reg_or_short_operand" "rI")])
+ (const_int 0))]
+ ""
+ "t%V0%I2 %1,%2")
+
+
+;; CYGNUS LOCAL -- meissner/branch prediction
+;; Branch prediction insns
+(define_expand "expectsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (expect:SI (match_operand:SI 1 "nonmemory_operand" "")
+ (match_operand:SI 2 "immediate_operand" "")))]
+ ""
+ "
+{
+ if (CONSTANT_P (operands[1]))
+ {
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+ }
+}")
+
+(define_insn "*expectsi3_internal"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r,?r,r,r,r")
+ (expect:SI (match_operand:SI 1 "nonmemory_operand" "0,r,I,J,i")
+ (match_operand:SI 2 "immediate_operand" "n,n,n,n,n")))]
+ ""
+ "@
+ # expect register %0 to be %2
+ mr %0,%1\;# expect register %0 to be %2
+ {lil|li} %0,%1
+ {liu|lis} %0,%v1
+ #"
+ [(set_attr "type" "integer")
+ (set_attr "length" "0,4,4,4,8")])
+
+;; Split a load of a large constant into the appropriate two-insn
+;; sequence.
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (expect:SI (match_operand:SI 1 "const_int_operand" "")
+ (match_operand:SI 2 "immediate_operand" "")))]
+ "(unsigned HOST_WIDE_INT) (INTVAL (operands[1]) + 0x8000) >= 0x10000
+ && (INTVAL (operands[1]) & 0xffff) != 0"
+ [(set (match_dup 0)
+ (match_dup 3))
+ (set (match_dup 0)
+ (ior:SI (match_dup 0)
+ (match_dup 4)))]
+ "
+{
+ operands[3] = gen_rtx (CONST_INT, VOIDmode,
+ INTVAL (operands[1]) & 0xffff0000);
+ operands[4] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) & 0xffff);
+}")
+
+(define_insn "*compare_expect1"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=y")
+ (compare:CC (expect:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (match_operand:SI 2 "immediate_operand" "n"))
+ (match_operand:SI 3 "reg_or_short_operand" "rI")))]
+ ""
+ "{cmp%I3|cmpw%I3} %0,%1,%3\\t# expect register %1 to be %2"
+ [(set_attr "type" "compare")])
+
+(define_insn "*compare_expect2"
+ [(set (match_operand:CC 0 "cc_reg_operand" "=y")
+ (compare:CC (expect:SI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "immediate_operand" "n"))
+ (match_operand:DI 3 "reg_or_short_operand" "rI")))]
+ "TARGET_POWERPC64"
+ "cmpd%I3 %0,%1,%3\\t# expect register %1 to be %2"
+ [(set_attr "type" "compare")])
+
+(define_insn "*branch_expect1"
+ [(set (pc)
+ (if_then_else (match_operator 1 "branch_comparison_operator"
+ [(expect (match_operand 2 "cc_reg_operand" "x,?y")
+ (match_operand:SI 3 "immediate_operand" "n,n"))
+ (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ if (get_attr_length (insn) == 8)
+ return \"%C1bc%Q3 %t1,%j1,%l0\";
+ else
+ return \"%C1bc%q3 %T1,%j1,%$+8\;b %l0\";
+
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn "*branch_expect2"
+ [(set (pc)
+ (if_then_else (match_operator 0 "branch_comparison_operator"
+ [(expect (match_operand 1 "cc_reg_operand" "x,?y")
+ (match_operand:SI 2 "immediate_operand" "n,n"))
+ (const_int 0)])
+ (return)
+ (pc)))]
+ "direct_return ()"
+ "{%C0bcr|%C0bclr}%Q2 %t0,%j0"
+ [(set_attr "type" "branch")
+ (set_attr "length" "8")])
+
+(define_insn "*branch_expect3"
+ [(set (pc)
+ (if_then_else (match_operator 1 "branch_comparison_operator"
+ [(expect (match_operand 2 "cc_reg_operand" "x,?y")
+ (match_operand:SI 3 "immediate_operand" "n,n"))
+ (const_int 0)])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "*
+{
+ if (get_attr_length (insn) == 8)
+ return \"%C1bc%q3 %T1,%j1,%l0\";
+ else
+ return \"%C1bc%Q3 %t1,%j1,%$+8\;b %l0\";
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn "*branch_expect4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "branch_comparison_operator"
+ [(expect (match_operand 1 "cc_reg_operand" "x,?y")
+ (match_operand:SI 2 "immediate_operand" "n,n"))
+ (const_int 0)])
+ (pc)
+ (return)))]
+ "direct_return ()"
+ "{%C0bcr|%C0bclr}%q2 %T0,%j0"
+ [(set_attr "type" "branch")
+ (set_attr "length" "8")])
+;; END CYGNUS LOCAL -- meissner/branch prediction
+
+;; CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling
+
+;; The following is necessary for generation of RTL representation of
+;; prologue and epilogue and subsequent instruction scheduling and
+;; branch delay slot scheduling (if any).
+
+;;
+;; ....................
+;;
+;; Function prologue/epilogue
+;;
+;; ....................
+;;
+
+(define_expand "prologue"
+ [(const_int 1)]
+ "TARGET_SCHED_PROLOG"
+ "
+{
+ rs6000_expand_prologue ();
+ DONE;
+}")
+
+;; At present, don't expand the epilogue, reorg.c will clobber the
+;; return register in compiling gen_lowpart (emit-rtl.c).
+
+(define_expand "epilogue"
+ [(const_int 2)]
+ "TARGET_SCHED_EPILOG"
+ "
+{
+ rs6000_expand_epilogue ();
+ DONE;
+}")
+
+(define_insn "movesi_from_cr"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (unspec [(reg:CC 68) (reg:CC 69) (reg:CC 70) (reg:CC 71) (reg:CC 72)
+ (reg:CC 73) (reg:CC 74) (reg:CC 75)] 101))]
+ "!TARGET_POWERPC64"
+ "mfcr %0")
+
+(define_insn "movedi_from_cr"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (unspec [(reg:CC 68) (reg:CC 69) (reg:CC 70) (reg:CC 71) (reg:CC 72)
+ (reg:CC 73) (reg:CC 74) (reg:CC 75)] 102))]
+ "TARGET_POWERPC64"
+ "mfcr %0")
+
+(define_insn "movesi_to_cr"
+ [(set (reg:CC 68) (unspec [(match_operand:SI 0 "gpc_reg_operand" "=r")] 113))
+ (set (reg:CC 69) (unspec [(match_dup 0)] 114))
+ (set (reg:CC 70) (unspec [(match_dup 0)] 115))
+ (set (reg:CC 71) (unspec [(match_dup 0)] 116))
+ (set (reg:CC 72) (unspec [(match_dup 0)] 117))
+ (set (reg:CC 73) (unspec [(match_dup 0)] 118))
+ (set (reg:CC 74) (unspec [(match_dup 0)] 119))
+ (set (reg:CC 75) (unspec [(match_dup 0)] 120))]
+ "!TARGET_POWERPC64"
+ "mtcr %0")
+
+(define_insn "movedi_to_cr"
+ [(set (reg:CC 68) (unspec [(match_operand:DI 0 "gpc_reg_operand" "=r")] 123))
+ (set (reg:CC 69) (unspec [(match_dup 0)] 124))
+ (set (reg:CC 70) (unspec [(match_dup 0)] 125))
+ (set (reg:CC 71) (unspec [(match_dup 0)] 126))
+ (set (reg:CC 72) (unspec [(match_dup 0)] 127))
+ (set (reg:CC 73) (unspec [(match_dup 0)] 128))
+ (set (reg:CC 74) (unspec [(match_dup 0)] 129))
+ (set (reg:CC 75) (unspec [(match_dup 0)] 130))]
+ "TARGET_POWERPC64"
+ "mtcr %0")
+
+(define_insn "loadsi_svr4_relocatable_toc"
+ [(set (reg:SI 30) (unspec [(pc)] 133))
+ (set (pc) (unspec [(pc)] 143))
+ (clobber (reg:SI 65))
+ (clobber (match_operand:SI 0 "gpc_reg_operand" "r"))]
+ ""
+ "*
+{
+ rs6000_output_load_toc_table (asm_out_file, 30, FALSE);
+ return \"# end of toc load\";
+}")
+
+(define_insn "loaddi_svr4_relocatable_toc"
+ [(set (reg:DI 30) (unspec [(pc)] 153))
+ (set (pc) (unspec [(pc)] 154))
+ (clobber (reg:DI 65))
+ (clobber (match_operand:DI 0 "gpc_reg_operand" "r"))]
+ ""
+ "*
+{
+ rs6000_output_load_toc_table (asm_out_file, 30, FALSE);
+ return \"# end of toc load\";
+}")
+
+(define_insn "loadsi_svr4_toc"
+ [(set (reg:SI 30) (unspec [(pc)] 134))]
+ ""
+ "*
+{
+ rs6000_output_load_toc_table (asm_out_file, 30, FALSE);
+ return \"# end of toc load\";
+}")
+
+(define_insn "loadsi_nonsvr4_toc"
+ [(set (reg:SI 30) (unspec [(pc)] 136))
+ (clobber (match_operand:SI 0 "gpc_reg_operand" "r"))]
+ ""
+ "*
+{
+ rs6000_output_load_toc_table (asm_out_file, 30, FALSE);
+ return \"# end of toc load\";
+}")
+
+(define_insn "loaddi_nonsvr4_toc"
+ [(set (reg:DI 30) (unspec [(pc)] 137))
+ (clobber (match_operand:DI 0 "gpc_reg_operand" "r"))]
+ ""
+ "*
+{
+ rs6000_output_load_toc_table (asm_out_file, 30, FALSE);
+ return \"# end of toc load\";
+}")
+
+;; END CYGNUS LOCAL -- vmakarov/prolog-epilog instruction scheduling
diff --git a/gcc/config/rs6000/rtems.h b/gcc/config/rs6000/rtems.h
new file mode 100755
index 0000000..bf14072
--- /dev/null
+++ b/gcc/config/rs6000/rtems.h
@@ -0,0 +1,38 @@
+/* Definitions for rtems targeting a PowerPC using elf.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Joel Sherrill (joel@OARcorp.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "rs6000/eabi.h"
+
+/* Specify predefined symbols in preprocessor. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-DPPC -Drtems -D__rtems__ \
+ -Asystem(rtems) -Acpu(powerpc) -Amachine(powerpc)"
+
+/* Generate calls to memcpy, memcmp and memset. */
+#ifndef TARGET_MEM_FUNCTIONS
+#define TARGET_MEM_FUNCTIONS
+#endif
+
+#undef STARTFILE_DEFAULT_SPEC
+#define STARTFILE_DEFAULT_SPEC "crt0.o%s"
+
+/* end of rs6000/rtems.h */
diff --git a/gcc/config/rs6000/sol-c0.c b/gcc/config/rs6000/sol-c0.c
new file mode 100755
index 0000000..bf935c3
--- /dev/null
+++ b/gcc/config/rs6000/sol-c0.c
@@ -0,0 +1,122 @@
+/* Solaris PowerPC startfile. */
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+extern char **_environ;
+
+extern int atexit (void (*__func) (void));
+extern void __init (void) __attribute__ ((__longcall__));
+extern void __fini (void) __attribute__ ((__longcall__));
+
+typedef void (*func_ptr) (void);
+int (*__atexit)(func_ptr) = atexit;
+
+/* Exception handling */
+struct ex_shared1 {
+ void *prev;
+ void *next;
+ char *text_start;
+ char *range_start;
+ char *text_end;
+ char *range_end;
+};
+
+struct ex_shared {
+ void (*ex_register) (struct ex_shared1 *);
+ void (*ex_deregister) (struct ex_shared1 *);
+ struct ex_shared1 shared_info;
+};
+
+extern char _ex_text0[], _ex_text1[];
+extern char _ex_range0[], _ex_range1[];
+extern void _ex_register (struct ex_shared1 *);
+extern void _ex_deregister (struct ex_shared1 *);
+extern char _SDA_BASE_[];
+extern char _SDA2_BASE_[];
+
+struct ex_shared shared __attribute__((section(".ex_shared"))) = {
+ _ex_register,
+ _ex_deregister,
+ {
+ (void *)0,
+ (void *)0,
+ _ex_text0,
+ _ex_range0,
+ _ex_text1,
+ _ex_range1
+ }
+};
+
+static void
+deregister (void)
+{
+ (* shared.ex_deregister) (&shared.shared_info);
+}
+
+/* Start function. */
+void
+_start(int argc, char *argv[], char *envp[], void *auxp, void (*termfunc)())
+{
+ int ret;
+ int dummy = 0;
+
+#if 0
+ /* Disable this for now, it causes an impossible reload. */
+ /* Load up r13/r2 before we do anything else. */
+ __asm__ volatile ("mr %%r13,%0;mr %%r2,%1" : "=r" (dummy) : "r" (&_SDA_BASE_[0]), "r" (&_SDA2_BASE_[0]), "r" (dummy));
+#endif
+
+ _environ = envp + dummy;
+
+ /* Register loader termination function (the || dummy is to make sure the above asm
+ is not optimized away). */
+ if (termfunc)
+ atexit (termfunc);
+
+ /* Register exception handler if needed */
+ if (shared.ex_register)
+ (* shared.ex_register) (&shared.shared_info);
+
+ if (shared.ex_deregister)
+ atexit (deregister);
+
+ /* Call any global constructors and destructors. */
+ __init ();
+
+ atexit (__fini);
+
+ /* Call the main program now */
+ ret = main (argc, argv, envp, auxp);
+
+ /* Return to the os */
+ exit (ret);
+}
+
+/* Provide a dummy __eabi in case main got compiled without -mcall-solaris. */
+void
+__eabi ()
+{
+}
diff --git a/gcc/config/rs6000/sol-ci.asm b/gcc/config/rs6000/sol-ci.asm
new file mode 100755
index 0000000..d0eced3
--- /dev/null
+++ b/gcc/config/rs6000/sol-ci.asm
@@ -0,0 +1,104 @@
+# crti.s for solaris
+
+# Copyright (C) 1996 Free Software Foundation, Inc.
+# Written By Michael Meissner
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# In addition to the permissions in the GNU General Public License, the
+# Free Software Foundation gives you unlimited permission to link the
+# compiled version of this file with other programs, and to distribute
+# those programs without any restriction coming from the use of this
+# file. (The General Public License restrictions do apply in other
+# respects; for example, they cover modification of the file, and
+# distribution when not linked into another program.)
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# As a special exception, if you link this library with files
+# compiled with GCC to produce an executable, this does not cause
+# the resulting executable to be covered by the GNU General Public License.
+# This exception does not however invalidate any other reasons why
+# the executable file might be covered by the GNU General Public License.
+#
+
+# This file just supplies labeled starting points for the .got* and other
+# special sections. It is linked in first before other modules.
+
+ .file "scrti.s"
+ .ident "GNU C scrti.s"
+
+# Start of .text
+ .section ".text"
+ .globl _ex_text0
+_ex_text0:
+
+# Exception range
+ .section ".exception_ranges","aw"
+ .globl _ex_range0
+_ex_range0:
+
+# List of C++ constructors
+ .section ".ctors","aw"
+ .globl __CTOR_LIST__
+ .type __CTOR_LIST__,@object
+__CTOR_LIST__:
+
+# List of C++ destructors
+ .section ".dtors","aw"
+ .globl __DTOR_LIST__
+ .type __DTOR_LIST__,@object
+__DTOR_LIST__:
+
+# Head of __init function used for static constructors in Solaris
+ .section ".init","ax"
+ .align 2
+ .globl __init
+ .type __init,@function
+__init: stwu %r1,-16(%r1)
+ mflr %r0
+ stw %r31,12(%r1)
+ stw %r0,16(%r1)
+
+ bl _GLOBAL_OFFSET_TABLE_-4 # get the GOT address
+ mflr %r31
+
+# lwz %r3,_ex_shared0@got(%r31)
+# lwz %r4,-8(%r3) # _ex_register or 0
+# cmpi %cr0,%r4,0
+# beq .Lno_reg
+# mtlr %r4
+# blrl
+#.Lno_reg:
+
+# Head of __fini function used for static destructors in Solaris
+ .section ".fini","ax"
+ .align 2
+ .globl __fini
+ .type __fini,@function
+__fini: stwu %r1,-16(%r1)
+ mflr %r0
+ stw %r31,12(%r1)
+ stw %r0,16(%r1)
+
+ bl _GLOBAL_OFFSET_TABLE_-4 # get the GOT address
+ mflr %r31
+
+# _environ and its evil twin environ, pointing to the environment
+ .section ".sdata","aw"
+ .align 2
+ .globl _environ
+ .space 4
+ .weak environ
+ .set environ,_environ
diff --git a/gcc/config/rs6000/sol-cn.asm b/gcc/config/rs6000/sol-cn.asm
new file mode 100755
index 0000000..2bc992e
--- /dev/null
+++ b/gcc/config/rs6000/sol-cn.asm
@@ -0,0 +1,82 @@
+# crtn.s for solaris
+
+# Copyright (C) 1996 Free Software Foundation, Inc.
+# Written By Michael Meissner
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+#
+# In addition to the permissions in the GNU General Public License, the
+# Free Software Foundation gives you unlimited permission to link the
+# compiled version of this file with other programs, and to distribute
+# those programs without any restriction coming from the use of this
+# file. (The General Public License restrictions do apply in other
+# respects; for example, they cover modification of the file, and
+# distribution when not linked into another program.)
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+# As a special exception, if you link this library with files
+# compiled with GCC to produce an executable, this does not cause
+# the resulting executable to be covered by the GNU General Public License.
+# This exception does not however invalidate any other reasons why
+# the executable file might be covered by the GNU General Public License.
+#
+
+# This file just supplies labeled ending points for the .got* and other
+# special sections. It is linked in last after other modules.
+
+ .file "scrtn.s"
+ .ident "GNU C scrtn.s"
+
+# Default versions of exception handling register/deregister
+ .weak _ex_register
+ .weak _ex_deregister
+ .set _ex_register,0
+ .set _ex_deregister,0
+
+# End list of C++ constructors
+ .section ".ctors","aw"
+ .globl __CTOR_END__
+ .type __CTOR_END__,@object
+__CTOR_END__:
+
+# End list of C++ destructors
+ .section ".dtors","aw"
+ .globl __DTOR_END__
+ .type __DTOR_END__,@object
+__DTOR_END__:
+
+ .section ".text"
+ .globl _ex_text1
+_ex_text1:
+
+ .section ".exception_ranges","aw"
+ .globl _ex_range1
+_ex_range1:
+
+# Tail of __init used for static constructors in Solaris
+ .section ".init","ax"
+ lwz %r0,16(%r1)
+ lwz %r31,12(%r1)
+ mtlr %r0
+ addi %r1,%r1,16
+ blr
+
+# Tail of __fini used for static destructors in Solaris
+ .section ".fini","ax"
+ lwz %r0,16(%r1)
+ lwz %r31,12(%r1)
+ mtlr %r0
+ addi %r1,%r1,16
+ blr
diff --git a/gcc/config/rs6000/sol2.h b/gcc/config/rs6000/sol2.h
new file mode 100755
index 0000000..0f1b13b
--- /dev/null
+++ b/gcc/config/rs6000/sol2.h
@@ -0,0 +1,179 @@
+/* Definitions of target machine for GNU compiler,
+ for IBM RS/6000 running AIX version 3.1.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by David Reese (Dave.Reese@East.Sun.COM)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "rs6000/sysv4le.h"
+
+/* Default ABI to use */
+#undef RS6000_ABI_NAME
+#define RS6000_ABI_NAME "solaris"
+
+#undef ASM_CPU_SPEC
+#define ASM_CPU_SPEC "-le -s"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | \
+ MASK_NEW_MNEMONICS | \
+ MASK_LITTLE_ENDIAN | \
+ MASK_REGNAMES)
+
+#undef LIB_DEFAULT_SPEC
+#define LIB_DEFAULT_SPEC "%(lib_solaris)"
+
+#undef STARTFILE_DEFAULT_SPEC
+#define STARTFILE_DEFAULT_SPEC "%(startfile_solaris)"
+
+#undef ENDFILE_DEFAULT_SPEC
+#define ENDFILE_DEFAULT_SPEC "%(endfile_solaris)"
+
+#undef LINK_START_DEFAULT_SPEC
+#define LINK_START_DEFAULT_SPEC "%(link_start_solaris)"
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{posix: -D_POSIX_SOURCE}\
+%(cpp_sysv) %(cpp_endian) %(cpp_cpu) \
+%{mmvme: %(cpp_os_mvme) } \
+%{msim: %(cpp_os_sim) } \
+%{mcall-linux: %(cpp_os_linux) } \
+%{mcall-solaris: %(cpp_os_solaris) } \
+%{!mmvme: %{!msim: %{!mcall-linux: %{!mcall-solaris: %(cpp_os_default) }}}}"
+
+#undef CPP_OS_DEFAULT_SPEC
+#define CPP_OS_DEFAULT_SPEC "%(cpp_os_solaris)"
+
+#undef LINK_OS_DEFAULT_SPEC
+#define LINK_OS_DEFAULT_SPEC "%(link_os_solaris)"
+
+#undef CPP_ENDIAN_LITTLE_SPEC
+#define CPP_ENDIAN_LITTLE_SPEC CPP_ENDIAN_SOLARIS_SPEC
+
+/* Don't turn -B into -L if the argument specifies a relative file name. */
+#undef RELATIVE_PREFIX_NOT_LINKDIR
+
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (PowerPC Solaris)");
+
+
+/* Macros to check register numbers against specific register classes. */
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+
+#if 0
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ fprintf ((FILE), "\t%s\t", ".lcomm"); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
+} while (0)
+#endif
+
+/* Like block addresses, stabs line numbers are relative to the
+ current function. */
+
+/* use .stabd instead of .stabn */
+
+#define ASM_STABN_OP ".stabd"
+
+#undef ASM_OUTPUT_SOURCE_LINE
+#define ASM_OUTPUT_SOURCE_LINE(file, line) \
+do \
+ { \
+ static int sym_lineno = 1; \
+ char *_p; \
+ fprintf (file, "\t.stabd 68,0,%d,.LM%d-", \
+ line, sym_lineno); \
+ STRIP_NAME_ENCODING (_p, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); \
+ assemble_name (file, _p); \
+ fprintf (file, "\n.LM%d:\n", sym_lineno); \
+ sym_lineno += 1; \
+ } \
+while (0)
+
+/* This is how to output an assembler line defining a `double' constant. */
+
+#undef ASM_OUTPUT_DOUBLE
+#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \
+ { \
+ if (REAL_VALUE_ISINF (VALUE) \
+ || REAL_VALUE_ISNAN (VALUE) \
+ || REAL_VALUE_MINUS_ZERO (VALUE)) \
+ { \
+ long t[2]; \
+ REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \
+ fprintf (FILE, "\t.long 0x%lx\n\t.long 0x%lx\n", \
+ t[0] & 0xffffffff, t[1] & 0xffffffff); \
+ } \
+ else \
+ { \
+ char str[30]; \
+ REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", str); \
+ fprintf (FILE, "\t.double %s\n", str); \
+ } \
+ }
+
+/* This is how to output an assembler line defining a `float' constant. */
+
+#undef ASM_OUTPUT_FLOAT
+#define ASM_OUTPUT_FLOAT(FILE, VALUE) \
+ { \
+ if (REAL_VALUE_ISINF (VALUE) \
+ || REAL_VALUE_ISNAN (VALUE) \
+ || REAL_VALUE_MINUS_ZERO (VALUE)) \
+ { \
+ long t; \
+ REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
+ fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
+ } \
+ else \
+ { \
+ char str[30]; \
+ REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
+ fprintf (FILE, "\t.float %s\n", str); \
+ } \
+ }
+
+
+/* Sun-ppc assembler does not permit '.' in some symbol names.
+ Use 'name_.labelno' instead. */
+#undef ASM_FORMAT_PRIVATE_NAME
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
+( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
+ sprintf ((OUTPUT), "%s_.%d", (NAME), (LABELNO)))
+
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using `MULTILIB_OPTIONS'.
+
+ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
+ the target makefile fragment or if none of the options listed in
+ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mlittle", "mcall-solaris" }
+
+#define STDC_0_IN_SYSTEM_HEADERS
diff --git a/gcc/config/rs6000/sysv4.h b/gcc/config/rs6000/sysv4.h
new file mode 100755
index 0000000..c0564c3
--- /dev/null
+++ b/gcc/config/rs6000/sysv4.h
@@ -0,0 +1,1770 @@
+/* Target definitions for GNU compiler for PowerPC running System V.4
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Small data support types */
+enum rs6000_sdata_type {
+ SDATA_NONE, /* no small data support */
+ SDATA_DATA, /* just put data in .sbss/.sdata, don't use relocs */
+ SDATA_SYSV, /* Use r13 to point to .sdata/.sbss */
+ SDATA_EABI /* Use r13 like above, r2 points to .sdata2/.sbss2 */
+};
+
+extern enum rs6000_sdata_type rs6000_sdata;
+
+/* V.4/eabi switches */
+#define MASK_NO_BITFIELD_TYPE 0x40000000 /* Set PCC_BITFIELD_TYPE_MATTERS to 0 */
+#define MASK_STRICT_ALIGN 0x20000000 /* Set STRICT_ALIGNMENT to 1. */
+#define MASK_RELOCATABLE 0x10000000 /* GOT pointers are PC relative */
+#define MASK_EABI 0x08000000 /* Adhere to eabi, not System V spec */
+#define MASK_LITTLE_ENDIAN 0x04000000 /* target is little endian */
+#define MASK_REGNAMES 0x02000000 /* use alternate register names. */
+#define MASK_PROTOTYPE 0x01000000 /* Only prototyped fcns pass variable args */
+/* CYGNUS LOCAL vmakarov */
+#define MASK_NO_BITFIELD_WORD 0x00400000 /* Bitfields cannot cross word boundaries */
+/* END CYGNUS LOCAL */
+
+#define TARGET_NO_BITFIELD_TYPE (target_flags & MASK_NO_BITFIELD_TYPE)
+#define TARGET_STRICT_ALIGN (target_flags & MASK_STRICT_ALIGN)
+#define TARGET_RELOCATABLE (target_flags & MASK_RELOCATABLE)
+#define TARGET_EABI (target_flags & MASK_EABI)
+/* CYGNUS LOCAL vmakarov */
+#define TARGET_NO_BITFIELD_WORD (target_flags & MASK_NO_BITFIELD_WORD)
+/* END CYGNUS LOCAL */
+#define TARGET_LITTLE_ENDIAN (target_flags & MASK_LITTLE_ENDIAN)
+#define TARGET_REGNAMES (target_flags & MASK_REGNAMES)
+#define TARGET_PROTOTYPE (target_flags & MASK_PROTOTYPE)
+#define TARGET_TOC ((target_flags & MASK_64BIT) \
+ || ((target_flags & (MASK_RELOCATABLE \
+ | MASK_MINIMAL_TOC)) \
+ && flag_pic > 1) \
+ || DEFAULT_ABI == ABI_AIX \
+ || DEFAULT_ABI == ABI_NT)
+
+#define TARGET_BITFIELD_TYPE (! TARGET_NO_BITFIELD_TYPE)
+#define TARGET_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN)
+#define TARGET_NO_PROTOTYPE (! TARGET_PROTOTYPE)
+#define TARGET_NO_TOC (! TARGET_TOC)
+#define TARGET_NO_EABI (! TARGET_EABI)
+/* CYGNUS LOCAL vmakarov */
+#define TARGET_BITFIELD_WORD (! TARGET_NO_BITFIELD_WORD)
+/* END CYGNUS LOCAL */
+
+/* Pseudo target to indicate whether the object format is ELF
+ (to get around not having conditional compilation in the md file) */
+#define TARGET_ELF 1
+
+/* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be just
+ the same as -mminimal-toc. */
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ { "bit-align", -MASK_NO_BITFIELD_TYPE }, \
+ { "no-bit-align", MASK_NO_BITFIELD_TYPE }, \
+ { "strict-align", MASK_STRICT_ALIGN }, \
+ { "no-strict-align", -MASK_STRICT_ALIGN }, \
+ { "relocatable", MASK_RELOCATABLE | MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC }, \
+ { "no-relocatable", -MASK_RELOCATABLE }, \
+ { "relocatable-lib", MASK_RELOCATABLE | MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC }, \
+ { "no-relocatable-lib", -MASK_RELOCATABLE }, \
+ { "little-endian", MASK_LITTLE_ENDIAN }, \
+ { "little", MASK_LITTLE_ENDIAN }, \
+ { "big-endian", -MASK_LITTLE_ENDIAN }, \
+ { "big", -MASK_LITTLE_ENDIAN }, \
+ { "no-toc", 0 }, \
+ { "toc", MASK_MINIMAL_TOC }, \
+ { "full-toc", MASK_MINIMAL_TOC }, \
+ { "prototype", MASK_PROTOTYPE }, \
+ { "no-prototype", -MASK_PROTOTYPE }, \
+ { "no-traceback", 0 }, \
+ { "eabi", MASK_EABI }, \
+ { "no-eabi", -MASK_EABI }, \
+/* CYGNUS LOCAL vmakarov */ \
+ { "bit-word", -MASK_NO_BITFIELD_WORD }, \
+ { "no-bit-word", MASK_NO_BITFIELD_WORD }, \
+/* END CYGNUS LOCAL */ \
+ { "regnames", MASK_REGNAMES }, \
+ { "no-regnames", -MASK_REGNAMES }, \
+ { "sdata", 0 }, \
+ { "no-sdata", 0 }, \
+ { "sim", 0 }, \
+ { "ads", 0 }, \
+ { "yellowknife", 0 }, \
+ { "mvme", 0 }, \
+ { "emb", 0 }, \
+ { "solaris-cclib", 0 }, \
+ { "shlib", 0 }, \
+/* CYGNUS LOCAL vmakarov */ \
+ { "vxworks", 0 }, \
+/* END CYGNUS LOCAL */ \
+ EXTRA_SUBTARGET_SWITCHES \
+ { "newlib", 0 },
+
+/* This is meant to be redefined in the host dependent files */
+#define EXTRA_SUBTARGET_SWITCHES
+
+/* Default ABI to use */
+#define RS6000_ABI_NAME "sysv"
+
+/* Strings provided by SUBTARGET_OPTIONS */
+extern char *rs6000_abi_name;
+extern char *rs6000_sdata_name;
+
+#define SUBTARGET_OPTIONS \
+ { "call-", &rs6000_abi_name}, \
+ { "sdata=", &rs6000_sdata_name}
+
+/* Max # of bytes for variables to automatically be put into the .sdata
+ or .sdata2 sections. */
+extern int g_switch_value; /* value of the -G xx switch */
+extern int g_switch_set; /* whether -G xx was passed. */
+
+#ifndef SDATA_DEFAULT_SIZE
+#define SDATA_DEFAULT_SIZE 8
+#endif
+
+/* Sometimes certain combinations of command options do not make sense
+ on a particular target machine. You can define a macro
+ `OVERRIDE_OPTIONS' to take account of this. This macro, if
+ defined, is executed once just after all the command options have
+ been parsed.
+
+ The macro SUBTARGET_OVERRIDE_OPTIONS is provided for subtargets, to
+ get control. */
+
+#define SUBTARGET_OVERRIDE_OPTIONS \
+do { \
+ if (!g_switch_set) \
+ g_switch_value = SDATA_DEFAULT_SIZE; \
+ \
+ if (!strcmp (rs6000_abi_name, "sysv")) \
+ rs6000_current_abi = ABI_V4; \
+ else if (!strcmp (rs6000_abi_name, "sysv-noeabi")) \
+ { \
+ rs6000_current_abi = ABI_V4; \
+ target_flags &= ~ MASK_EABI; \
+ } \
+ else if (!strcmp (rs6000_abi_name, "sysv-eabi") \
+ || !strcmp (rs6000_abi_name, "eabi")) \
+ { \
+ rs6000_current_abi = ABI_V4; \
+ target_flags |= MASK_EABI; \
+ } \
+ else if (!strcmp (rs6000_abi_name, "aix")) \
+ { \
+ rs6000_current_abi = ABI_AIX_NODESC; \
+ target_flags |= MASK_EABI; \
+ } \
+ else if (!strcmp (rs6000_abi_name, "aixdesc")) \
+ rs6000_current_abi = ABI_AIX; \
+ else if (!strcmp (rs6000_abi_name, "nt")) \
+ rs6000_current_abi = ABI_NT; \
+ else if (!strcmp (rs6000_abi_name, "linux")) \
+ rs6000_current_abi = ABI_V4; \
+ else if (!strcmp (rs6000_abi_name, "solaris")) \
+ rs6000_current_abi = ABI_SOLARIS; \
+/* CYGNUS LOCAL vmakarov */ \
+ else if (!strcmp (rs6000_abi_name, "i960-old")) \
+ { \
+ rs6000_current_abi = ABI_V4; \
+ target_flags |= (MASK_LITTLE_ENDIAN | MASK_EABI \
+ | MASK_NO_BITFIELD_WORD); \
+ target_flags &= ~MASK_STRICT_ALIGN; \
+ } \
+/* END CYGNUS LOCAL */ \
+ else \
+ { \
+ rs6000_current_abi = ABI_V4; \
+ error ("Bad value for -mcall-%s", rs6000_abi_name); \
+ } \
+ \
+ if (rs6000_sdata_name) \
+ { \
+ if (!strcmp (rs6000_sdata_name, "none")) \
+ rs6000_sdata = SDATA_NONE; \
+ else if (!strcmp (rs6000_sdata_name, "data")) \
+ rs6000_sdata = SDATA_DATA; \
+ else if (!strcmp (rs6000_sdata_name, "default")) \
+ rs6000_sdata = (TARGET_EABI) ? SDATA_EABI : SDATA_SYSV; \
+ else if (!strcmp (rs6000_sdata_name, "sysv")) \
+ rs6000_sdata = SDATA_SYSV; \
+ else if (!strcmp (rs6000_sdata_name, "eabi")) \
+ rs6000_sdata = SDATA_EABI; \
+ else \
+ error ("Bad value for -msdata=%s", rs6000_sdata_name); \
+ } \
+ else if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) \
+ { \
+ rs6000_sdata = SDATA_DATA; \
+ rs6000_sdata_name = "data"; \
+ } \
+ else \
+ { \
+ rs6000_sdata = SDATA_NONE; \
+ rs6000_sdata_name = "none"; \
+ } \
+ \
+ if (TARGET_RELOCATABLE && \
+ (rs6000_sdata == SDATA_EABI || rs6000_sdata == SDATA_SYSV)) \
+ { \
+ rs6000_sdata = SDATA_DATA; \
+ error ("-mrelocatable and -msdata=%s are incompatible.", \
+ rs6000_sdata_name); \
+ } \
+ \
+ else if (flag_pic && \
+ (rs6000_sdata == SDATA_EABI || rs6000_sdata == SDATA_SYSV)) \
+ { \
+ rs6000_sdata = SDATA_DATA; \
+ error ("-f%s and -msdata=%s are incompatible.", \
+ (flag_pic > 1) ? "PIC" : "pic", \
+ rs6000_sdata_name); \
+ } \
+ \
+ if (rs6000_sdata != SDATA_NONE && DEFAULT_ABI != ABI_V4 \
+ && DEFAULT_ABI != ABI_SOLARIS) \
+ { \
+ rs6000_sdata = SDATA_NONE; \
+ error ("-msdata=%s and -mcall-%s are incompatible.", \
+ rs6000_sdata_name, rs6000_abi_name); \
+ } \
+ \
+ if (TARGET_RELOCATABLE && !TARGET_MINIMAL_TOC) \
+ { \
+ target_flags |= MASK_MINIMAL_TOC; \
+ error ("-mrelocatable and -mno-minimal-toc are incompatible."); \
+ } \
+ \
+ if (TARGET_RELOCATABLE && \
+ (rs6000_current_abi == ABI_AIX || rs6000_current_abi == ABI_NT)) \
+ { \
+ target_flags &= ~MASK_RELOCATABLE; \
+ error ("-mrelocatable and -mcall-%s are incompatible.", \
+ rs6000_abi_name); \
+ } \
+ \
+ if (flag_pic > 1 && \
+ (rs6000_current_abi == ABI_AIX || rs6000_current_abi == ABI_NT)) \
+ { \
+ flag_pic = 0; \
+ error ("-fPIC and -mcall-%s are incompatible.", \
+ rs6000_abi_name); \
+ } \
+ \
+ if (rs6000_current_abi == ABI_AIX && TARGET_LITTLE_ENDIAN) \
+ { \
+ target_flags &= ~MASK_LITTLE_ENDIAN; \
+ error ("-mcall-aixdesc must be big endian"); \
+ } \
+ \
+ if (rs6000_current_abi == ABI_NT && TARGET_BIG_ENDIAN) \
+ { \
+ target_flags |= MASK_LITTLE_ENDIAN; \
+ error ("-mcall-nt must be little endian"); \
+ } \
+ \
+ /* Treat -fPIC the same as -mrelocatable */ \
+ if (flag_pic > 1) \
+ target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC; \
+ \
+ else if (TARGET_RELOCATABLE) \
+ flag_pic = 2; \
+ \
+} while (0)
+
+/* Default ABI to compile code for */
+#define DEFAULT_ABI rs6000_current_abi
+
+#define CPP_DEFAULT_SPEC "-D_ARCH_PPC"
+
+#define ASM_DEFAULT_SPEC "-mppc"
+
+#include "rs6000/rs6000.h"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS)
+
+#undef PROCESSOR_DEFAULT
+#define PROCESSOR_DEFAULT PROCESSOR_PPC601
+
+/* System V.4 uses register 13 as a pointer to the small data area,
+ so it is not available to the normal user. */
+
+#undef FIXED_R13
+#define FIXED_R13 1
+
+/* System V.4 passes the first 8 floating arguments in registers,
+ instead of the first 13 like AIX does. */
+#undef FP_ARG_MAX_REG
+#define FP_ARG_MAX_REG ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_AIX_NODESC) \
+ ? FP_ARG_AIX_MAX_REG : FP_ARG_V4_MAX_REG)
+
+/* Size of the V.4 varargs area if needed */
+#undef RS6000_VARARGS_AREA
+#define RS6000_VARARGS_AREA ((rs6000_sysv_varargs_p) ? RS6000_VARARGS_SIZE : 0)
+
+/* Override default big endianism */
+#undef BYTES_BIG_ENDIAN
+#undef WORDS_BIG_ENDIAN
+#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN)
+#define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN)
+
+/* Define this to set the endianness to use in libgcc2.c, which can
+ not depend on target_flags. */
+#if !defined(_LITTLE_ENDIAN) && !defined(__sun__)
+#define LIBGCC2_WORDS_BIG_ENDIAN 1
+#else
+#define LIBGCC2_WORDS_BIG_ENDIAN 0
+#endif
+
+/* Size of the outgoing register save area */
+#undef RS6000_REG_SAVE
+#define RS6000_REG_SAVE ((DEFAULT_ABI == ABI_AIX \
+ || DEFAULT_ABI == ABI_AIX_NODESC) \
+ ? (TARGET_64BIT ? 64 : 32) \
+ : 0)
+
+/* Size of the fixed area on the stack. For AIX, use the standard 6 word
+ area, otherwise use 2 words to store back chain & LR. */
+#undef RS6000_SAVE_AREA
+#define RS6000_SAVE_AREA \
+ (((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_AIX_NODESC) ? 24 : 8) << (TARGET_64BIT ? 1 : 0))
+
+/* Define cutoff for using external functions to save floating point.
+ Currently on V.4, always use inline stores */
+#undef FP_SAVE_INLINE
+#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 64)
+
+/* Don't generate XCOFF debugging information. */
+
+#undef XCOFF_DEBUGGING_INFO
+
+/* Don't use the COFF object file format. */
+
+#undef OBJECT_FORMAT_COFF
+
+/* Don't bother to output .extern pseudo-ops. They are not needed by
+ ELF assemblers. */
+
+#undef ASM_OUTPUT_EXTERNAL
+
+/* Put jump tables in read-only memory, rather than in .text. */
+#undef JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION 0
+
+/* Disable AIX-ism that disables turning -B into -L if the argument specifies a
+ relative file name. This breaks setting GCC_EXEC_PREFIX to D:\path under
+ Windows. */
+#undef RELATIVE_PREFIX_NOT_LINKDIR
+
+/* Undefine some things which are defined by the generic svr4.h. */
+
+#undef ASM_FILE_END
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+#undef READONLY_DATA_SECTION
+#undef SELECT_SECTION
+#undef ASM_DECLARE_FUNCTION_NAME
+#undef ASM_OUTPUT_CONSTRUCTOR
+#undef ASM_OUTPUT_DESTRUCTOR
+
+/* Use the regular svr4 definitions. */
+
+#include "svr4.h"
+
+/* Prefix and suffix to use to saving floating point */
+#undef SAVE_FP_PREFIX
+#undef SAVE_FP_SUFFIX
+#define SAVE_FP_PREFIX "_savefpr_"
+#define SAVE_FP_SUFFIX "_l"
+
+/* Prefix and suffix to use to restoring floating point */
+#undef RESTORE_FP_PREFIX
+#undef RESTORE_FP_SUFFIX
+#define RESTORE_FP_PREFIX "_restfpr_"
+#define RESTORE_FP_SUFFIX "_l"
+
+/* Type used for ptrdiff_t, as a string used in a declaration. */
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+/* CYGNUS LOCAL vmakarov */
+#if 0
+/* END CYGNUS LOCAL */
+
+/* Variables to set wchar_t size/type */
+extern char *rs6000_wchar_type;
+extern int rs6000_wchar_type_size;
+
+/* Type used for wchar_t, as a string used in a declaration. */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE rs6000_wchar_type
+
+/* Width of wchar_t in bits. */
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE rs6000_wchar_type_size
+
+/* Tell the preprocessor the maximum size of wchar_t. */
+#undef MAX_WCHAR_TYPE_SIZE
+#define MAX_WCHAR_TYPE_SIZE INT_TYPE_SIZE
+
+/* Tell cccp we'll set up __WCHAR_TYPE__ */
+#undef NO_BUILTIN_WCHAR_TYPE
+#define NO_BUILTIN_WCHAR_TYPE 1
+
+/* CYGNUS LOCAL vmakarov */
+#else
+/* Type used for wchar_t, as a string used in a declaration. */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+/* Width of wchar_t in bits. */
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+#endif
+/* END CYGNUS LOCAL */
+
+/* Make int foo : 8 not cause structures to be aligned to an int boundary */
+
+#undef PCC_BITFIELD_TYPE_MATTERS
+#define PCC_BITFIELD_TYPE_MATTERS (TARGET_BITFIELD_TYPE)
+
+/* CYGNUS LOCAL vmakarov */
+#undef BITFIELD_NBYTES_LIMITED
+#define BITFIELD_NBYTES_LIMITED (TARGET_NO_BITFIELD_WORD)
+/* END CYGNUS LOCAL */
+
+/* Define this macro to be the value 1 if instructions will fail to
+ work if given data not on the nominal alignment. If instructions
+ will merely go slower in that case, define this macro as 0. */
+#undef STRICT_ALIGNMENT
+#define STRICT_ALIGNMENT (TARGET_STRICT_ALIGN)
+
+/* Alignment in bits of the stack boundary. Note, in order to allow building
+ one set of libraries with -mno-eabi instead of eabi libraries and non-eabi
+ versions, just use 64 as the stack boundary. */
+#undef STACK_BOUNDARY
+#define STACK_BOUNDARY 64
+
+/* Real stack boundary as mandated by the appropriate ABI */
+#define ABI_STACK_BOUNDARY ((TARGET_EABI) ? 64 : 128)
+
+/* No data type wants to be aligned rounder than this. */
+#undef BIGGEST_ALIGNMENT
+#define BIGGEST_ALIGNMENT ((TARGET_EABI) ? 64 : 128)
+
+#undef BIGGEST_FIELD_ALIGNMENT
+#undef ADJUST_FIELD_ALIGN
+#undef ROUND_TYPE_ALIGN
+
+/* Use ELF style section commands. */
+
+#undef TEXT_SECTION_ASM_OP
+#define TEXT_SECTION_ASM_OP "\t.section\t\".text\""
+
+#undef DATA_SECTION_ASM_OP
+#define DATA_SECTION_ASM_OP "\t.section\t\".data\""
+
+#undef BSS_SECTION_ASM_OP
+#define BSS_SECTION_ASM_OP "\t.section\t\".bss\""
+
+#undef INIT_SECTION_ASM_OP
+#define INIT_SECTION_ASM_OP "\t.section\t\".init\",\"ax\""
+
+#undef FINI_SECTION_ASM_OP
+#define FINI_SECTION_ASM_OP "\t.section\t\".fini\",\"ax\""
+
+#define TOC_SECTION_ASM_OP "\t.section\t\".got\",\"aw\""
+
+/* Put PC relative got entries in .got2 */
+#define MINIMAL_TOC_SECTION_ASM_OP \
+ ((TARGET_RELOCATABLE || flag_pic) ? "\t.section\t\".got2\",\"aw\"" : "\t.section\t\".got1\",\"aw\"")
+
+/* Put relocatable data in .data, not .rodata so initialized pointers can be updated */
+#undef CONST_SECTION_ASM_OP
+#define CONST_SECTION_ASM_OP \
+ ((TARGET_RELOCATABLE || flag_pic) ? "\t.section\t\".data\"\t# .rodata" : "\t.section\t\".rodata\"")
+
+
+#define SDATA_SECTION_ASM_OP "\t.section\t\".sdata\",\"aw\""
+#define SDATA2_SECTION_ASM_OP "\t.section\t\".sdata2\",\"a\""
+#define SBSS_SECTION_ASM_OP \
+ ((DEFAULT_ABI == ABI_SOLARIS) ? "\t.section\t\".sbss\",\"aw\"" : "\t.section\t\".sbss\",\"aw\",@nobits")
+
+
+/* Besides the usual ELF sections, we need a toc section. */
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_const, in_ctors, in_dtors, in_toc, in_sdata, in_sdata2, in_sbss, in_init, in_fini
+
+#undef EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS \
+ CONST_SECTION_FUNCTION \
+ CTORS_SECTION_FUNCTION \
+ DTORS_SECTION_FUNCTION \
+ TOC_SECTION_FUNCTION \
+ SDATA_SECTION_FUNCTION \
+ SDATA2_SECTION_FUNCTION \
+ SBSS_SECTION_FUNCTION \
+ INIT_SECTION_FUNCTION \
+ FINI_SECTION_FUNCTION
+
+extern void toc_section (), sdata_section (), sdata2_section ();
+extern void sbss_section ();
+
+#define TOC_SECTION_FUNCTION \
+void \
+toc_section () \
+{ \
+ if (in_section != in_toc) \
+ { \
+ in_section = in_toc; \
+ if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT) \
+ && TARGET_MINIMAL_TOC \
+ && !TARGET_RELOCATABLE) \
+ { \
+ if (! toc_initialized) \
+ { \
+ toc_initialized = 1; \
+ fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP); \
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LCTOC", 0); \
+ fprintf (asm_out_file, "\t.tc "); \
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1[TC],"); \
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); \
+ fprintf (asm_out_file, "\n"); \
+ \
+ fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); \
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); \
+ fprintf (asm_out_file, " = .+32768\n"); \
+ } \
+ else \
+ fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); \
+ } \
+ else if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT) \
+ && !TARGET_RELOCATABLE) \
+ fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP); \
+ else \
+ { \
+ fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); \
+ if (! toc_initialized) \
+ { \
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1"); \
+ fprintf (asm_out_file, " = .+32768\n"); \
+ toc_initialized = 1; \
+ } \
+ } \
+ } \
+}
+
+#define SDATA_SECTION_FUNCTION \
+void \
+sdata_section () \
+{ \
+ if (in_section != in_sdata) \
+ { \
+ in_section = in_sdata; \
+ fprintf (asm_out_file, "%s\n", SDATA_SECTION_ASM_OP); \
+ } \
+}
+
+#define SDATA2_SECTION_FUNCTION \
+void \
+sdata2_section () \
+{ \
+ if (in_section != in_sdata2) \
+ { \
+ in_section = in_sdata2; \
+ fprintf (asm_out_file, "%s\n", SDATA2_SECTION_ASM_OP); \
+ } \
+}
+
+#define SBSS_SECTION_FUNCTION \
+void \
+sbss_section () \
+{ \
+ if (in_section != in_sbss) \
+ { \
+ in_section = in_sbss; \
+ fprintf (asm_out_file, "%s\n", SBSS_SECTION_ASM_OP); \
+ } \
+}
+
+#define INIT_SECTION_FUNCTION \
+void \
+init_section () \
+{ \
+ if (in_section != in_init) \
+ { \
+ in_section = in_init; \
+ fprintf (asm_out_file, "%s\n", INIT_SECTION_ASM_OP); \
+ } \
+}
+
+#define FINI_SECTION_FUNCTION \
+void \
+fini_section () \
+{ \
+ if (in_section != in_fini) \
+ { \
+ in_section = in_fini; \
+ fprintf (asm_out_file, "%s\n", FINI_SECTION_ASM_OP); \
+ } \
+}
+
+/* A C statement or statements to switch to the appropriate section
+ for output of RTX in mode MODE. You can assume that RTX is some
+ kind of constant in RTL. The argument MODE is redundant except in
+ the case of a `const_int' rtx. Select the section by calling
+ `text_section' or one of the alternatives for other sections.
+
+ Do not define this macro if you put all constants in the read-only
+ data section. */
+
+extern void rs6000_select_rtx_section (), rs6000_select_section ();
+
+#undef SELECT_RTX_SECTION
+#define SELECT_RTX_SECTION(MODE, X) rs6000_select_rtx_section (MODE, X)
+
+/* A C statement or statements to switch to the appropriate
+ section for output of DECL. DECL is either a `VAR_DECL' node
+ or a constant of some sort. RELOC indicates whether forming
+ the initial value of DECL requires link-time relocations. */
+
+#undef SELECT_SECTION
+#define SELECT_SECTION(DECL,RELOC) rs6000_select_section (DECL, RELOC)
+
+/* Return non-zero if this entry is to be written into the constant pool
+ in a special way. We do so if this is a SYMBOL_REF, LABEL_REF or a CONST
+ containing one of them. If -mfp-in-toc (the default), we also do
+ this for floating-point constants. We actually can only do this
+ if the FP formats of the target and host machines are the same, but
+ we can't check that since not every file that uses
+ GO_IF_LEGITIMATE_ADDRESS_P includes real.h.
+
+ Unlike AIX, we don't key off of -mminimal-toc, but instead do not
+ allow floating point constants in the TOC if -mrelocatable. */
+
+#undef ASM_OUTPUT_SPECIAL_POOL_ENTRY_P
+#define ASM_OUTPUT_SPECIAL_POOL_ENTRY_P(X) \
+ (TARGET_TOC \
+ && (GET_CODE (X) == SYMBOL_REF \
+ || (GET_CODE (X) == CONST && GET_CODE (XEXP (X, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF) \
+ || GET_CODE (X) == LABEL_REF \
+ || (!TARGET_NO_FP_IN_TOC \
+ && !TARGET_RELOCATABLE \
+ && GET_CODE (X) == CONST_DOUBLE \
+ && GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
+ && BITS_PER_WORD == HOST_BITS_PER_INT)))
+
+/* These macros generate the special .type and .size directives which
+ are used to set the corresponding fields of the linker symbol table
+ entries in an ELF object file under SVR4. These macros also output
+ the starting labels for the relevant functions/objects. */
+
+/* Write the extra assembler code needed to declare a function properly.
+ Some svr4 assemblers need to also have something extra said about the
+ function's return value. We allow for that here. */
+
+extern int rs6000_pic_labelno;
+
+/* CYGNUS LOCAL vmakarov */
+#undef USER_LABEL_PREFIX
+/* END CYGNUS LOCAL */
+
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+ do { \
+ char *orig_name; \
+ char *init_ptr = (TARGET_64BIT) ? ".quad" : ".long"; \
+ STRIP_NAME_ENCODING (orig_name, NAME); \
+ \
+ if (TARGET_RELOCATABLE && (get_pool_size () != 0 || profile_flag)) \
+ { \
+ char buf[256], *buf_ptr; \
+ \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, "LCL", rs6000_pic_labelno); \
+ \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1); \
+ STRIP_NAME_ENCODING (buf_ptr, buf); \
+ fprintf (FILE, "\t%s %s-", init_ptr, buf_ptr); \
+ \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno); \
+ fprintf (FILE, "%s\n", buf_ptr); \
+ } \
+ \
+ asm_fprintf (FILE, "\t%s\t %U%s,", TYPE_ASM_OP, orig_name); /* CYGNUS LOCAL vmakarov: asm_fprintf */ \
+ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \
+ putc ('\n', FILE); \
+ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
+ \
+ if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT) \
+ { \
+ char *desc_name = orig_name; \
+ \
+ while (*desc_name == '.') \
+ desc_name++; \
+ \
+ if (TREE_PUBLIC (DECL)) \
+ fprintf (FILE, "\t.globl %s\n", desc_name); \
+ \
+ fprintf (FILE, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); \
+ fprintf (FILE, "%s:\n", desc_name); \
+ fprintf (FILE, "\t%s %s\n", init_ptr, orig_name); \
+ fprintf (FILE, "\t%s _GLOBAL_OFFSET_TABLE_\n", init_ptr); \
+ if (DEFAULT_ABI == ABI_AIX) \
+ fprintf (FILE, "\t%s 0\n", init_ptr); \
+ fprintf (FILE, "\t.previous\n"); \
+ } \
+ asm_fprintf (FILE, "%U%s:\n", orig_name); /* CYGNUS LOCAL vmakarov: asm_fprintf */ \
+ } while (0)
+
+/* How to renumber registers for dbx and gdb. */
+
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+/* CYGNUS LOCAL vmakarov */
+/* If defined, C string expressions to be used for the `%R', `%L',
+ `%U', and `%I' options of `asm_fprintf' (see `final.c'). These
+ are useful when a single `md' file must support multiple assembler
+ formats. In that case, the various `tm.h' files can define these
+ macros differently. */
+
+#ifndef REGISTER_PREFIX
+#define REGISTER_PREFIX ""
+#endif
+
+#ifndef LOCAL_LABEL_PREFIX
+#define LOCAL_LABEL_PREFIX "."
+#endif
+
+#ifndef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
+#endif
+
+#ifndef IMMEDIATE_PREFIX
+#define IMMEDIATE_PREFIX ""
+#endif
+/* END CYGNUS LOCAL */
+
+/* svr4.h overrides ASM_OUTPUT_INTERNAL_LABEL. */
+
+#undef ASM_OUTPUT_INTERNAL_LABEL_PREFIX
+#define ASM_OUTPUT_INTERNAL_LABEL_PREFIX(FILE,PREFIX) \
+ asm_fprintf (FILE, "%L%s", PREFIX) /* CYGNUS LOCAL vmakarov: asm_fprintf */
+
+/* This is how to allocate empty space in some section. Use .space
+ instead of .zero because the Solaris PowerPC assembler doesn't
+ like it, and gas accepts either syntax. */
+
+#undef SKIP_ASM_OP
+#define SKIP_ASM_OP ".space"
+
+/* This says how to output assembler code to declare an
+ uninitialized internal linkage data object. Under SVR4,
+ the linker seems to want the alignment of data objects
+ to depend on their types. We do exactly that here. */
+
+#ifndef LOCAL_ASM_OP
+#define LOCAL_ASM_OP ".local"
+#endif
+
+#ifndef LCOMM_ASM_OP
+#define LCOMM_ASM_OP ".lcomm"
+#endif
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ if (rs6000_sdata != SDATA_NONE && (SIZE) > 0 \
+ && (SIZE) <= g_switch_value) \
+ { \
+ sbss_section (); \
+ ASM_OUTPUT_ALIGN (FILE, exact_log2 (ALIGN / BITS_PER_UNIT)); \
+ ASM_OUTPUT_LABEL (FILE, NAME); \
+ ASM_OUTPUT_SKIP (FILE, SIZE); \
+ if (!flag_inhibit_size_directive && (SIZE) > 0) \
+ { \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ",%d\n", SIZE); \
+ } \
+ } \
+ else \
+ { \
+ fprintf (FILE, "\t%s\t", LCOMM_ASM_OP); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
+ } \
+} while (0)
+
+/* Describe how to emit uninitialized external linkage items */
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+do { \
+ ASM_GLOBALIZE_LABEL (FILE, NAME); \
+ ASM_OUTPUT_ALIGNED_LOCAL (FILE, NAME, SIZE, ALIGN); \
+} while (0)
+
+/* Switch Recognition by gcc.c. Add -G xx support */
+
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
+ || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
+ || (CHAR) == 'I' || (CHAR) == 'm' || (CHAR) == 'x' \
+ || (CHAR) == 'L' || (CHAR) == 'A' || (CHAR) == 'V' \
+ || (CHAR) == 'B' || (CHAR) == 'b' || (CHAR) == 'G')
+
+/* Output .file. */
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+do { \
+ output_file_directive ((FILE), main_input_filename); \
+ rs6000_file_start (FILE, TARGET_CPU_DEFAULT); \
+} while (0)
+
+
+/* This is how to output an assembler line defining an `int' constant.
+ For -mrelocatable, we mark all addresses that need to be fixed up
+ in the .fixup section. */
+#undef ASM_OUTPUT_INT
+#define ASM_OUTPUT_INT(FILE,VALUE) \
+do { \
+ static int recurse = 0; \
+ if ((TARGET_RELOCATABLE || flag_pic) \
+ && in_section != in_toc \
+ && in_section != in_text \
+ && in_section != in_ctors \
+ && in_section != in_dtors \
+ && !recurse \
+ && GET_CODE (VALUE) != CONST_INT \
+ && GET_CODE (VALUE) != CONST_DOUBLE \
+ && CONSTANT_P (VALUE)) \
+ { \
+ static int labelno = 0; \
+ char buf[256], *p; \
+ \
+ recurse = 1; \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", labelno++); \
+ STRIP_NAME_ENCODING (p, buf); \
+ fprintf (FILE, "%s:\n", p); \
+ fprintf (FILE, "\t.long ("); \
+ output_addr_const (FILE, (VALUE)); \
+ fprintf (FILE, ")@fixup\n"); \
+ fprintf (FILE, "\t.section\t\".fixup\",\"aw\"\n"); \
+ ASM_OUTPUT_ALIGN (FILE, 2); \
+ fprintf (FILE, "\t.long\t%s\n", p); \
+ fprintf (FILE, "\t.previous\n"); \
+ recurse = 0; \
+ } \
+ /* Remove initial .'s to turn a -mcall-aixdesc or -mcall-nt function \
+ address into the address of the descriptor, not the function \
+ itself. */ \
+ else if (GET_CODE (VALUE) == SYMBOL_REF \
+ && XSTR (VALUE, 0)[0] == '.' \
+ && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)) \
+ { \
+ char *name = XSTR (VALUE, 0); \
+ while (*name == '.') \
+ name++; \
+ \
+ fprintf (FILE, "\t.long %s\n", name); \
+ } \
+ else \
+ { \
+ fprintf (FILE, "\t.long "); \
+ output_addr_const (FILE, (VALUE)); \
+ fprintf (FILE, "\n"); \
+ } \
+} while (0)
+
+/* This is the end of what might become sysv4.h. */
+
+/* Allow stabs and dwarf, for now, make stabs the default debugging type,
+ not dwarf since G++ doesn't support dwarf. */
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+#define DBX_DEBUGGING_INFO
+#define DWARF_DEBUGGING_INFO
+
+/* If we are referencing a function that is static or is known to be
+ in this file, make the SYMBOL_REF special. We can use this to indicate
+ that we can branch to this function without emitting a no-op after the
+ call. For real AIX and NT calling sequences, we also replace the
+ function name with the real name (1 or 2 leading .'s), rather than
+ the function descriptor name. This saves a lot of overriding code
+ to readd the prefixes. */
+
+#undef ENCODE_SECTION_INFO
+#define ENCODE_SECTION_INFO(DECL) rs6000_encode_section_info (DECL)
+
+extern void rs6000_encode_section_info ();
+
+/* This macro gets just the user-specified name
+ out of the string in a SYMBOL_REF. Discard
+ a leading * or @. */
+#undef STRIP_NAME_ENCODING
+#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \
+do { \
+ char *_name = SYMBOL_NAME; \
+ while (*_name == '*' || *_name == '@') \
+ _name++; \
+ (VAR) = _name; \
+} while (0)
+
+/* This is how to output a reference to a user-level label named NAME.
+ `assemble_name' uses this. */
+
+#undef ASM_OUTPUT_LABELREF
+#define ASM_OUTPUT_LABELREF(FILE,NAME) \
+do { \
+ char *_name = NAME; \
+ while (*_name == '*' || *_name == '@') \
+ _name++; \
+ asm_fprintf (FILE, "%U%s", _name); /* CYGNUS LOCAL vmakarov: asm_fprintf */ \
+} while (0)
+
+/*
+ * Switch into a generic section.
+ *
+ * We make the section read-only and executable for a function decl,
+ * read-only for a const data decl, and writable for a non-const data decl.
+ *
+ * If the section has already been defined, we must not
+ * emit the attributes here. The SVR4 assembler does not
+ * recognize section redefinitions.
+ * If DECL is NULL, no attributes are emitted.
+ *
+ * Note, Solaris as doesn't like @nobits, and gas can handle .sbss without
+ * needing @nobits.
+ */
+
+#undef ASM_OUTPUT_SECTION_NAME
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
+do { \
+ static struct section_info \
+ { \
+ struct section_info *next; \
+ char *name; \
+ enum sect_enum {SECT_RW, SECT_RO, SECT_EXEC} type; \
+ } *sections; \
+ struct section_info *s; \
+ char *mode; \
+ enum sect_enum type; \
+ \
+ for (s = sections; s; s = s->next) \
+ if (!strcmp (NAME, s->name)) \
+ break; \
+ \
+ if (DECL && TREE_CODE (DECL) == FUNCTION_DECL) \
+ type = SECT_EXEC, mode = "ax"; \
+ else if (DECL && DECL_READONLY_SECTION (DECL, RELOC) && !TARGET_RELOCATABLE && !flag_pic) \
+ type = SECT_RO, mode = "a"; \
+ else \
+ type = SECT_RW, mode = "aw"; \
+ \
+ if (s == 0) \
+ { \
+ s = (struct section_info *) xmalloc (sizeof (struct section_info)); \
+ s->name = xmalloc ((strlen (NAME) + 1) * sizeof (*NAME)); \
+ strcpy (s->name, NAME); \
+ s->type = type; \
+ s->next = sections; \
+ sections = s; \
+ fprintf (FILE, "\t.section\t\"%s\",\"%s\"\n", NAME, mode); \
+ } \
+ else \
+ { \
+ if (DECL && s->type != type) \
+ error_with_decl (DECL, "%s causes a section type conflict"); \
+ \
+ fprintf (FILE, "\t.section\t\"%s\"\n", NAME); \
+ } \
+} while (0)
+
+#undef ASM_OUTPUT_CONSTRUCTOR
+#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
+ do { \
+ if (DEFAULT_ABI != ABI_SOLARIS) \
+ { \
+ ctors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ } \
+ else \
+ { \
+ init_section (); \
+ fputs ("\tbl ", FILE); \
+ assemble_name (FILE, NAME); \
+ } \
+ fputs ("\n", FILE); \
+ } while (0)
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global destructors. */
+#undef ASM_OUTPUT_DESTRUCTOR
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
+ do { \
+ if (DEFAULT_ABI != ABI_SOLARIS) \
+ { \
+ dtors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ } \
+ else \
+ { \
+ fini_section (); \
+ fputs ("\tbl ", FILE); \
+ assemble_name (FILE, NAME); \
+ } \
+ fputs ("\n", FILE); \
+ } while (0)
+
+/* But, to make this work, we have to output the stabs for the function
+ name *first*... */
+
+#define DBX_FUNCTION_FIRST
+
+/* This is the end of what might become sysv4dbx.h. */
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (PowerPC System V.4)");
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-DPPC -Dunix -D__svr4__ -Asystem(unix) -Asystem(svr4) -Acpu(powerpc) -Amachine(powerpc)"
+
+/* Pass various options to the assembler */
+#undef ASM_SPEC
+#define ASM_SPEC "%(asm_cpu) \
+%{.s: %{mregnames} %{mno-regnames}} %{.S: %{mregnames} %{mno-regnames}} \
+%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} \
+%{mrelocatable} %{mrelocatable-lib} %{fpic:-K PIC} %{fPIC:-K PIC} \
+%{memb} %{!memb: %{msdata: -memb} %{msdata=eabi: -memb}} \
+%{mlittle} %{mlittle-endian} %{mbig} %{mbig-endian} \
+%{!mlittle: %{!mlittle-endian: %{!mbig: %{!mbig-endian: \
+ %{mcall-solaris: -mlittle -msolaris} \
+ %{cygnus-local-vmakarov: } \
+ %{mcall-i960-old: -mlittle} \
+ %{end-cygnus-local: } \
+ %{mcall-linux: -mbig} }}}}"
+
+#ifndef CC1_ENDIAN_BIG_SPEC
+#define CC1_ENDIAN_BIG_SPEC ""
+#endif
+
+#ifndef CC1_ENDIAN_LITTLE_SPEC
+#define CC1_ENDIAN_LITTLE_SPEC "\
+%{!mstrict-align: %{!mno-strict-align: \
+ %{cygnus-local-vmakarov: } \
+ %{!mcall-i960-old: \
+ %{end-cygnus-local: } \
+ -mstrict-align \
+ %{cygnus-local-vmakarov: } \
+ } \
+ %{end-cygnus-local: } \
+}}"
+#endif
+
+#ifndef CC1_ENDIAN_DEFAULT_SPEC
+#define CC1_ENDIAN_DEFAULT_SPEC "%(cc1_endian_big_spec)"
+#endif
+
+#undef CC1_SPEC
+/* Pass -G xxx to the compiler and set correct endian mode */
+#define CC1_SPEC "%{G*} \
+%{mlittle: %(cc1_endian_little)} %{!mlittle: %{mlittle-endian: %(cc1_endian_little)}} \
+%{mbig: %(cc1_endian_big)} %{!mbig: %{mbig-endian: %(cc1_endian_big)}} \
+%{!mlittle: %{!mlittle-endian: %{!mbig: %{!mbig-endian: \
+ %{mcall-nt: -mlittle %(cc1_endian_little) } \
+ %{mcall-aixdesc: -mbig %(cc1_endian_big) } \
+ %{mcall-solaris: -mlittle %(cc1_endian_little) } \
+ %{cygnus-local-vmakarov: } \
+ %{mcall-i960-old: -mlittle %(cc1_endian_little) } \
+ %{end-cygnus-local: } \
+ %{mcall-linux: -mbig %(cc1_endian_big) }} \
+ %{!mcall-nt: %{!mcall-aixdesc: %{!mcall-solaris: %{!mcall-linux: \
+ %{cygnus-local-vmakarov: } \
+ %{!mcall-i960-old: \
+ %{end-cygnus-local: } \
+ %(cc1_endian_default) \
+ %{cygnus-local-vmakarov: } \
+ } \
+ %{end-cygnus-local: } \
+ }}}} \
+}}} \
+%{mcall-solaris: -mregnames } \
+%{mno-sdata: -msdata=none } \
+%{meabi: %{!mcall-*: -mcall-sysv }} \
+%{!meabi: %{!mno-eabi: \
+ %{mrelocatable: -meabi } \
+ %{mcall-solaris: -mno-eabi } \
+ %{cygnus-local-vmakarov: } \
+ %{mcall-i960-old: -meabi } \
+ %{end-cygnus-local: } \
+ %{mcall-linux: -mno-eabi }}} \
+%{msdata: -msdata=default} \
+%{mno-sdata: -msdata=none}"
+
+/* Don't put -Y P,<path> for cross compilers */
+#undef LINK_PATH_SPEC
+#ifndef CROSS_COMPILE
+#define LINK_PATH_SPEC "\
+%{!R*:%{L*:-R %*}} \
+%{!nostdlib: %{!YP,*: \
+ %{compat-bsd: \
+ %{p:-Y P,/usr/ucblib:/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{!p:-Y P,/usr/ucblib:/usr/ccs/lib:/usr/lib}} \
+ %{!R*: %{!L*: -R /usr/ucblib}} \
+ %{!compat-bsd: \
+ %{p:-Y P,/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{!p:-Y P,/usr/ccs/lib:/usr/lib}}}}"
+
+#else
+#define LINK_PATH_SPEC ""
+#endif
+
+/* Default starting address if specified */
+#ifndef LINK_START_SPEC
+#define LINK_START_SPEC "\
+%{mads: %(link_start_ads) } \
+%{myellowknife: %(link_start_yellowknife) } \
+%{mmvme: %(link_start_mvme) } \
+%{msim: %(link_start_sim) } \
+%{mcall-linux: %(link_start_linux) } \
+%{mcall-solaris: %(link_start_solaris) } \
+%{cygnus-local-vmakarov: } \
+%{mvxworks: %(link_start_vxworks) } \
+%{end-cygnus-local: } \
+%{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mcall-linux: %{!mcall-solaris:\
+%{cygnus-local-vmakarov: } \
+ %{!mvxworks: \
+%{end-cygnus-local: } \
+ %(link_start_default) \
+%{cygnus-local-vmakarov: } \
+ } \
+%{end-cygnus-local: } \
+}}}}}}"
+#endif
+
+#ifndef LINK_START_DEFAULT_SPEC
+#define LINK_START_DEFAULT_SPEC ""
+#endif
+
+#undef LINK_SPEC
+/* CYGNUS LOCAL jlemke (mpc860) */
+#define LINK_SPEC "\
+%{h*} %{v:-V} %{G*} \
+%{Wl,*:%*} %{YP,*} %{R*} \
+%{Qy:} %{!Qn:-Qy} \
+%(link_shlib) \
+%{!Ttext*: %(link_start) } \
+%(link_target) \
+%{mmpc860c0*:--mpc860c0%*} \
+%(link_os)"
+/* END CYGNUS LOCAL */
+
+/* For now, turn off shared libraries by default. */
+#ifndef SHARED_LIB_SUPPORT
+#define NO_SHARED_LIB_SUPPORT
+#endif
+
+#undef LINK_SHLIB_SPEC
+#ifndef NO_SHARED_LIB_SUPPORT
+/* Shared libraries are default. */
+#define LINK_SHLIB_SPEC "\
+%{!static: %(link_path) %{!R*:%{L*:-R %*}}} \
+%{mshlib: } \
+%{static:-dn -Bstatic} \
+%{shared:-G -dy -z text} \
+%{symbolic:-Bsymbolic -G -dy -z text}"
+
+#else
+/* Shared libraries are not default. */
+#define LINK_SHLIB_SPEC "\
+%{mshlib: %(link_path) } \
+%{!mshlib: %{!shared: %{!symbolic: -dn -Bstatic}}} \
+%{static: } \
+%{shared:-G -dy -z text %(link_path) } \
+%{symbolic:-Bsymbolic -G -dy -z text %(link_path) }"
+#endif
+
+/* Override the default target of the linker. */
+#undef LINK_TARGET_SPEC
+#define LINK_TARGET_SPEC "\
+%{mlittle: -oformat elf32-powerpcle } %{mlittle-endian: -oformat elf32-powerpcle } \
+%{!mlittle: %{!mlittle-endian: %{!mbig: %{!mbig-endian: \
+ %{cygnus-local-vmakarov: } \
+ %{mcall-i960-old: -oformat elf32-powerpcle} \
+ %{end-cygnus-local: } \
+ %{mcall-solaris: -oformat elf32-powerpcle} \
+ %{mcall-linux: -oformat elf32-powerpc}}}}}"
+
+/* Any specific OS flags */
+#ifndef LINK_OS_SPEC
+#define LINK_OS_SPEC "\
+%{mads: %(link_os_ads) } \
+%{myellowknife: %(link_os_yellowknife) } \
+%{mmvme: %(link_os_mvme) } \
+%{msim: %(link_os_sim) } \
+%{mcall-linux: %(link_os_linux) } \
+%{mcall-solaris: %(link_os_solaris) } \
+%{cygnus-local-vmakarov: } \
+%{mvxworks: %(link_os_vxworks) } \
+%{end-cygnus-local: } \
+%{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mcall-linux: %{!mcall-solaris:\
+%{cygnus-local-vmakarov: } \
+ %{!mvxworks: \
+%{end-cygnus-local: } \
+ %(link_os_default) \
+%{cygnus-local-vmakarov: } \
+ } \
+%{end-cygnus-local: } \
+}}}}}}"
+#endif
+
+#ifndef LINK_OS_DEFAULT_SPEC
+#define LINK_OS_DEFAULT_SPEC ""
+#endif
+
+#undef CPP_SYSV_SPEC
+#define CPP_SYSV_SPEC \
+"%{mrelocatable*: -D_RELOCATABLE} \
+%{fpic: -D__PIC__=1 -D__pic__=1} \
+%{fPIC: -D__PIC__=2 -D__pic__=2} \
+%{mcall-sysv: -D_CALL_SYSV} %{mcall-nt: -D_CALL_NT} \
+%{mcall-aix: -D_CALL_AIX} %{mcall-aixdesc: -D_CALL_AIX -D_CALL_AIXDESC} \
+%{!mcall-sysv: %{!mcall-aix: %{!mcall-aixdesc: %{!mcall-nt: %(cpp_sysv_default) }}}} \
+%{msoft-float: -D_SOFT_FLOAT} \
+%{cygnus-local-vmakarov: } \
+%{!msoft-float: %{!mhard-float: \
+ %{mcpu=401: -D_SOFT_FLOAT} \
+ %{mcpu=403: -D_SOFT_FLOAT} \
+ %{mcpu=ec603e: -D_SOFT_FLOAT} \
+ %{mcpu=801: -D_SOFT_FLOAT} \
+ %{mcpu=821: -D_SOFT_FLOAT} \
+ %{mcpu=823: -D_SOFT_FLOAT} \
+ %{mcpu=860: -D_SOFT_FLOAT} \
+ %{!mcpu*: %(cpp_float_default) }}} \
+%{end-cygnus-local: }"
+
+/* CYGNUS LOCAL vmakarov */
+/* Whether floating point is disabled by default */
+#undef CPP_FLOAT_DEFAULT_SPEC
+#define CPP_FLOAT_DEFAULT_SPEC ""
+
+/* For solaris, don't define _LITTLE_ENDIAN, it conflicts with a
+ header file. For VxWorks, don't define either _{BIG,LITTLE}_ENDIAN
+ for the same reason. */
+/* END CYGNUS LOCAL */
+#undef CPP_SYSV_DEFAULT_SPEC
+#define CPP_SYSV_DEFAULT_SPEC "-D_CALL_SYSV"
+
+#ifndef CPP_ENDIAN_BIG_SPEC
+#define CPP_ENDIAN_BIG_SPEC "\
+%{cygnus-local-vmakarov: } \
+%{!mcall-solaris: %{!mvxworks: -D_BIG_ENDIAN }} \
+%{end-cygnus-local: } \
+-D__BIG_ENDIAN__ -Amachine(bigendian)"
+#endif
+
+#ifndef CPP_ENDIAN_LITTLE_SPEC
+#define CPP_ENDIAN_LITTLE_SPEC "\
+%{cygnus-local-vmakarov: } \
+%{!mcall-solaris: %{!mvxworks: -D_LITTLE_ENDIAN }} \
+%{end-cygnus-local: } \
+-D__LITTLE_ENDIAN__ -Amachine(littleendian)"
+#endif
+
+/* CYGNUS LOCAL vmakarov */
+#if 0
+/* END CYGNUS LOCAL */
+#ifndef CPP_ENDIAN_SOLARIS_SPEC
+#define CPP_ENDIAN_SOLARIS_SPEC "-D__LITTLE_ENDIAN__ -Amachine(littleendian)"
+#endif
+/* For solaris, don't define _LITTLE_ENDIAN, it conflicts with a header file. */
+/* CYGNUS LOCAL vmakarov */
+#endif
+/* END CYGNUS LOCAL */
+
+#undef CPP_ENDIAN_SPEC
+#define CPP_ENDIAN_SPEC \
+"%{mlittle: %(cpp_endian_little) } \
+%{mlittle-endian: %(cpp_endian_little) } \
+%{mbig: %(cpp_endian_big) } \
+%{mbig-endian: %(cpp_endian_big) } \
+%{!mlittle: %{!mlittle-endian: %{!mbig: %{!mbig-endian: \
+ %{mcall-solaris: %(cpp_endian_little) } %{cygnus-local-cpp-endian-little: }\
+ %{mcall-nt: %(cpp_endian_little) } \
+ %{cygnus-local-vmakarov: } \
+ %{mcall-i960-old: %(cpp_endian_little) } \
+ %{end-cygnus-local: } \
+ %{mcall-linux: %(cpp_endian_big) } \
+ %{mcall-aixdesc: %(cpp_endian_big) } \
+ %{!mcall-solaris: %{!mcall-linux: %{!mcall-nt: %{!mcall-aixdesc: %(cpp_endian_default) }}}}}}}}"
+
+#undef CPP_ENDIAN_DEFAULT_SPEC
+#define CPP_ENDIAN_DEFAULT_SPEC "%(cpp_endian_big)"
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{posix: -D_POSIX_SOURCE} %{msoft-float: -D_SOFT_FLOAT} \
+%(cpp_sysv) %(cpp_endian) %(cpp_cpu) \
+%{mads: %(cpp_os_ads) } \
+%{myellowknife: %(cpp_os_yellowknife) } \
+%{mmvme: %(cpp_os_mvme) } \
+%{msim: %(cpp_os_sim) } \
+%{mcall-linux: %(cpp_os_linux) } \
+%{mcall-solaris: %(cpp_os_solaris) } \
+%{cygnus-local-vmakarov: } \
+%{mvxworks: %(cpp_os_vxworks) } \
+%{end-cygnus-local: } \
+%{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mcall-linux: %{!mcall-solaris:\
+%{cygnus-local-vmakarov: } \
+%{!mvxworks: \
+%{end-cygnus-local: } \
+ %(cpp_os_default) \
+ } \
+%{end-cygnus-local: } \
+}}}}}}"
+
+#ifndef CPP_OS_DEFAULT_SPEC
+#define CPP_OS_DEFAULT_SPEC ""
+#endif
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "\
+%{mads: %(startfile_ads) } \
+%{myellowknife: %(startfile_yellowknife) } \
+%{mmvme: %(startfile_mvme) } \
+%{msim: %(startfile_sim) } \
+%{mcall-linux: %(startfile_linux) } \
+%{mcall-solaris: %(startfile_solaris) } \
+%{cygnus-local-vmakarov: } \
+%{mvxworks: %(startfile_vxworks) } \
+%{end-cygnus-local: } \
+%{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mcall-linux: %{!mcall-solaris:\
+%{cygnus-local-vmakarov: } \
+%{!mvxworks: \
+%{end-cygnus-local: } \
+ %(startfile_default) \
+%{cygnus-local-vmakarov: } \
+ } \
+%{end-cygnus-local: } \
+}}}}}}"
+
+#undef STARTFILE_DEFAULT_SPEC
+#define STARTFILE_DEFAULT_SPEC ""
+
+#undef LIB_SPEC
+#define LIB_SPEC "\
+%{mads: %(lib_ads) } \
+%{myellowknife: %(lib_yellowknife) } \
+%{mmvme: %(lib_mvme) } \
+%{msim: %(lib_sim) } \
+%{mcall-linux: %(lib_linux) } \
+%{mcall-solaris: %(lib_solaris) } \
+%{cygnus-local-vmakarov: } \
+%{mvxworks: %(lib_vxworks) } \
+%{end-cygnus-local: } \
+%{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mcall-linux: %{!mcall-solaris:\
+%{cygnus-local-vmakarov: } \
+%{!mvxworks: \
+%{end-cygnus-local: } \
+ %(lib_default) \
+%{cygnus-local-vmakarov: } \
+ }\
+%{end-cygnus-local: } \
+}}}}}}"
+
+#undef LIBGCC_SPEC
+#define LIBGCC_SPEC "libgcc.a%s"
+
+#ifndef LIB_DEFAULT_SPEC
+#define LIB_DEFAULT_SPEC ""
+#endif
+
+#undef ENDFILE_SPEC
+
+/* CYGNUS LOCAL vmakarov */
+#if 0
+/* END CYGNUS LOCAL */
+#define ENDFILE_SPEC "\
+%{mads: ecrtn.o%s} \
+%{myellowknife: ecrtn.o%s} \
+%{mmvme: ecrtn.o%s} \
+%{msim: ecrtn.o%s} \
+%{mcall-linux: %(endfile_linux) } \
+%{mcall-solaris: scrtn.o%s} \
+%{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mcall-linux: %{!mcall-solaris: %(endfile_default) }}}}}}"
+
+/* CYGNUS LOCAL vmakarov */
+#endif
+
+#define ENDFILE_SPEC "\
+%{mads: %(endfile_ads) } \
+%{myellowknife: %(endfile_yellowknife) } \
+%{mmvme: %(endfile_mvme) } \
+%{msim: %(endfile_sim) } \
+%{mcall-linux: %(endfile_linux) } \
+%{mcall-solaris: %(endfile_solarils) } \
+%{mvxworks: %(endfile_vxworks) } \
+%{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mcall-linux: %{!mcall-solaris: %{!mvxworks: %(endfile_default) }}}}}}}"
+/* END CYGNUS LOCAL */
+
+#undef ENDFILE_DEFAULT_SPEC
+#define ENDFILE_DEFAULT_SPEC ""
+
+/* Motorola ADS support. */
+#ifndef LIB_ADS_SPEC
+#define LIB_ADS_SPEC "--start-group -lads -lc --end-group"
+#endif
+
+#ifndef STARTFILE_ADS_SPEC
+#define STARTFILE_ADS_SPEC "ecrti.o%s crt0.o%s"
+#endif
+
+#ifndef ENDFILE_ADS_SPEC
+#define ENDFILE_ADS_SPEC "ecrtn.o%s"
+#endif
+
+#ifndef LINK_START_ADS_SPEC
+#define LINK_START_ADS_SPEC "-T ads.ld%s"
+#endif
+
+#ifndef LINK_OS_ADS_SPEC
+#define LINK_OS_ADS_SPEC ""
+#endif
+
+#ifndef CPP_OS_ADS_SPEC
+#define CPP_OS_ADS_SPEC ""
+#endif
+
+/* Motorola Yellowknife support. */
+#ifndef LIB_YELLOWKNIFE_SPEC
+#define LIB_YELLOWKNIFE_SPEC "--start-group -lyk -lc --end-group"
+#endif
+
+#ifndef STARTFILE_YELLOWKNIFE_SPEC
+#define STARTFILE_YELLOWKNIFE_SPEC "ecrti.o%s crt0.o%s"
+#endif
+
+#ifndef ENDFILE_YELLOWKNIFE_SPEC
+#define ENDFILE_YELLOWKNIFE_SPEC "ecrtn.o%s"
+#endif
+
+#ifndef LINK_START_YELLOWKNIFE_SPEC
+#define LINK_START_YELLOWKNIFE_SPEC "-T yellowknife.ld%s"
+#endif
+
+#ifndef LINK_OS_YELLOWKNIFE_SPEC
+#define LINK_OS_YELLOWKNIFE_SPEC ""
+#endif
+
+#ifndef CPP_OS_YELLOWKNIFE_SPEC
+#define CPP_OS_YELLOWKNIFE_SPEC ""
+#endif
+
+/* Motorola MVME support. */
+#ifndef LIB_MVME_SPEC
+#define LIB_MVME_SPEC "--start-group -lmvme -lc --end-group"
+#endif
+
+#ifndef STARTFILE_MVME_SPEC
+#define STARTFILE_MVME_SPEC "ecrti.o%s crt0.o%s"
+#endif
+
+#ifndef ENDFILE_MVME_SPEC
+#define ENDFILE_MVME_SPEC "ecrtn.o%s"
+#endif
+
+#ifndef LINK_START_MVME_SPEC
+#define LINK_START_MVME_SPEC "%{!Wl,-T*: %{!T*: -Ttext 0x40000}}"
+#endif
+
+#ifndef LINK_OS_MVME_SPEC
+#define LINK_OS_MVME_SPEC ""
+#endif
+
+#ifndef CPP_OS_MVME_SPEC
+#define CPP_OS_MVME_SPEC ""
+#endif
+
+/* PowerPC simulator based on netbsd system calls support. */
+#ifndef LIB_SIM_SPEC
+#define LIB_SIM_SPEC "--start-group -lsim -lc --end-group"
+#endif
+
+#ifndef STARTFILE_SIM_SPEC
+#define STARTFILE_SIM_SPEC "ecrti.o%s sim-crt0.o%s"
+#endif
+
+#ifndef ENDFILE_SIM_SPEC
+#define ENDFILE_SIM_SPEC "ecrtn.o%s"
+#endif
+
+#ifndef LINK_START_SIM_SPEC
+#define LINK_START_SIM_SPEC "-Ttext 0x10000074"
+#endif
+
+#ifndef LINK_OS_SIM_SPEC
+#define LINK_OS_SIM_SPEC ""
+#endif
+
+#ifndef CPP_OS_SIM_SPEC
+#define CPP_OS_SIM_SPEC ""
+#endif
+
+/* GNU/Linux support. */
+#ifndef LIB_LINUX_SPEC
+#define LIB_LINUX_SPEC "%{mnewlib: --start-group -llinux -lc --end-group } %{!mnewlib: -lc }"
+#endif
+
+#ifndef STARTFILE_LINUX_SPEC
+#define STARTFILE_LINUX_SPEC "\
+%{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}} \
+%{mnewlib: ecrti.o%s} \
+%{!mnewlib: crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}}"
+#endif
+
+#ifndef ENDFILE_LINUX_SPEC
+#define ENDFILE_LINUX_SPEC "\
+%{mnewlib: ecrtn.o%s} \
+%{!mnewlib: %{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s}"
+#endif
+
+#ifndef LINK_START_LINUX_SPEC
+#define LINK_START_LINUX_SPEC "-Ttext 0x400074"
+#endif
+
+#ifndef LINK_OS_LINUX_SPEC
+#define LINK_OS_LINUX_SPEC ""
+#endif
+
+#ifndef CPP_OS_LINUX_SPEC
+#define CPP_OS_LINUX_SPEC "-D__unix__ -D__linux__ \
+%{!ansi: -Dunix -Dlinux } \
+-Asystem(unix) -Asystem(linux)"
+#endif
+
+#ifndef CPP_OS_LINUX_SPEC
+#define CPP_OS_LINUX_SPEC ""
+#endif
+
+/* Solaris support. */
+/* For Solaris, Gcc automatically adds in one of the files
+ /usr/ccs/lib/values-Xc.o, /usr/ccs/lib/values-Xa.o, or
+ /usr/ccs/lib/values-Xt.o for each final link step (depending upon the other
+ gcc options selected, such as -traditional and -ansi). These files each
+ contain one (initialized) copy of a special variable called `_lib_version'.
+ Each one of these files has `_lib_version' initialized to a different (enum)
+ value. The SVR4 library routines query the value of `_lib_version' at run
+ to decide how they should behave. Specifically, they decide (based upon the
+ value of `_lib_version') if they will act in a strictly ANSI conforming
+ manner or not. */
+
+#ifndef LIB_SOLARIS_SPEC
+#define LIB_SOLARIS_SPEC "\
+%{mnewlib: --start-group -lsolaris -lc --end-group } \
+%{!mnewlib: \
+ %{ansi:values-Xc.o%s} \
+ %{!ansi: \
+ %{traditional:values-Xt.o%s} \
+ %{!traditional:values-Xa.o%s}} \
+ %{compat-bsd:-lucb -lsocket -lnsl -lelf -laio} \
+ %{solaris-cclib: /opt/SUNWspro/SC4.0/lib/libabi.a} \
+ %{!shared: %{!symbolic: -lc }}}"
+#endif
+
+#ifndef STARTFILE_SOLARIS_SPEC
+#define STARTFILE_SOLARIS_SPEC "\
+%{!msolaris-cclib: scrti.o%s scrt0.o%s} \
+%{msolaris-cclib: /opt/SUNWspro/SC4.0/lib/crti.o%s /opt/SUNWspro/SC4.0/lib/crt1.o%s}"
+#endif
+
+#ifndef ENDFILE_SOLARIS_SPEC
+#define ENDFILE_SOLARIS_SPEC "\
+%{!msolaris-cclib: scrtn.o%s} \
+%{msolaris-cclib: /opt/SUNWspro/SC4.0/lib/crtn.o%s}"
+#endif
+
+#ifndef LINK_START_SOLARIS_SPEC
+#ifdef CROSS_COMPILER
+#define LINK_START_SOLARIS_SPEC "-Ttext 0x2000074"
+#else
+#define LINK_START_SOLARIS_SPEC ""
+#endif
+#endif
+
+#ifndef LINK_OS_SOLARIS_SPEC
+#define LINK_OS_SOLARIS_SPEC ""
+#endif
+
+#ifndef CPP_OS_SOLARIS_SPEC
+#define CPP_OS_SOLARIS_SPEC "-D__ppc -D__sun__=1 -D__unix__ -D__svr4__ -D__SVR4__ \
+%{!ansi: -Dsun=1 -Dunix -DSVR4 -D__EXTENSIONS__ } \
+-Amachine(prep)"
+#endif
+
+/* CYGNUS LOCAL vmakarov */
+/* VxWorks support. */
+/* VxWorks does all the library stuff itself. */
+#ifndef LIB_VXWORKS_SPEC
+#define LIB_VXWORKS_SPEC ""
+#endif
+
+/* Because it uses ld -r, vxworks has no start/end files, nor starting address. */
+#ifndef STARTFILE_VXWORKS_SPEC
+#define STARTFILE_VXWORKS_SPEC ""
+#endif
+
+#ifndef ENDFILE_VXWORKS_SPEC
+#define ENDFILE_VXWORKS_SPEC ""
+#endif
+
+#ifndef LINK_START_VXWORKS_SPEC
+#define LINK_START_VXWORKS_SPEC ""
+#endif
+
+#ifndef LINK_OS_VXWORKS_SPEC
+#define LINK_OS_VXWORKS_SPEC "-r"
+#endif
+
+#ifndef CPP_OS_VXWORKS_SPEC
+#define CPP_OS_VXWORKS_SPEC "\
+-DCPU_FAMILY=PPC \
+%{!mcpu*: \
+ %{mpowerpc*: -DCPU=PPC603} \
+ %{!mno-powerpc: -DCPU=PPC603}} \
+%{mcpu=powerpc: -DCPU=PPC603} \
+%{mcpu=401: -DCPU=PPC403} \
+%{mcpu=403: -DCPU=PPC403} \
+%{mcpu=601: -DCPU=PPC601} \
+%{mcpu=602: -DCPU=PPC603} \
+%{mcpu=603: -DCPU=PPC603} \
+%{mcpu=603e: -DCPU=PPC603} \
+%{mcpu=ec603e: -DCPU=PPC603} \
+%{mcpu=604: -DCPU=PPC604} \
+%{mcpu=604e: -DCPU=PPC604} \
+%{mcpu=620: -DCPU=PPC604} \
+%{mcpu=801: -DCPU=PPC603} \
+%{mcpu=821: -DCPU=PPC603} \
+%{mcpu=823: -DCPU=PPC603} \
+%{mcpu=860: -DCPU=PPC603}"
+
+#endif
+/* END CYGNUS LOCAL */
+
+/* Define any extra SPECS that the compiler needs to generate. */
+#undef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS \
+ { "lib_ads", LIB_ADS_SPEC }, \
+ { "lib_yellowknife", LIB_YELLOWKNIFE_SPEC }, \
+ { "lib_mvme", LIB_MVME_SPEC }, \
+ { "lib_sim", LIB_SIM_SPEC }, \
+ { "lib_linux", LIB_LINUX_SPEC }, \
+ { "lib_solaris", LIB_SOLARIS_SPEC }, \
+/* CYGNUS LOCAL vmakarov */ \
+ { "lib_vxworks", LIB_VXWORKS_SPEC }, \
+/* END CYGNUS LOCAL */ \
+ { "lib_default", LIB_DEFAULT_SPEC }, \
+ { "startfile_ads", STARTFILE_ADS_SPEC }, \
+ { "startfile_yellowknife", STARTFILE_YELLOWKNIFE_SPEC }, \
+ { "startfile_mvme", STARTFILE_MVME_SPEC }, \
+ { "startfile_sim", STARTFILE_SIM_SPEC }, \
+ { "startfile_linux", STARTFILE_LINUX_SPEC }, \
+ { "startfile_solaris", STARTFILE_SOLARIS_SPEC }, \
+/* CYGNUS LOCAL vmakarov */ \
+ { "startfile_vxworks", STARTFILE_VXWORKS_SPEC }, \
+/* END CYGNUS LOCAL */ \
+ { "startfile_default", STARTFILE_DEFAULT_SPEC }, \
+ { "endfile_ads", ENDFILE_ADS_SPEC }, \
+ { "endfile_yellowknife", ENDFILE_YELLOWKNIFE_SPEC }, \
+ { "endfile_mvme", ENDFILE_MVME_SPEC }, \
+ { "endfile_sim", ENDFILE_SIM_SPEC }, \
+ { "endfile_linux", ENDFILE_LINUX_SPEC }, \
+ { "endfile_solaris", ENDFILE_SOLARIS_SPEC }, \
+/* CYGNUS LOCAL vmakarov */ \
+ { "endfile_vxworks", ENDFILE_VXWORKS_SPEC }, \
+/* END CYGNUS LOCAL */ \
+ { "endfile_default", ENDFILE_DEFAULT_SPEC }, \
+ { "link_path", LINK_PATH_SPEC }, \
+ { "link_shlib", LINK_SHLIB_SPEC }, \
+ { "link_target", LINK_TARGET_SPEC }, \
+ { "link_start", LINK_START_SPEC }, \
+ { "link_start_ads", LINK_START_ADS_SPEC }, \
+ { "link_start_yellowknife", LINK_START_YELLOWKNIFE_SPEC }, \
+ { "link_start_mvme", LINK_START_MVME_SPEC }, \
+ { "link_start_sim", LINK_START_SIM_SPEC }, \
+ { "link_start_linux", LINK_START_LINUX_SPEC }, \
+ { "link_start_solaris", LINK_START_SOLARIS_SPEC }, \
+/* CYGNUS LOCAL vmakarov */ \
+ { "link_start_vxworks", LINK_START_VXWORKS_SPEC }, \
+/* END CYGNUS LOCAL */ \
+ { "link_start_default", LINK_START_DEFAULT_SPEC }, \
+ { "link_os", LINK_OS_SPEC }, \
+ { "link_os_ads", LINK_OS_ADS_SPEC }, \
+ { "link_os_yellowknife", LINK_OS_YELLOWKNIFE_SPEC }, \
+ { "link_os_mvme", LINK_OS_MVME_SPEC }, \
+ { "link_os_sim", LINK_OS_SIM_SPEC }, \
+ { "link_os_linux", LINK_OS_LINUX_SPEC }, \
+ { "link_os_solaris", LINK_OS_SOLARIS_SPEC }, \
+/* CYGNUS LOCAL vmakarov */ \
+ { "link_os_vxworks", LINK_OS_VXWORKS_SPEC }, \
+/* END CYGNUS LOCAL */ \
+ { "link_os_default", LINK_OS_DEFAULT_SPEC }, \
+ { "cc1_endian_big", CC1_ENDIAN_BIG_SPEC }, \
+ { "cc1_endian_little", CC1_ENDIAN_LITTLE_SPEC }, \
+ { "cc1_endian_default", CC1_ENDIAN_DEFAULT_SPEC }, \
+ { "cpp_endian_big", CPP_ENDIAN_BIG_SPEC }, \
+ { "cpp_endian_little", CPP_ENDIAN_LITTLE_SPEC }, \
+/* CYGNUS LOCAL vmakarov */ \
+ { "cpp_endian_default", CPP_ENDIAN_DEFAULT_SPEC }, \
+ { "cpp_float_default", CPP_FLOAT_DEFAULT_SPEC }, \
+/* END CYGNUS LOCAL */ \
+ { "cpp_os_ads", CPP_OS_ADS_SPEC }, \
+ { "cpp_os_yellowknife", CPP_OS_YELLOWKNIFE_SPEC }, \
+ { "cpp_os_mvme", CPP_OS_MVME_SPEC }, \
+ { "cpp_os_sim", CPP_OS_SIM_SPEC }, \
+ { "cpp_os_linux", CPP_OS_LINUX_SPEC }, \
+ { "cpp_os_solaris", CPP_OS_SOLARIS_SPEC }, \
+/* CYGNUS LOCAL vmakarov */ \
+ { "cpp_os_vxworks", CPP_OS_VXWORKS_SPEC }, \
+/* END CYGNUS LOCAL */ \
+ { "cpp_os_default", CPP_OS_DEFAULT_SPEC },
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using `MULTILIB_OPTIONS'.
+
+ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
+ the target makefile fragment or if none of the options listed in
+ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mbig", "mcall-sysv" }
+
+/* Define this macro if the code for function profiling should come
+ before the function prologue. Normally, the profiling code comes
+ after. */
+#define PROFILE_BEFORE_PROLOGUE 1
+
+/* Function name to call to do profiling. */
+#undef RS6000_MCOUNT
+#define RS6000_MCOUNT "_mcount"
diff --git a/gcc/config/rs6000/sysv4le.h b/gcc/config/rs6000/sysv4le.h
new file mode 100755
index 0000000..d444a1a
--- /dev/null
+++ b/gcc/config/rs6000/sysv4le.h
@@ -0,0 +1,54 @@
+/* Target definitions for GNU compiler for a little endian PowerPC
+ running System V.4
+ Copyright (C) 1995, 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "rs6000/sysv4.h"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_LITTLE_ENDIAN)
+
+#undef CPP_ENDIAN_DEFAULT_SPEC
+#define CPP_ENDIAN_DEFAULT_SPEC "%(cpp_endian_little)"
+
+#undef CC1_ENDIAN_DEFAULT_SPEC
+#define CC1_ENDIAN_DEFAULT_SPEC "%(cc1_endian_little)"
+
+#undef LINK_TARGET_SPEC
+#define LINK_TARGET_SPEC "\
+%{mbig: -oformat elf32-powerpc } %{mbig-endian: -oformat elf32-powerpc } \
+%{!mlittle: %{!mlittle-endian: %{!mbig: %{!mbig-endian: \
+ %{cygnus-local-vmakarov: } \
+ %{mcall-i960-old: -oformat elf32-powerpcle} \
+ %{end-cygnus-local: } \
+ %{mcall-solaris: -oformat elf32-powerpcle} \
+ %{mcall-linux: -oformat elf32-powerpc}}}}}"
+
+/* Define this macro as a C expression for the initializer of an
+ array of string to tell the driver program which options are
+ defaults for this target and thus do not need to be handled
+ specially when using `MULTILIB_OPTIONS'.
+
+ Do not define this macro if `MULTILIB_OPTIONS' is not defined in
+ the target makefile fragment or if none of the options listed in
+ `MULTILIB_OPTIONS' are set by default. *Note Target Fragment::. */
+
+#undef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "mlittle", "mcall-sysv" }
diff --git a/gcc/config/rs6000/t-aix43 b/gcc/config/rs6000/t-aix43
new file mode 100755
index 0000000..56ddb45
--- /dev/null
+++ b/gcc/config/rs6000/t-aix43
@@ -0,0 +1,48 @@
+# Do not build libgcc1.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so... [taken from t-sparclite]
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+# Build the libraries for both hard and soft floating point and all of the
+# different processor models
+
+MULTILIB_OPTIONS = msoft-float \
+ mcpu=common/mcpu=power/mcpu=powerpc/maix64
+
+MULTILIB_DIRNAMES = soft-float \
+ common power powerpc aix64
+
+MULTILIB_MATCHES = msoft-float=mcpu?403 \
+ maix64=maix64 \
+ mcpu?power=mpower \
+ mcpu?power=mrios1 \
+ mcpu?power=mcpu?rios1 \
+ mcpu?power=mcpu?rsc \
+ mcpu?power=mcpu?rsc1 \
+ mcpu?power=mpower2 \
+ mcpu?power=mrios2 \
+ mcpu?power=mcpu=rios2 \
+ mcpu?powerpc=mcpu?601 \
+ mcpu?powerpc=mcpu?602 \
+ mcpu?powerpc=mcpu?603 \
+ mcpu?powerpc=mcpu?603e \
+ mcpu?powerpc=mcpu?604 \
+ mcpu?powerpc=mcpu?620 \
+ mcpu?powerpc=mcpu?403 \
+ mcpu?powerpc=mpowerpc \
+ mcpu?powerpc=mpowerpc-gpopt \
+ mcpu?powerpc=mpowerpc-gfxopt
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
diff --git a/gcc/config/rs6000/t-beos b/gcc/config/rs6000/t-beos
new file mode 100755
index 0000000..1436108
--- /dev/null
+++ b/gcc/config/rs6000/t-beos
@@ -0,0 +1,51 @@
+# Do not build libgcc1.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so... [taken from t-sparclite]
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+# Build the libraries for both hard and soft floating point
+
+MULTILIB_OPTIONS = msoft-float mcpu=common
+MULTILIB_DIRNAMES = soft-float common
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
+# This is probably the correct define, to override the Makefile
+# default, but using it causes more problems than it solves.
+#
+# Using it will cause fixincludes to try and fix some of the
+# mwcc header files, which it seems to do a poor job of. On
+# the other hand, not using it will only cause the gcc version
+# of limits.h to lack the header and trailer parts that are
+# tacked on to it when there is a limits.h in the system header
+# dir.
+#
+# For now it is probably better to change the rule for
+# LIMITS_H_TEST to explicitly look for the BeOS limits.h.
+# If the gcc limits.h is not set up to #include_next the
+# BeOS limits.h, then some things will go undefined, like
+# PATH_MAX.
+
+#SYSTEM_HEADER_DIR=/boot/develop/headers/posix
+# Test to see whether <limits.h> exists in the system header files.
+LIMITS_H_TEST = [ -f /boot/develop/headers/posix/limits.h ]
+
+# Aix 3.2.x needs milli.exp for -mcpu=common
+EXTRA_PARTS = milli.exp
+milli.exp: $(srcdir)/config/rs6000/milli.exp
+ rm -f milli.exp
+ cp $(srcdir)/config/rs6000/milli.exp ./milli.exp
+
+# Don't use collect.
+USE_COLLECT2 =
diff --git a/gcc/config/rs6000/t-newas b/gcc/config/rs6000/t-newas
new file mode 100755
index 0000000..823b03b
--- /dev/null
+++ b/gcc/config/rs6000/t-newas
@@ -0,0 +1,52 @@
+# Do not build libgcc1.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so... [taken from t-sparclite]
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+# Build the libraries for both hard and soft floating point and all of the
+# different processor models
+
+MULTILIB_OPTIONS = msoft-float \
+ mcpu=common/mcpu=power/mcpu=powerpc
+
+MULTILIB_DIRNAMES = soft-float \
+ common power powerpc
+
+MULTILIB_MATCHES = msoft-float=mcpu?403 \
+ mcpu?power=mpower \
+ mcpu?power=mrios1 \
+ mcpu?power=mcpu?rios1 \
+ mcpu?power=mcpu?rsc \
+ mcpu?power=mcpu?rsc1 \
+ mcpu?power=mpower2 \
+ mcpu?power=mrios2 \
+ mcpu?power=mcpu=rios2 \
+ mcpu?powerpc=mcpu?601 \
+ mcpu?powerpc=mcpu?602 \
+ mcpu?powerpc=mcpu?603 \
+ mcpu?powerpc=mcpu?603e \
+ mcpu?powerpc=mcpu?604 \
+ mcpu?powerpc=mcpu?620 \
+ mcpu?powerpc=mcpu?403 \
+ mcpu?powerpc=mpowerpc \
+ mcpu?powerpc=mpowerpc-gpopt \
+ mcpu?powerpc=mpowerpc-gfxopt
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
+# Aix 3.2.x needs milli.exp for -mcpu=common
+EXTRA_PARTS = milli.exp
+milli.exp: $(srcdir)/config/rs6000/milli.exp
+ rm -f milli.exp
+ cp $(srcdir)/config/rs6000/milli.exp ./milli.exp
diff --git a/gcc/config/rs6000/t-ppc b/gcc/config/rs6000/t-ppc
new file mode 100755
index 0000000..8143488
--- /dev/null
+++ b/gcc/config/rs6000/t-ppc
@@ -0,0 +1,12 @@
+# PowerPC support without gas
+
+# Build libgcc.a with different options. If no gas support, don't build
+# explicit little endian or big endian libraries, since it depends on the
+# -mbig/-mlittle switches passed to gas. The -mrelocatable support also needs
+# -mrelocatable passed to gas, so don't use it either.
+
+MULTILIB_OPTIONS = msoft-float
+MULTILIB_DIRNAMES = nof
+MULTILIB_EXCEPTIONS =
+MULTILIB_EXTRA_OPTS = mstrict-align
+MULTILIB_MATCHES = ${MULTILIB_MATCHES_FLOAT}
diff --git a/gcc/config/rs6000/t-ppccomm b/gcc/config/rs6000/t-ppccomm
new file mode 100755
index 0000000..9ed1690
--- /dev/null
+++ b/gcc/config/rs6000/t-ppccomm
@@ -0,0 +1,79 @@
+# Common support for PowerPC eabi, System V targets.
+
+# Do not build libgcc1.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so... [taken from t-sparclite]
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c eabi.S eabi-ctors.c tramp.S
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+eabi.S: $(srcdir)/config/rs6000/eabi.asm
+ cat $(srcdir)/config/rs6000/eabi.asm > eabi.S
+
+eabi-ctors.c: $(srcdir)/config/rs6000/eabi-ctors.c
+ cat $(srcdir)/config/rs6000/eabi-ctors.c > eabi-ctors.c
+
+tramp.S: $(srcdir)/config/rs6000/tramp.asm
+ cat $(srcdir)/config/rs6000/tramp.asm > tramp.S
+
+# Switch synonyms
+MULTILIB_MATCHES_FLOAT = msoft-float=mcpu?401 \
+ msoft-float=mcpu?403 \
+ msoft-float=mcpu?ec603e \
+ msoft-float=mcpu?801 \
+ msoft-float=mcpu?821 \
+ msoft-float=mcpu?823 \
+ msoft-float=mcpu?860
+MULTILIB_MATCHES_ENDIAN = mlittle=mlittle-endian mbig=mbig-endian
+MULTILIB_MATCHES_SYSV = mcall-sysv=mcall-sysv-eabi mcall-sysv=mcall-sysv-noeabi
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+EXTRA_MULTILIB_PARTS = ecrti$(objext) ecrtn$(objext) scrt0$(objext) scrti$(objext) scrtn$(objext)
+
+# We build {e,s}crti.o, {e,s}crtn.o, and scrt0.o which serve to add begin and
+# end labels to all of the special sections used when we link using gcc.
+
+# Assemble startup files.
+ecrti.S: $(srcdir)/config/rs6000/eabi-ci.asm
+ cat $(srcdir)/config/rs6000/eabi-ci.asm >ecrti.S
+
+ecrtn.S: $(srcdir)/config/rs6000/eabi-cn.asm
+ cat $(srcdir)/config/rs6000/eabi-cn.asm >ecrtn.S
+
+scrti.S: $(srcdir)/config/rs6000/sol-ci.asm
+ cat $(srcdir)/config/rs6000/sol-ci.asm >scrti.S
+
+scrtn.S: $(srcdir)/config/rs6000/sol-cn.asm
+ cat $(srcdir)/config/rs6000/sol-cn.asm >scrtn.S
+
+scrt0.c: $(srcdir)/config/rs6000/sol-c0.c
+ cat $(srcdir)/config/rs6000/sol-c0.c >scrt0.c
+
+# Build multiple copies of ?crt{i,n}.o, one for each target switch.
+$(T)ecrti$(objext): ecrti.S
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -c ecrti.S -o $(T)ecrti$(objext)
+
+$(T)ecrtn$(objext): ecrtn.S
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -c ecrtn.S -o $(T)ecrtn$(objext)
+
+$(T)scrti$(objext): scrti.S
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -c scrti.S -o $(T)scrti$(objext)
+
+$(T)scrtn$(objext): scrtn.S
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -c scrtn.S -o $(T)scrtn$(objext)
+
+$(T)scrt0$(objext): scrt0.c
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -c scrt0.c -o $(T)scrt0$(objext)
+
+# It is important that crtbegin.o, etc., aren't surprised by stuff in .sdata.
+CRTSTUFF_T_CFLAGS = -msdata=none
+CRTSTUFF_T_CFLAGS_S = -fpic -msdata=none
diff --git a/gcc/config/rs6000/t-ppcgas b/gcc/config/rs6000/t-ppcgas
new file mode 100755
index 0000000..ce4c469
--- /dev/null
+++ b/gcc/config/rs6000/t-ppcgas
@@ -0,0 +1,22 @@
+# PowerPC embedded support with gas.
+# Build libgcc.a with different options.
+
+MULTILIB_OPTIONS = msoft-float \
+ mlittle/mbig \
+ mcall-sysv/mcall-aix/mcall-linux/mcall-i960-old \
+ fleading-underscore # CYGNUS local vmakarov: mcall-i960-old and fleading-underscore
+
+MULTILIB_DIRNAMES = nof \
+ le be \
+ cs ca lin o960 \
+ uns # CYGNUS local vmakarov: o960 and uns
+
+MULTILIB_EXTRA_OPTS = mrelocatable-lib mno-eabi mstrict-align
+MULTILIB_EXCEPTIONS = *mbig/*mcall-linux* \
+ *mlittle/*mcall-linux* \
+ *msoft-float/*mcall-linux* \
+ *mbig/*mcall-i960-old* # CYGNUS local vmakarov
+
+MULTILIB_MATCHES = ${MULTILIB_MATCHES_FLOAT} \
+ ${MULTILIB_MATCHES_ENDIAN} \
+ ${MULTILIB_MATCHES_SYSV}
diff --git a/gcc/config/rs6000/t-ppcos b/gcc/config/rs6000/t-ppcos
new file mode 100755
index 0000000..480665a
--- /dev/null
+++ b/gcc/config/rs6000/t-ppcos
@@ -0,0 +1,12 @@
+# Target config file for a System V based system (Solaris, GNU/Linux, Netbsd)
+# with gas.
+
+# Build libgcc.a with different options. With gas, build pic libraries
+# as well no floating point
+MULTILIB_OPTIONS = msoft-float fPIC
+MULTILIB_DIRNAMES = nof pic
+MULTILIB_EXCEPTIONS =
+MULTILIB_MATCHES = ${MULTILIB_MATCHES_FLOAT} \
+ fPIC=mrelocatable-lib \
+ fPIC=mrelocatable \
+ fPIC=fpic
diff --git a/gcc/config/rs6000/t-rs6000 b/gcc/config/rs6000/t-rs6000
new file mode 100755
index 0000000..4c659a6
--- /dev/null
+++ b/gcc/config/rs6000/t-rs6000
@@ -0,0 +1,22 @@
+# Do not build libgcc1.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so... [taken from t-sparclite]
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+# Build the libraries for both hard and soft floating point
+
+MULTILIB_OPTIONS = msoft-float
+MULTILIB_DIRNAMES = soft-float
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
diff --git a/gcc/config/rs6000/t-vxworks b/gcc/config/rs6000/t-vxworks
new file mode 100755
index 0000000..df4f856
--- /dev/null
+++ b/gcc/config/rs6000/t-vxworks
@@ -0,0 +1,3 @@
+# Inhibit building libc routines under VxWorks for now
+
+TARGET_LIBGCC2_CFLAGS = -Dinhibit_libc
diff --git a/gcc/config/rs6000/t-winnt b/gcc/config/rs6000/t-winnt
new file mode 100755
index 0000000..f58aefe
--- /dev/null
+++ b/gcc/config/rs6000/t-winnt
@@ -0,0 +1,35 @@
+# Do not build libgcc1.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+EXTRA_PARTS = crti.o crtn.o
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so... [taken from t-sparclite]
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c ntstack.S
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+ntstack.S: $(srcdir)/config/rs6000/ntstack.asm
+ cat $(srcdir)/config/rs6000/ntstack.asm > ntstack.S
+
+# For NT we build crti.o and crtn.o which serve to add begin and
+# end labels for the static constructors and destructors.
+
+# Assemble startup files.
+crti.s: $(srcdir)/config/rs6000/nt-ci.asm
+ cat $(srcdir)/config/rs6000/nt-ci.asm >crti.s
+
+crtn.s: $(srcdir)/config/rs6000/nt-cn.asm
+ cat $(srcdir)/config/rs6000/nt-cn.asm >crtn.s
+
+crti.o: crti.s
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -c -o crti.o crti.s
+
+crtn.o: crtn.s
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -c -o crtn.o crtn.s
diff --git a/gcc/config/rs6000/t-xnewas b/gcc/config/rs6000/t-xnewas
new file mode 100755
index 0000000..285f825
--- /dev/null
+++ b/gcc/config/rs6000/t-xnewas
@@ -0,0 +1,58 @@
+# Same as t-newas, except don't build libgcc1-test. This is because
+# the compiler emits code to call external functions to save the
+# arguments that are in libc, but since libgcc1-test is linked without
+# libc, they will show up as errors.
+LIBGCC1_TEST =
+
+# Do not build libgcc1.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so... [taken from t-sparclite]
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+# Build the libraries for both hard and soft floating point and all of the
+# different processor models
+
+MULTILIB_OPTIONS = msoft-float \
+ mcpu=common/mcpu=power/mcpu=powerpc
+
+MULTILIB_DIRNAMES = soft-float \
+ common power powerpc
+
+MULTILIB_MATCHES = msoft-float=mcpu?403 \
+ mcpu?power=mpower \
+ mcpu?power=mrios1 \
+ mcpu?power=mcpu?rios1 \
+ mcpu?power=mcpu?rsc \
+ mcpu?power=mcpu?rsc1 \
+ mcpu?power=mpower2 \
+ mcpu?power=mrios2 \
+ mcpu?power=mcpu=rios2 \
+ mcpu?powerpc=mcpu?601 \
+ mcpu?powerpc=mcpu?602 \
+ mcpu?powerpc=mcpu?603 \
+ mcpu?powerpc=mcpu?603e \
+ mcpu?powerpc=mcpu?604 \
+ mcpu?powerpc=mcpu?620 \
+ mcpu?powerpc=mcpu?403 \
+ mcpu?powerpc=mpowerpc \
+ mcpu?powerpc=mpowerpc-gpopt \
+ mcpu?powerpc=mpowerpc-gfxopt
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
+# Aix 3.2.x needs milli.exp for -mcpu=common
+EXTRA_PARTS = milli.exp
+milli.exp: $(srcdir)/config/rs6000/milli.exp
+ rm -f milli.exp
+ cp $(srcdir)/config/rs6000/milli.exp ./milli.exp
diff --git a/gcc/config/rs6000/t-xrs6000 b/gcc/config/rs6000/t-xrs6000
new file mode 100755
index 0000000..f5d34d6
--- /dev/null
+++ b/gcc/config/rs6000/t-xrs6000
@@ -0,0 +1,28 @@
+# Same as t-rs6000, except don't build libgcc1-test. This is because
+# the compiler emits code to call external functions to save the
+# arguments that are in libc, but since libgcc1-test is linked without
+# libc, they will show up as errors.
+LIBGCC1_TEST =
+
+# Do not build libgcc1.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so... [taken from t-sparclite]
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+# Build the libraries for both hard and soft floating point
+
+MULTILIB_OPTIONS = msoft-float
+MULTILIB_DIRNAMES = soft-float
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
diff --git a/gcc/config/rs6000/tramp.asm b/gcc/config/rs6000/tramp.asm
new file mode 100755
index 0000000..47ab7d6
--- /dev/null
+++ b/gcc/config/rs6000/tramp.asm
@@ -0,0 +1,120 @@
+/* Special support for trampolines
+ *
+ * Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ * Written By Michael Meissner
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * In addition to the permissions in the GNU General Public License, the
+ * Free Software Foundation gives you unlimited permission to link the
+ * compiled version of this file with other programs, and to distribute
+ * those programs without any restriction coming from the use of this
+ * file. (The General Public License restrictions do apply in other
+ * respects; for example, they cover modification of the file, and
+ * distribution when not linked into another program.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * As a special exception, if you link this library with files
+ * compiled with GCC to produce an executable, this does not cause
+ * the resulting executable to be covered by the GNU General Public License.
+ * This exception does not however invalidate any other reasons why
+ * the executable file might be covered by the GNU General Public License.
+ */
+
+/* Set up trampolines */
+
+ .file "tramp.asm"
+ .section ".text"
+ #include "ppc-asm.h"
+
+ .globl __trampoline_initial
+ .type __trampoline_initial,@object
+ .align 2
+__trampoline_initial:
+ mflr r0
+ bl 1f
+.Lfunc = .-__trampoline_initial
+ .long 0 /* will be replaced with function address */
+.Lchain = .-__trampoline_initial
+ .long 0 /* will be replaced with static chain */
+1: mflr r11
+ mtlr r0
+ lwz r0,0(r11) /* function address */
+ lwz r11,4(r11) /* static chain */
+ mtctr r0
+ bctr
+
+__trampoline_size = .-__trampoline_initial
+ .size __trampoline_initial,__trampoline_size
+
+ .section ".got2","aw"
+.LCTOC1 = .+32768
+.Ltramp = .-.LCTOC1
+ .long __trampoline_initial-4
+
+ .section ".text"
+.LCL0:
+ .long .LCTOC1-.LCF0
+
+/* R3 = stack address to store trampoline */
+/* R4 = length of trampoline area */
+/* R5 = function address */
+/* R6 = static chain */
+
+FUNC_START(__trampoline_setup)
+ mflr r0 /* save return address */
+ bl .LCF0 /* load up __trampoline_initial into r7 */
+.LCF0:
+ mflr r11
+ lwz r12,(.LCL0-.LCF0)(r11)
+ add r11,r12,r11
+ lwz r7,.Ltramp(r11) /* trampoline address -4 */
+
+ li r8,__trampoline_size /* verify that the trampoline is big enough */
+ cmpw cr1,r8,r4
+ srwi r4,r4,2 /* # words to move */
+ addi r9,r3,-4 /* adjust pointer for lwzu */
+ mtctr r4
+ blt cr1,.Labort
+
+ mtlr r0
+
+ /* Copy the instructions to the stack */
+.Lmove:
+ lwzu r10,4(r7)
+ stwu r10,4(r9)
+ bdnz .Lmove
+
+ /* Store correct function and static chain */
+ stw r5,.Lfunc(r3)
+ stw r6,.Lchain(r3)
+
+ /* Now flush both caches */
+ mtctr r4
+.Lcache:
+ icbi 0,r3
+ dcbf 0,r3
+ addi r3,r3,4
+ bdnz .Lcache
+
+ /* Finally synchronize things & return */
+ sync
+ isync
+ blr
+
+.Labort:
+ bl abort
+FUNC_END(__trampoline_setup)
+/* END CYGNUS LOCAL -- waiting for FSF sources to be restored/meissner */
diff --git a/gcc/config/rs6000/vxppc.h b/gcc/config/rs6000/vxppc.h
new file mode 100755
index 0000000..83b2348
--- /dev/null
+++ b/gcc/config/rs6000/vxppc.h
@@ -0,0 +1,107 @@
+/* Definitions of target machine for GNU compiler. Vxworks PowerPC version.
+ Copyright (C) 1996, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file just exists to give specs for the PowerPC running on VxWorks. */
+
+#include "rs6000/sysv4.h"
+
+/* CYGNUS LOCAL vmakarov */
+#if 0
+/* END CYGNUS LOCAL */
+/* ??? This file redefines CPP_SPEC which is wrong. It should instead define
+ one of the extra specs that gets included in CPP_SPEC. For instance,
+ CPP_OS_DEFAULT_SPEC. The mrelocatable line was copied from CPP_SYSV_SPEC.
+ There is probably other stuff missing. */
+
+#undef CPP_SPEC
+#define CPP_SPEC "\
+%{posix: -D_POSIX_SOURCE} \
+%{mrelocatable*: -D_RELOCATABLE} \
+%{!mcpu*: \
+ %{mpowerpc*: -D_ARCH_PPC -DCPU=PPC603} \
+ %{!mno-powerpc: -D_ARCH_PPC -DCPU=PPC603}} \
+%{mcpu=powerpc: -D_ARCH_PPC -DCPU=PPC603} \
+%{mcpu=403: -D_ARCH_PPC -DCPU=PPC403} \
+%{mcpu=601: -D_ARCH_PPC -D_ARCH_PWR -DCPU=PPC601} \
+%{mcpu=603: -D_ARCH_PPC -DCPU=PPC603} \
+%{mcpu=604: -D_ARCH_PPC -DCPU=PPC604}"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "\
+-D__vxworks -D__vxworks__ -Asystem(vxworks) -Asystem(embedded) \
+-Acpu(powerpc) -Amachine(powerpc)"
+
+/* VxWorks does all the library stuff itself. */
+
+#undef LIB_SPEC
+#define LIB_SPEC ""
+
+/* VxWorks uses object files, not loadable images. make linker just
+ combine objects. */
+
+#undef LINK_SPEC
+#define LINK_SPEC "-r"
+
+/* VxWorks provides the functionality of crt0.o and friends itself. */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC ""
+
+/* CYGNUS LOCAL vmakarov */
+#endif
+
+/* Reset defaults */
+#undef CPP_OS_DEFAULT_SPEC
+#define CPP_OS_DEFAULT_SPEC "%(cpp_os_vxworks)"
+
+#undef LIB_DEFAULT_SPEC
+#define LIB_DEFAULT_SPEC "%(lib_vxworks)"
+
+#undef STARTFILE_DEFAULT_SPEC
+#define STARTFILE_DEFAULT_SPEC "%(startfile_vxworks)"
+
+#undef ENDFILE_DEFAULT_SPEC
+#define ENDFILE_DEFAULT_SPEC "%(endfile_vxworks)"
+
+#undef LINK_START_DEFAULT_SPEC
+#define LINK_START_DEFAULT_SPEC "%(link_start_vxworks)"
+
+#undef LINK_OS_DEFAULT_SPEC
+#define LINK_OS_DEFAULT_SPEC "%(link_os_vxworks)"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "\
+-D__vxworks -D__vxworks__ -Asystem(vxworks) -Asystem(embedded) \
+-Acpu(powerpc) -Amachine(powerpc)"
+
+/* Don't define _LITTLE_ENDIAN or _BIG_ENDIAN */
+#undef CPP_ENDIAN_BIG_SPEC
+#define CPP_ENDIAN_BIG_SPEC "-D__BIG_ENDIAN__ -Amachine(bigendian)"
+
+#undef CPP_ENDIAN_LITTLE_SPEC
+#define CPP_ENDIAN_LITTLE_SPEC "-D__LITTLE_ENDIAN__ -Amachine(littleendian)"
+/* END CYGNUS LOCAL */
+
+/* We use stabs-in-elf for debugging */
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
diff --git a/gcc/config/rs6000/vxppcle.h b/gcc/config/rs6000/vxppcle.h
new file mode 100755
index 0000000..fadec99
--- /dev/null
+++ b/gcc/config/rs6000/vxppcle.h
@@ -0,0 +1,58 @@
+/* Definitions of target machine for GNU compiler. Vxworks PowerPC version.
+ Copyright (C) 1996, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file just exists to give specs for the PowerPC running on VxWorks. */
+
+#include "rs6000/sysv4le.h"
+
+/* Reset defaults */
+#undef CPP_OS_DEFAULT_SPEC
+#define CPP_OS_DEFAULT_SPEC "%(cpp_os_vxworks)"
+
+#undef LIB_DEFAULT_SPEC
+#define LIB_DEFAULT_SPEC "%(lib_vxworks)"
+
+#undef STARTFILE_DEFAULT_SPEC
+#define STARTFILE_DEFAULT_SPEC "%(startfile_vxworks)"
+
+#undef ENDFILE_DEFAULT_SPEC
+#define ENDFILE_DEFAULT_SPEC "%(endfile_vxworks)"
+
+#undef LINK_START_DEFAULT_SPEC
+#define LINK_START_DEFAULT_SPEC "%(link_start_vxworks)"
+
+#undef LINK_OS_DEFAULT_SPEC
+#define LINK_OS_DEFAULT_SPEC "%(link_os_vxworks)"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "\
+-D__vxworks -D__vxworks__ -Asystem(vxworks) -Asystem(embedded) \
+-Acpu(powerpc) -Amachine(powerpc)"
+
+/* Don't define _LITTLE_ENDIAN or _BIG_ENDIAN */
+#undef CPP_ENDIAN_BIG_SPEC
+#define CPP_ENDIAN_BIG_SPEC "-D__BIG_ENDIAN__ -Amachine(bigendian)"
+
+#undef CPP_ENDIAN_LITTLE_SPEC
+#define CPP_ENDIAN_LITTLE_SPEC "-D__LITTLE_ENDIAN__ -Amachine(littleendian)"
+
+/* We use stabs-in-elf for debugging */
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
diff --git a/gcc/config/rs6000/win-nt.h b/gcc/config/rs6000/win-nt.h
new file mode 100755
index 0000000..742a5e8
--- /dev/null
+++ b/gcc/config/rs6000/win-nt.h
@@ -0,0 +1,481 @@
+/* Definitions of target machine for GNU compiler, for PowerPC
+ running Windows/NT.
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Say this is Windows/NT for the other config files. */
+#define WINDOWS_NT 1
+#define COFF_WITH_PE 1
+
+/* Default ABI to compile code for */
+#define DEFAULT_ABI ABI_NT
+
+#define CPP_DEFAULT_SPEC "-D_ARCH_PPC"
+
+#define ASM_DEFAULT_SPEC "-mppc"
+
+/* Pseudo target that we can test in the md file. */
+#define TARGET_WINDOWS_NT 1
+
+#include "rs6000/rs6000.h"
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS)
+
+#undef PROCESSOR_DEFAULT
+#define PROCESSOR_DEFAULT PROCESSOR_POWERPC
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-DWIN32 -D_WIN32 \
+ -DWINNT -D__STDC__=0 -DALMOST_STDC \
+ -D_POWER -D_ARCH_PPC -D__PPC__ -Asystem(winnt) -Acpu(powerpc) -Amachine(powerpc)"
+
+#if 0
+#include "winnt/win-nt.h"
+#endif
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{mwindows:-subsystem:windows -entry:WinMainCRTStartup \
+ USER32.LIB GDI32.LIB COMDLG32.LIB WINSPOOL.LIB} \
+ %{!mwindows:-subsystem console -e mainCRTStartup} \
+ %{mcrtmt:LIBCMT.LIB KERNEL32.LIB} %{!mcrtmt:-lkernel32 -lcygwin} \
+ %{v}"
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{v:-V}"
+
+/* Allow switches specified in LIB_SPEC, but don't do anything with them
+ in the compiler. */
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ { "windows", 0 }, \
+ { "crtmt", 0 },
+
+#undef XCOFF_DEBUGGING_INFO
+
+/* this is pure coff, not xcoff */
+#define SDB_DEBUGGING_INFO
+#define DBX_DEBUGGING_INFO
+
+#undef SDB_DELIM
+#define SDB_DELIM ";"
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+/* NT always runs little endian */
+#undef BYTES_BIG_ENDIAN
+#define BYTES_BIG_ENDIAN 0
+
+#undef WORDS_BIG_ENDIAN
+#define WORDS_BIG_ENDIAN 0
+
+/* Define cutoff for using external functions to save floating point.
+ Currently on NT, always use inline stores */
+#undef FP_SAVE_INLINE
+#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 64)
+
+/* Note, little endian systems trap on unaligned addresses, so never
+ turn off strict alignment in that case. */
+
+#undef STRICT_ALIGNMENT
+#define STRICT_ALIGNMENT 1
+
+/* Align stack to 16 byte boundaries */
+#undef STACK_BOUNDARY
+#define STACK_BOUNDARY 128
+
+/* No data type wants to be aligned rounder than this. */
+#undef BIGGEST_ALIGNMENT
+#define BIGGEST_ALIGNMENT 128
+
+/* NT aligns internal doubles in structures on dword boundaries. */
+#undef BIGGEST_FIELD_ALIGNMENT
+#define BIGGEST_FIELD_ALIGNMENT 64
+
+#undef ADJUST_FIELD_ALIGN
+#undef ROUND_TYPE_ALIGN
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (PowerPC PE)");
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC)
+
+/* Address to save the TOC register */
+#undef RS6000_SAVE_TOC
+#define RS6000_SAVE_TOC plus_constant (virtual_incoming_args_rtx, -RS6000_SAVE_AREA - 8)
+
+/* Windows NT specifies that r13 is reserved to the OS, so it is not available
+ to the normal user. */
+
+#undef FIXED_R13
+#define FIXED_R13 1
+
+/* This says how to output an assembler line
+ to define a global common symbol. */
+
+#undef ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGNMENT) \
+ do { fputs ("\t.comm \t", (FILE)); \
+ assemble_name ((FILE), (NAME)); \
+ if ( (SIZE) > 4) \
+ fprintf ((FILE), ",%d,%d\n", (SIZE), 3); \
+ else \
+ fprintf( (FILE), ",%d\n", (SIZE)); \
+ } while (0)
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+
+/* This says how to output an assembler line
+ to define a global common symbol. */
+
+#undef ASM_OUTPUT_COMMON
+#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
+ do { fputs ("\t.comm \t", (FILE)); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), ",%d\n", (SIZE)); } while (0)
+
+/* This says how to output an assembler line
+ to define an aligned local common symbol. */
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ bss_section (); \
+ ASM_OUTPUT_ALIGN (FILE, exact_log2 (ALIGN / BITS_PER_UNIT)); \
+ ASM_OUTPUT_LABEL (FILE, NAME); \
+ ASM_OUTPUT_SKIP (FILE, SIZE); \
+} while (0)
+
+/* Describe how to emit uninitialized external linkage items */
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+do { \
+ ASM_GLOBALIZE_LABEL (FILE, NAME); \
+ ASM_OUTPUT_ALIGNED_LOCAL (FILE, NAME, SIZE, ALIGN); \
+} while (0)
+
+/* This says out to put a global symbol in the BSS section */
+#undef ASM_OUTPUT_ALIGNED_BSS
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ asm_output_aligned_bss ((FILE), (DECL), (NAME), (SIZE), (ALIGN))
+
+
+/* Stuff to force fit us into the Motorola PPC assembler */
+
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+do { \
+ output_file_directive ((FILE), main_input_filename); \
+ rs6000_file_start (FILE, TARGET_CPU_DEFAULT); \
+ data_section (); \
+} while (0)
+
+#undef ASM_FILE_END
+
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \
+{ \
+ tree exception_args; \
+ int i; \
+ \
+ if (TREE_PUBLIC (DECL)) \
+ { \
+ fprintf (FILE, "\t.globl .."); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } \
+ \
+ fprintf (FILE, "\n#\tFunction: '.."); \
+ assemble_name (FILE, NAME); \
+ fputs ("'\n", FILE); \
+ fputs ("#\tText in section: <default>\n\n", FILE); \
+ fputs ("#\tSetup MS Structured-Exception-Handling\n", FILE); \
+ fputs ("\t.pdata\n", FILE); \
+ fputs ("\t.align 2\n", FILE); \
+ fputs ("\t.ualong ..", FILE); \
+ assemble_name (FILE, NAME); \
+ fputs (",", FILE); \
+ assemble_name (FILE, NAME); \
+ fputs (".e,", FILE); \
+ exception_args = lookup_attribute ("exception", \
+ TYPE_ATTRIBUTES (TREE_TYPE (DECL))); \
+ \
+ if (exception_args) \
+ exception_args = TREE_VALUE (exception_args); \
+ \
+ for (i = 0; i < 2; i++) \
+ { \
+ if (!exception_args) \
+ fputs ("0,", FILE); \
+ else \
+ { \
+ tree field = TREE_VALUE (exception_args); \
+ exception_args = TREE_PURPOSE (exception_args); \
+ if (TREE_CODE (field) == STRING_CST) \
+ fprintf (FILE, "%.*s,", TREE_STRING_LENGTH (field), \
+ TREE_STRING_POINTER (field)); \
+ else if (TREE_CODE (field) == IDENTIFIER_NODE) \
+ fprintf (FILE, "%.*s,", IDENTIFIER_LENGTH (field), \
+ IDENTIFIER_POINTER (field)); \
+ else \
+ abort (); \
+ } \
+ } \
+ \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ".b\n\n"); \
+ fprintf (FILE, "#\tSwitch to the relocation section\n"); \
+ fprintf (FILE, "\t.reldata\n"); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ":\n"); \
+ fprintf (FILE, "\t.ualong .."); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ",.toc\n"); \
+ \
+ if (lookup_attribute ("dllexport", \
+ TYPE_ATTRIBUTES (TREE_TYPE (DECL)))) \
+ { \
+ fprintf (FILE, "\t.globl __imp_"); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n__imp_"); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ":\n\t.ulong "); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } \
+ \
+ fprintf (FILE, "\t.section .text\n\t.align 2\n.."); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ":\n"); \
+ fprintf (FILE, "\t.function\t.."); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+}
+
+/* This is how to output an assembler line defining a `double' constant. */
+
+#undef ASM_OUTPUT_DOUBLE
+#define ASM_OUTPUT_DOUBLE(FILE, VALUE) \
+ { \
+ if (REAL_VALUE_ISINF (VALUE) \
+ || REAL_VALUE_ISNAN (VALUE) \
+ || REAL_VALUE_MINUS_ZERO (VALUE)) \
+ { \
+ long t[2]; \
+ REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \
+ fprintf (FILE, "\t.ualong 0x%lx\n\t.long 0x%lx\n", \
+ t[0] & 0xffffffff, t[1] & 0xffffffff); \
+ } \
+ else \
+ { \
+ char str[30]; \
+ REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", str); \
+ fprintf (FILE, "\t.double %s\n", str); \
+ } \
+ }
+
+/* This is how to output an assembler line defining a `float' constant. */
+
+#undef ASM_OUTPUT_FLOAT
+#define ASM_OUTPUT_FLOAT(FILE, VALUE) \
+ { \
+ if (REAL_VALUE_ISINF (VALUE) \
+ || REAL_VALUE_ISNAN (VALUE) \
+ || REAL_VALUE_MINUS_ZERO (VALUE)) \
+ { \
+ long t; \
+ REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
+ fprintf (FILE, "\t.ualong 0x%lx\n", t & 0xffffffff); \
+ } \
+ else \
+ { \
+ char str[30]; \
+ REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
+ fprintf (FILE, "\t.float %s\n", str); \
+ } \
+ }
+
+/* Output before instructions. */
+#undef TEXT_SECTION_ASM_OP
+#define TEXT_SECTION_ASM_OP "\t.text"
+
+/* Output before writable data. */
+#undef DATA_SECTION_ASM_OP
+#define DATA_SECTION_ASM_OP "\t.data"
+
+/* Output to the bss section. */
+#undef BSS_SECTION_ASM_OP
+#define BSS_SECTION_ASM_OP "\t.section .bss"
+
+/* Define the extra sections we need. We define a dummy TOC section,
+ plus sections to hold the list of static constructors (.ctors) and
+ destructors (.dtors). */
+
+#undef READONLY_DATA_SECTION
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_toc, in_ctors, in_dtors
+
+/* Define the routines to implement these extra sections. */
+
+#undef EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS \
+ CTORS_SECTION_FUNCTION \
+ DTORS_SECTION_FUNCTION \
+ TOC_SECTION_FUNCTION \
+
+#define TOC_SECTION_FUNCTION \
+void \
+toc_section () \
+{ \
+}
+
+#define CTORS_SECTION_ASM_OP ".section\t.ctors"
+#define CTORS_SECTION_FUNCTION \
+void \
+ctors_section () \
+{ \
+ if (in_section != in_ctors) \
+ { \
+ fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \
+ in_section = in_ctors; \
+ } \
+}
+
+#define DTORS_SECTION_ASM_OP ".section\t.dtors"
+#define DTORS_SECTION_FUNCTION \
+void \
+dtors_section () \
+{ \
+ if (in_section != in_dtors) \
+ { \
+ fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \
+ in_section = in_dtors; \
+ } \
+}
+
+#undef SELECT_SECTION
+#undef SELECT_RTX_SECTION
+
+/* Make sure __main gets called */
+#define INVOKE__main 1
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global constructors. */
+#undef ASM_OUTPUT_CONSTRUCTOR
+#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
+ do { \
+ ctors_section (); \
+ fprintf (FILE, "\t.ualong "); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global destructors. */
+#undef ASM_OUTPUT_DESTRUCTOR
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
+ do { \
+ dtors_section (); \
+ fprintf (FILE, "\t.ualong "); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+
+/* Text to write out after a CALL that may be replaced by glue code by
+ the loader. The motorola asm demands that, for dll support, a .znop
+ be issued after a bl instruction, and the symbol on the .znop is the
+ symbol on the bl instruction */
+
+#undef RS6000_CALL_GLUE
+#define RS6000_CALL_GLUE "nop #\tFIXME: only works for non-dll calls."
+
+#define RS6000_CALL_GLUE2 ".znop "
+
+#undef ASM_OUTPUT_SPECIAL_POOL_ENTRY
+
+/* Output something to declare an external symbol to the assembler. Most
+ assemblers don't need this. */
+
+#undef ASM_OUTPUT_EXTERNAL
+
+#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \
+{ \
+ char *_name; \
+ rtx _symref = XEXP (DECL_RTL (DECL), 0); \
+ if ((TREE_CODE (DECL) == VAR_DECL \
+ || TREE_CODE (DECL) == FUNCTION_DECL) \
+ && (NAME)[strlen (NAME) - 1] != ']') \
+ { \
+ _name = (char *) permalloc (strlen (XSTR (_symref, 0)) + 5); \
+ strcpy (_name, XSTR (_symref, 0)); \
+ XSTR (_symref, 0) = _name; \
+ } \
+ else \
+ _name = XSTR (_symref, 0); \
+ \
+ if (DECL_FUNCTION_CODE (DECL) == 0) \
+ { \
+ fputs ("\t.extern ", FILE); \
+ assemble_name (FILE, _name); \
+ putc ('\n', FILE); \
+ if (TREE_CODE (DECL) == FUNCTION_DECL) \
+ { \
+ fputs ("\t.extern ..", FILE); \
+ assemble_name (FILE, _name); \
+ putc ('\n', FILE); \
+ } \
+ } \
+}
+
+/* Similar, but for libcall. We only have to worry about the function name,
+ not that of the descriptor. */
+
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+
+#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \
+{ fprintf (FILE, "\t.extern .."); \
+ assemble_name (FILE, XSTR (FUN, 0)); \
+ fprintf (FILE, "\n"); \
+}
+
+/* The prefix to add to user-visible assembler symbols. */
+
+#define USER_LABEL_PREFIX ".."
+
+/* Eliminate AIX style constant pool processing */
+#undef LEGITIMATE_CONSTANT_POOL_BASE_P
+#define LEGITIMATE_CONSTANT_POOL_BASE_P(X) 0
+
+#undef LEGITIMATE_CONSTANT_POOL_ADDRESS_P
+#define LEGITIMATE_CONSTANT_POOL_ADDRESS_P(X) 0
+
+#undef ASM_OUTPUT_SPECIAL_POOL_ENTRY
+
+#undef ASM_IDENTIFY_GCC
+#define ASM_IDENTIFY_GCC(x)
+
+/* Output assembler code for a block containing the constant parts
+ of a trampoline, leaving space for the variable parts.
+
+ The trampoline should set the static chain pointer to value placed
+ into the trampoline and should branch to the specified routine. */
+#define TRAMPOLINE_TEMPLATE(FILE) rs6000_trampoline_template (FILE)
diff --git a/gcc/config/rs6000/x-aix31 b/gcc/config/rs6000/x-aix31
new file mode 100755
index 0000000..9f171fc
--- /dev/null
+++ b/gcc/config/rs6000/x-aix31
@@ -0,0 +1,9 @@
+# configuration for IBM rs6000 running aix
+# Show we need to use the C version of ALLOCA
+ALLOCA=alloca.o
+
+# For some reason, we need -lm for cc1.
+# We need -lld for collect2 (actually this only matters
+# for a native compiler, but this is as good a place as any
+# to define the symbol).
+CLIB=-lm -lld
diff --git a/gcc/config/rs6000/x-aix41 b/gcc/config/rs6000/x-aix41
new file mode 100755
index 0000000..69c666b
--- /dev/null
+++ b/gcc/config/rs6000/x-aix41
@@ -0,0 +1,12 @@
+# configuration for IBM RS/6000 running AIX 4.1+
+
+# Show we need to use the C version of ALLOCA
+ALLOCA=alloca.o
+
+# We need -lld for collect2 (actually this only matters
+# for a native compiler, but this is as good a place as any
+# to define the symbol).
+CLIB=-lld
+
+# f771 and cc1plus overflow the AIX TOC
+BOOT_LDFLAGS=-Wl,-bbigtoc
diff --git a/gcc/config/rs6000/x-aix43 b/gcc/config/rs6000/x-aix43
new file mode 100755
index 0000000..072d925
--- /dev/null
+++ b/gcc/config/rs6000/x-aix43
@@ -0,0 +1,15 @@
+# configuration for IBM RS/6000 running AIX 4.3+
+
+# Show we need to use the C version of ALLOCA
+ALLOCA=alloca.o
+
+# We need -lld for collect2 (actually this only matters
+# for a native compiler, but this is as good a place as any
+# to define the symbol).
+CLIB=-lld
+
+# f771 and cc1plus overflow the AIX TOC
+BOOT_LDFLAGS=-Wl,-bbigtoc
+
+# Both 32-bit and 64-bit objects in archives
+AR_FOR_TARGET=ar -X32_64
diff --git a/gcc/config/rs6000/x-beos b/gcc/config/rs6000/x-beos
new file mode 100755
index 0000000..37b8cca
--- /dev/null
+++ b/gcc/config/rs6000/x-beos
@@ -0,0 +1,9 @@
+# configuration for BeOS
+INSTALL=install -c
+
+# Show we need to use the C version of ALLOCA
+ALLOCA=alloca.o
+# Use it regardless of whether we are compiling with gcc or not.
+USE_ALLOCA= `echo "${ALLOCA}"`
+USE_HOST_ALLOCA= `echo ${HOST_PREFIX}${HOST_ALLOCA}`
+SUBDIR_USE_ALLOCA = `if [ x$(ALLOCA) != x ]; then echo ../$(ALLOCA); else true; fi`
diff --git a/gcc/config/rs6000/x-cygwin b/gcc/config/rs6000/x-cygwin
new file mode 100755
index 0000000..5e796a0
--- /dev/null
+++ b/gcc/config/rs6000/x-cygwin
@@ -0,0 +1,4 @@
+# Don't run fixproto
+STMP_FIXPROTO =
+# Don't need collect2
+USE_COLLECT2 =
diff --git a/gcc/config/rs6000/x-lynx b/gcc/config/rs6000/x-lynx
new file mode 100755
index 0000000..a1a2a73
--- /dev/null
+++ b/gcc/config/rs6000/x-lynx
@@ -0,0 +1,14 @@
+# /bin/cc is hopelessly broken, so we must use /bin/gcc instead.
+CC = $(OLDCC)
+OLDCC = /bin/gcc
+
+# /bin/sh is too buggy, so use /bin/bash instead.
+SHELL = /bin/bash
+
+# Show we need to use the C version of ALLOCA
+ALLOCA=alloca.o
+
+# configuration for IBM rs6000 running lynx
+
+# For some reason, we need -lm for cc1.
+CLIB=-lm
diff --git a/gcc/config/rs6000/x-mach b/gcc/config/rs6000/x-mach
new file mode 100755
index 0000000..64f39a5
--- /dev/null
+++ b/gcc/config/rs6000/x-mach
@@ -0,0 +1,7 @@
+# configuration for IBM rs6000 running MACH
+
+# Show we need to use the C version of ALLOCA
+ALLOCA=alloca.o
+
+# For some reason, we need -lm for cc1.
+CLIB=-lm
diff --git a/gcc/config/rs6000/x-rs6000 b/gcc/config/rs6000/x-rs6000
new file mode 100755
index 0000000..0d8f311
--- /dev/null
+++ b/gcc/config/rs6000/x-rs6000
@@ -0,0 +1,9 @@
+# configuration for IBM rs6000 running aix
+
+# Show we need to use the C version of ALLOCA
+ALLOCA=alloca.o
+
+# We need -lld for collect2 (actually this only matters
+# for a native compiler, but this is as good a place as any
+# to define the symbol).
+CLIB=-lld
diff --git a/gcc/config/rs6000/x-sysv4 b/gcc/config/rs6000/x-sysv4
new file mode 100755
index 0000000..2a661e3
--- /dev/null
+++ b/gcc/config/rs6000/x-sysv4
@@ -0,0 +1,2 @@
+X_CFLAGS=-DSVR4
+ALLOCA=alloca.o
diff --git a/gcc/config/rs6000/xm-beos.h b/gcc/config/rs6000/xm-beos.h
new file mode 100755
index 0000000..681aa73
--- /dev/null
+++ b/gcc/config/rs6000/xm-beos.h
@@ -0,0 +1,89 @@
+/* Configuration for GNU C-compiler for BeOS host.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Contributed by Fred Fish (fnf@cygnus.com), based on xm-rs6000.h
+ by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
+
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* #defines that need visibility everywhere. */
+
+#define FALSE 0
+#define TRUE 1
+
+/* This describes the machine the compiler is hosted on. */
+
+#define HOST_BITS_PER_CHAR 8
+#define HOST_BITS_PER_SHORT 16
+#define HOST_BITS_PER_INT 32
+#define HOST_BITS_PER_LONG 32
+#define HOST_BITS_PER_LONGLONG 64
+
+#define HOST_WORDS_BIG_ENDIAN
+
+/* target machine dependencies.
+ tm.h is a symbolic link to the actual target specific file. */
+
+#include "tm.h"
+
+/* Arguments to use with `exit'. */
+
+#define SUCCESS_EXIT_CODE 0
+#define FATAL_EXIT_CODE 33
+
+/* Use the C alloca and use only int bitfields. */
+
+#define USE_C_ALLOCA
+extern void *alloca ();
+#define ONLY_INT_FIELDS
+
+/* use ANSI/SYSV style byte manipulation routines instead of BSD ones */
+
+#undef bcopy
+#define bcopy(s,d,n) memmove((d),(s),(n))
+#undef bzero
+#define bzero(d,n) memset((d),0,(n))
+#undef bcmp
+#define bcmp(l,r,n) memcmp((l),(r),(n))
+#undef index
+#define index strchr
+#undef rindex
+#define rindex strrchr
+
+/* BeOS is closer to USG than BSD */
+
+#define USG
+
+/* Define various things that the BeOS host has. */
+
+#define HAVE_VPRINTF
+#define HAVE_PUTENV
+#define HAVE_ATEXIT
+#define HAVE_RENAME
+
+#define STDC_HEADERS 1
+
+/* STANDARD_INCLUDE_DIR is the equivalent of "/usr/include" on UNIX. */
+
+#define STANDARD_INCLUDE_DIR "/boot/develop/headers/posix"
+
+/* SYSTEM_INCLUDE_DIR is the location for system specific, non-POSIX headers. */
+
+#define SYSTEM_INCLUDE_DIR "/boot/develop/headers/be"
+
diff --git a/gcc/config/rs6000/xm-cygwin.h b/gcc/config/rs6000/xm-cygwin.h
new file mode 100755
index 0000000..ca54831
--- /dev/null
+++ b/gcc/config/rs6000/xm-cygwin.h
@@ -0,0 +1 @@
+#define EXECUTABLE_SUFFIX ".exe"
diff --git a/gcc/config/rs6000/xm-lynx.h b/gcc/config/rs6000/xm-lynx.h
new file mode 100755
index 0000000..1c093c2
--- /dev/null
+++ b/gcc/config/rs6000/xm-lynx.h
@@ -0,0 +1,35 @@
+/* Configuration for GNU C-compiler for rs6000 platforms running LynxOS.
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <xm-lynx.h>
+
+/* This describes the machine the compiler is hosted on. */
+#define HOST_BITS_PER_CHAR 8
+#define HOST_BITS_PER_SHORT 16
+#define HOST_BITS_PER_INT 32
+#define HOST_BITS_PER_LONG 32
+#define HOST_BITS_PER_LONGLONG 64
+
+#define HOST_WORDS_BIG_ENDIAN 1
+
+/* target machine dependencies.
+ tm.h is a symbolic link to the actual target specific file. */
+
+#include "tm.h"
diff --git a/gcc/config/rs6000/xm-mach.h b/gcc/config/rs6000/xm-mach.h
new file mode 100755
index 0000000..2d4ee5d
--- /dev/null
+++ b/gcc/config/rs6000/xm-mach.h
@@ -0,0 +1,2 @@
+#undef USG
+#undef COLLECT_EXPORT_LIST
diff --git a/gcc/config/rs6000/xm-rs6000.h b/gcc/config/rs6000/xm-rs6000.h
new file mode 100755
index 0000000..1ad9da9
--- /dev/null
+++ b/gcc/config/rs6000/xm-rs6000.h
@@ -0,0 +1,65 @@
+/* Configuration for GNU C-compiler for IBM RS/6000 running AIX in 32-bit mode.
+ Copyright (C) 1990, 1993, 1995, 1998 Free Software Foundation, Inc.
+ Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* #defines that need visibility everywhere. */
+#define FALSE 0
+#define TRUE 1
+
+/* This describes the machine the compiler is hosted on. */
+#define HOST_BITS_PER_CHAR 8
+#define HOST_BITS_PER_SHORT 16
+#define HOST_BITS_PER_INT 32
+#define HOST_BITS_PER_LONG 32
+#define HOST_BITS_PER_LONGLONG 64
+
+#define HOST_WORDS_BIG_ENDIAN
+
+/* target machine dependencies.
+ tm.h is a symbolic link to the actual target specific file. */
+#include "tm.h"
+
+/* Arguments to use with `exit'. */
+#define SUCCESS_EXIT_CODE 0
+#define FATAL_EXIT_CODE 33
+
+/* If not compiled with GNU C, use the C alloca and use only int bitfields. */
+#ifndef __GNUC__
+#define USE_C_ALLOCA
+#if __STDC__
+extern void *alloca ();
+#else
+extern char *alloca ();
+#endif
+#define ONLY_INT_FIELDS
+#endif
+
+/* AIX is a flavor of System V */
+#define USG
+
+/* Big buffers improve performance. */
+#define IO_BUFFER_SIZE (0x8000 - 4096)
+
+#ifndef CROSS_COMPILE
+/* The AIX linker will discard static constructors in object files before
+ collect has a chance to see them, so scan the object files directly. */
+#define COLLECT_EXPORT_LIST
+#endif
diff --git a/gcc/config/rs6000/xm-sysv4.h b/gcc/config/rs6000/xm-sysv4.h
new file mode 100755
index 0000000..cf56eb4
--- /dev/null
+++ b/gcc/config/rs6000/xm-sysv4.h
@@ -0,0 +1,72 @@
+/* Configuration for GNU C-compiler for PowerPC running System V.4.
+ Copyright (C) 1995, 1998 Free Software Foundation, Inc.
+
+ Cloned from sparc/xm-sysv4.h by Michael Meissner (meissner@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* #defines that need visibility everywhere. */
+#define FALSE 0
+#define TRUE 1
+
+/* This describes the machine the compiler is hosted on. */
+#define HOST_BITS_PER_CHAR 8
+#define HOST_BITS_PER_SHORT 16
+#define HOST_BITS_PER_INT 32
+#define HOST_BITS_PER_LONG 32
+#if 0
+#define HOST_BITS_PER_LONGLONG 64
+#endif
+
+/* Doubles are stored in memory with the high order word first. This
+ matters when cross-compiling. */
+#define HOST_WORDS_BIG_ENDIAN 1
+
+/* target machine dependencies.
+ tm.h is a symbolic link to the actual target specific file. */
+#include "tm.h"
+
+/* Arguments to use with `exit'. */
+#define SUCCESS_EXIT_CODE 0
+#define FATAL_EXIT_CODE 33
+
+#ifdef __linux__
+#include "xm-linux.h"
+#endif
+
+/* if not compiled with GNU C, use the C alloca and use only int bitfields. */
+#ifndef __GNUC__
+#define USE_C_ALLOCA
+#ifdef __STDC__
+extern void *alloca ();
+#else
+extern char *alloca ();
+#endif
+#undef ONLY_INT_FIELDS
+#define ONLY_INT_FIELDS
+#endif
+
+#ifdef __PPC__
+#ifndef __STDC__
+extern char *malloc (), *realloc (), *calloc ();
+#else
+extern void *malloc (), *realloc (), *calloc ();
+#endif
+extern void free ();
+#endif