diff options
Diffstat (limited to 'gcc/config/rs6000')
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, + ®); + + if (REG_NOTES (insn)) + REG_NOTES (insn) = rs6000_replace_regno (REG_NOTES (insn), + GOT_TOC_REGNUM, + ®); + } + + 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 |