OSDN Git Service

Add setjmp/longjmp exception handling.
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.h
index bc7624d..30a070b 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions of target machine for GNU compiler, for the HP Spectrum.
-   Copyright (C) 1992, 1993 Free Software Foundation, Inc.
-   Contributed by Michael Tiemann (tiemann@mcc.com)
+   Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+   Contributed by Michael Tiemann (tiemann@cygnus.com) of Cygnus Support
    and Tim Moore (moore@defmacro.cs.utah.edu) of the Center for
    Software Science at the University of Utah.
 
@@ -18,7 +18,8 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 enum cmp_type                          /* comparison type */
 {
@@ -28,9 +29,27 @@ enum cmp_type                                /* comparison type */
   CMP_MAX                              /* max comparison type */
 };
 
+/* For long call handling.  */
+extern unsigned int total_code_bytes;
+
+/* Which processor to schedule for.  */
+
+enum processor_type
+{
+  PROCESSOR_700,
+  PROCESSOR_7100,
+  PROCESSOR_7100LC,
+};
+
+#define pa_cpu_attr ((enum attr_cpu)pa_cpu)
+
+/* For -mschedule= option.  */
+extern char *pa_cpu_string;
+extern enum processor_type pa_cpu;
+
 /* Print subsidiary information on the compiler version in use.  */
 
-#define TARGET_VERSION fprintf (stderr, " (hppa)");
+#define TARGET_VERSION fputs (" (hppa)", stderr);
 
 /* Run-time compilation parameters selecting different hardware subsets.  */
 
@@ -47,16 +66,21 @@ extern int target_flags;
 
 #define TARGET_DISABLE_FPREGS (target_flags & 2)
 
-/* Allow unconditional jumps in the delay slots of call instructions.  */
-#define TARGET_JUMP_IN_DELAY (target_flags & 8)
+/* Generate code which assumes that calls through function pointers will
+   never cross a space boundary.  Such assumptions are generally safe for
+   building kernels and statically linked executables.  Code compiled with
+   this option will fail miserably if the executable is dynamically linked
+   or uses nested functions!
 
-/* Force all function calls to indirect addressing via a register.  This
-   avoids lossage when the function is very far away from the current PC.
+   This is also used to trigger agressive unscaled index addressing.  */
+#define TARGET_NO_SPACE_REGS (target_flags & 4)
 
-   ??? What about simple jumps, they can suffer from the same problem.
-   Would require significant surgery in pa.md.  */
+/* Allow unconditional jumps in the delay slots of call instructions.  */
+#define TARGET_JUMP_IN_DELAY (target_flags & 8)
 
-#define TARGET_LONG_CALLS (target_flags & 16)
+/* Optimize for space.  Currently this only turns on out of line
+   prologues and epilogues.  */
+#define TARGET_SPACE (target_flags & 16)
 
 /* Disable indexed addressing modes.  */
 
@@ -66,7 +90,8 @@ extern int target_flags;
    HP wants everyone to use for ELF objects.  If at all possible you want
    to avoid this since it's a performance loss for non-prototyped code.
 
-   Note TARGET_PORTABLE_RUNTIME also implies TARGET_LONG_CALLS.  */
+   Note TARGET_PORTABLE_RUNTIME also forces all calls to use inline
+   long-call stubs which is quite expensive.  */
 
 #define TARGET_PORTABLE_RUNTIME (target_flags & 64)
 
@@ -76,6 +101,17 @@ extern int target_flags;
 
 #define TARGET_GAS (target_flags & 128)
 
+/* Emit code for processors which do not have an FPU.  */
+
+#define TARGET_SOFT_FLOAT (target_flags & 256)
+
+/* Use 3-insn load/store sequences for access to large data segments
+   in shared libraries on hpux10.  */
+#define TARGET_LONG_LOAD_STORE (target_flags & 512)
+
+/* Use a faster sequence for indirect calls.  */
+#define TARGET_FAST_INDIRECT_CALLS (target_flags & 1024)
+
 /* Macro to define tables used to set the flags.
    This is a list in braces of pairs in braces,
    each pair being { "NAME", VALUE }
@@ -88,28 +124,48 @@ extern int target_flags;
    {"pa-risc-1-0", -1},                \
    {"pa-risc-1-1", 1},         \
    {"disable-fpregs", 2},      \
-   {"no-disable-fpregs", 2},   \
+   {"no-disable-fpregs", -2},  \
+   {"no-space-regs", 4},       \
+   {"space-regs", -4},         \
    {"jump-in-delay", 8},       \
    {"no-jump-in-delay", -8},   \
-   {"long-calls", 16},         \
-   {"no-long-calls", -16},     \
+   {"space", 16},              \
+   {"no-space", -16},          \
    {"disable-indexing", 32},   \
    {"no-disable-indexing", -32},\
-   {"portable-runtime", 64+16},\
-   {"no-portable-runtime", -(64+16)},\
+   {"portable-runtime", 64},   \
+   {"no-portable-runtime", -64},\
    {"gas", 128},               \
    {"no-gas", -128},           \
-   { "", TARGET_DEFAULT}}
+   {"soft-float", 256},                \
+   {"no-soft-float", -256},    \
+   {"long-load-store", 512},   \
+   {"no-long-load-store", -512},\
+   {"fast-indirect-calls", 1024},\
+   {"no-fast-indirect-calls", -1024},\
+   {"linker-opt", 0},          \
+   { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}}
 
 #ifndef TARGET_DEFAULT
 #define TARGET_DEFAULT 0x88            /* TARGET_GAS + TARGET_JUMP_IN_DELAY */
 #endif
 
+#ifndef TARGET_CPU_DEFAULT
+#define TARGET_CPU_DEFAULT 0
+#endif
+
+#define TARGET_OPTIONS                 \
+{                                      \
+  { "schedule=",       &pa_cpu_string }\
+}
+
+#define OVERRIDE_OPTIONS override_options ()
+
 #define DBX_DEBUGGING_INFO
 #define DEFAULT_GDB_EXTENSIONS 1
 
 /* This is the way other stabs-in-XXX tools do things.  We will be
-   compatable.  */
+   compatible.  */
 #define DBX_BLOCKS_FUNCTION_RELATIVE 1
 
 /* Likewise for linenos.
@@ -134,7 +190,7 @@ extern int target_flags;
    name *first*...  */
 #define DBX_FUNCTION_FIRST
 
-/* Only lables should ever begin in colunm zero.  */
+/* Only labels should ever begin in column zero.  */
 #define ASM_STABS_OP "\t.stabs"
 #define ASM_STABN_OP "\t.stabn"
 
@@ -159,21 +215,36 @@ extern int target_flags;
   ((GET_CODE (X) == PLUS ? OFFSET : 0) \
     + (frame_pointer_needed ? 0 : compute_frame_size (get_frame_size (), 0)))
 
-#if (TARGET_DEFAULT & 1) == 0
+/* gdb needs a null N_SO at the end of each file for scattered loading. */
+
+#undef DBX_OUTPUT_MAIN_SOURCE_FILE_END
+#define DBX_OUTPUT_MAIN_SOURCE_FILE_END(FILE, FILENAME) \
+  text_section (); \
+  if (!TARGET_PORTABLE_RUNTIME) \
+    fputs ("\t.SPACE $TEXT$\n\t.NSUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY\n", FILE); \
+  else \
+    fprintf (FILE, "%s\n", TEXT_SECTION_ASM_OP); \
+  fprintf (FILE,                                                       \
+          "\t.stabs \"\",%d,0,0,L$text_end0000\nL$text_end0000:\n", N_SO)
+
+#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & 1) == 0
 #define CPP_SPEC "%{msnake:-D__hp9000s700 -D_PA_RISC1_1}\
- %{mpa-risc-1-1:-D__hp9000s700 -D_PA_RISC1_1}"
+ %{mpa-risc-1-1:-D__hp9000s700 -D_PA_RISC1_1}\
+ %{!ansi: -D_HPUX_SOURCE -D_HIUX_SOURCE}"
 #else
-#define CPP_SPEC "%{!mpa-risc-1-0:%{!mnosnake:-D__hp9000s700 -D_PA_RISC1_1}}"
+#define CPP_SPEC "%{!mpa-risc-1-0:%{!mnosnake:%{!msoft-float:-D__hp9000s700 -D_PA_RISC1_1}}} %{!ansi: -D_HPUX_SOURCE -D_HIUX_SOURCE}"
 #endif
 
 /* Defines for a K&R CC */
 
 #define CC1_SPEC "%{pg:} %{p:}"
 
-#define LINK_SPEC "-u main"
+#define LINK_SPEC "%{mlinker-opt:-O} %{!shared:-u main} %{shared:-b}"
 
-/* Allow $ in identifiers.  */
-#define DOLLARS_IN_IDENTIFIERS 2
+/* We don't want -lg.  */
+#ifndef LIB_SPEC
+#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}"
+#endif
 
 /* Make gcc agree with <machine/ansi.h> */
 
@@ -182,30 +253,82 @@ extern int target_flags;
 #define WCHAR_TYPE "unsigned int"
 #define WCHAR_TYPE_SIZE 32
 
-/* 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.
-
-   On the PA, it is used to explicitly warn the user that -fpic and -fPIC
-   do not work.  */
-
-#define OVERRIDE_OPTIONS \
-{                                                              \
-  if (flag_pic != 0)                                           \
-    warning ("-fpic and -fPIC are not supported on the PA.");  \
-}
-
 /* Show we can debug even without a frame pointer.  */
 #define CAN_DEBUG_WITHOUT_FP
 
+/* Machine dependent reorg pass.  */
+#define MACHINE_DEPENDENT_REORG(X) pa_reorg(X)
+
 /* Names to predefine in the preprocessor for this target machine.  */
 
-#define CPP_PREDEFINES "-Dhppa -Dhp9000s800 -D__hp9000s800 -Dhp9k8 -Dunix -D_HPUX_SOURCE -Dhp9000 -Dhp800 -Dspectrum -DREVARGV -Asystem(unix) -Asystem(bsd) -Acpu(hppa) -Amachine(hppa)"
+#define CPP_PREDEFINES "-Dhppa -Dhp9000s800 -D__hp9000s800 -Dhp9k8 -Dunix -Dhp9000 -Dhp800 -Dspectrum -DREVARGV -Asystem(unix) -Asystem(bsd) -Acpu(hppa) -Amachine(hppa)"
+
+/* HPUX has a program 'chatr' to list the dependencies of dynamically
+   linked executables and shared libraries.  */
+#define LDD_SUFFIX "chatr"
+/* Look for lines like "dynamic   /usr/lib/X11R5/libX11.sl"
+   or "static    /usr/lib/X11R5/libX11.sl". 
+
+   HPUX 10.20 also has lines like "static branch prediction ..."
+   so we filter that out explcitly.
+
+   We also try to bound our search for libraries with marker
+   lines.  What a pain.  */
+#define PARSE_LDD_OUTPUT(PTR)                                  \
+do {                                                           \
+  static int in_shlib_list = 0;                                        \
+  while (*PTR == ' ') PTR++;                                   \
+  if (strncmp (PTR, "shared library list:",                    \
+              sizeof ("shared library list:") - 1) == 0)       \
+    {                                                          \
+      PTR = 0;                                                 \
+      in_shlib_list = 1;                                       \
+    }                                                          \
+  else if (strncmp (PTR, "shared library binding:",            \
+                   sizeof ("shared library binding:") - 1) == 0)\
+    {                                                          \
+      PTR = 0;                                                 \
+      in_shlib_list = 0;                                       \
+    }                                                          \
+  else if (strncmp (PTR, "static branch prediction disabled",  \
+                   sizeof ("static branch prediction disabled") - 1) == 0)\
+    {                                                          \
+      PTR = 0;                                                 \
+      in_shlib_list = 0;                                       \
+    }                                                          \
+  else if (in_shlib_list                                       \
+          &&  strncmp (PTR, "dynamic", sizeof ("dynamic") - 1) == 0) \
+    {                                                          \
+      PTR += sizeof ("dynamic") - 1;                           \
+      while (*p == ' ') PTR++;                                 \
+    }                                                          \
+  else if (in_shlib_list                                       \
+          && strncmp (PTR, "static", sizeof ("static") - 1) == 0) \
+    {                                                          \
+      PTR += sizeof ("static") - 1;                            \
+      while (*p == ' ') PTR++;                                 \
+    }                                                          \
+  else                                                         \
+    PTR = 0;                                                   \
+} while (0)
 \f
 /* target machine storage layout */
 
+/* Define for cross-compilation from a host with a different float format
+   or endianness (e.g. VAX, x86).  */
+#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) < 4)     \
+    (MODE) = SImode;
+
 /* Define this if most significant bit is lowest numbered
    in instructions that operate on numbered bit-fields.  */
 #define BITS_BIG_ENDIAN 1
@@ -216,8 +339,6 @@ extern int target_flags;
 
 /* Define this if most significant word of a multiword number is lowest
    numbered.  */
-/* For the HP-PA we can decide arbitrarily
-   since there are no machine instructions for them.  */
 #define WORDS_BIG_ENDIAN 1
 
 /* number of bits in an addressable storage unit */
@@ -243,8 +364,12 @@ extern int target_flags;
    Don't define this if it is equal to PARM_BOUNDARY */
 #define MAX_PARM_BOUNDARY 64
 
-/* Boundary (in *bits*) on which stack pointer should be aligned.  */
-#define STACK_BOUNDARY 512
+/* Boundary (in *bits*) on which stack pointer is always aligned;
+   certain optimizations in combine depend on this.
+
+   GCC for the PA always rounds its stacks to a 512bit boundary,
+   but that happens late in the compilation process.  */
+#define STACK_BOUNDARY 64
 
 /* Allocation boundary (in *bits*) for the code of a function.  */
 #define FUNCTION_BOUNDARY 32
@@ -322,7 +447,7 @@ extern int target_flags;
    Reg 23-26   = Temporary/Parameter Registers
    Reg 27      = Global Data Pointer (hp)
    Reg 28      = Temporary/???/Return Value register
-   Reg 29      = Temporary/Static Chain/Return Value register
+   Reg 29      = Temporary/Static Chain/Return Value register #2
    Reg 30      = stack pointer
    Reg 31      = Temporary/Millicode Return Pointer (hp)
 
@@ -388,13 +513,16 @@ extern int target_flags;
       for (i = 33; i < 88; i += 2)             \
        fixed_regs[i] = call_used_regs[i] = 1;  \
     }                                          \
-  else if (TARGET_DISABLE_FPREGS)              \
+  if (TARGET_DISABLE_FPREGS || TARGET_SOFT_FLOAT)\
     {                                          \
       for (i = 32; i < 88; i++)                \
        fixed_regs[i] = call_used_regs[i] = 1;  \
     }                                          \
   if (flag_pic)                                        \
-    fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;   \
+    {                                          \
+      fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \
+      fixed_regs[PIC_OFFSET_TABLE_REGNUM_SAVED] = 1;\
+    }                                          \
 }
 
 /* Allocate the call used registers first.  This should minimize
@@ -407,10 +535,10 @@ extern int target_flags;
 #define REG_ALLOC_ORDER \
  {                                     \
   /* caller-saved fp regs.  */         \
-  40, 41, 42, 43, 44, 45, 46, 47,      \
   68, 69, 70, 71, 72, 73, 74, 75,      \
   76, 77, 78, 79, 80, 81, 82, 83,      \
   84, 85, 86, 87,                      \
+  40, 41, 42, 43, 44, 45, 46, 47,      \
   32, 33, 34, 35, 36, 37, 38, 39,      \
   /* caller-saved general regs.  */    \
   19, 20, 21, 22, 23, 24, 25, 26,      \
@@ -471,9 +599,9 @@ extern int target_flags;
 /* Base register for access to local variables of the function.  */
 #define FRAME_POINTER_REGNUM 3
 
-/* Value should be nonzero if functions must have frame pointers. */
-#define FRAME_POINTER_REQUIRED (current_function_calls_alloca)
-
+/* Value should be nonzero if functions must have frame pointers.  */
+#define FRAME_POINTER_REQUIRED \
+  (current_function_calls_alloca)
 
 /* C statement to store the difference between the frame pointer
    and the stack pointer values immediately after the function prologue.
@@ -495,12 +623,16 @@ extern int target_flags;
    data references.  */
 
 #define PIC_OFFSET_TABLE_REGNUM 19
+#define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED 1
 
-#define FINALIZE_PIC finalize_pic ()
+/* Register into which we save the PIC_OFFEST_TABLE_REGNUM so that it
+   can be restore across function calls.  */
+#define PIC_OFFSET_TABLE_REGNUM_SAVED 4
 
 /* SOM ABI says that objects larger than 64 bits are returned in memory.  */
+#define DEFAULT_PCC_STRUCT_RETURN 0
 #define RETURN_IN_MEMORY(TYPE) \
-  (TYPE_MODE (TYPE) == BLKmode || int_size_in_bytes (TYPE) > 8)
+  (int_size_in_bytes (TYPE) > 8)
 
 /* Register in which address to store a structure value
    is passed to a function.  */
@@ -626,11 +758,15 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FP_REGS, GENERAL_OR_FP_REGS,
 #define PREFERRED_RELOAD_CLASS(X,CLASS) (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.  */
+   or out of a register in CLASS in MODE.  If it can be done directly
+   NO_REGS is returned. 
+
+  Avoid doing any work for the common case calls.  */
 
 #define SECONDARY_RELOAD_CLASS(CLASS,MODE,IN) \
-  secondary_reload_class (CLASS, MODE, IN)
+  ((CLASS == BASE_REG_CLASS && GET_CODE (IN) == REG            \
+    && REGNO (IN) < FIRST_PSEUDO_REGISTER)                     \
+   ? NO_REGS : secondary_reload_class (CLASS, MODE, IN))
 
 /* On the PA it is not possible to directly move data between
    GENERAL_REGS and FP_REGS.  */
@@ -715,10 +851,11 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FP_REGS, GENERAL_OR_FP_REGS,
 
 /* Value is 1 if returning from a function call automatically
    pops the arguments described by the number-of-args field in the 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.  */
 
-#define RETURN_POPS_ARGS(FUNTYPE,SIZE) 0
+#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).
@@ -730,26 +867,29 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FP_REGS, GENERAL_OR_FP_REGS,
 
 
 #define FUNCTION_VALUE(VALTYPE, FUNC)  \
-  gen_rtx (REG, TYPE_MODE (VALTYPE), ((TYPE_MODE (VALTYPE) == SFmode ||        \
-                                      TYPE_MODE (VALTYPE) == DFmode) ? \
+  gen_rtx (REG, TYPE_MODE (VALTYPE), ((! TARGET_SOFT_FLOAT                  \
+                                      && (TYPE_MODE (VALTYPE) == SFmode ||  \
+                                          TYPE_MODE (VALTYPE) == DFmode)) ? \
                                      32 : 28))
 
 /* 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, ((MODE) == SFmode || (MODE) == DFmode ? 32 : 28))
+#define LIBCALL_VALUE(MODE)    \
+  gen_rtx (REG, MODE,                                                  \
+          (! TARGET_SOFT_FLOAT                                         \
+           && ((MODE) == SFmode || (MODE) == DFmode) ? 32 : 28))
 
 /* 1 if N is a possible register number for a function value
    as seen by the caller.  */
 
 #define FUNCTION_VALUE_REGNO_P(N) \
-  ((N) == 28 || (N) == 32)
+  ((N) == 28 || (! TARGET_SOFT_FLOAT && (N) == 32))
 
 /* 1 if N is a possible register number for function argument passing.  */
 
 #define FUNCTION_ARG_REGNO_P(N) \
-  (((N) >= 23 && (N) <= 26) || ((N) >= 32 && (N) <= 39))
+  (((N) >= 23 && (N) <= 26) || (! TARGET_SOFT_FLOAT && (N) >= 32 && (N) <= 39))
 \f
 /* Define a data type for recording info about an argument list
    during the scan of that argument list.  This data type should
@@ -762,7 +902,7 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FP_REGS, GENERAL_OR_FP_REGS,
    if any, which holds the structure-value-address).
    Thus 4 or more means all following args should go on the stack.  */
 
-struct hppa_args {int words, nargs_prototype; };
+struct hppa_args {int words, nargs_prototype, indirect; };
 
 #define CUMULATIVE_ARGS struct hppa_args
 
@@ -770,8 +910,9 @@ struct hppa_args {int words, nargs_prototype; };
    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) \
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
   (CUM).words = 0,                                                     \
+  (CUM).indirect = INDIRECT,                                           \
   (CUM).nargs_prototype = (FNTYPE && TYPE_ARG_TYPES (FNTYPE)           \
                           ? (list_length (TYPE_ARG_TYPES (FNTYPE)) - 1 \
                              + (TYPE_MODE (TREE_TYPE (FNTYPE)) == BLKmode \
@@ -781,10 +922,11 @@ struct hppa_args {int words, nargs_prototype; };
 
 
 /* Similar, but when scanning the definition of a procedure.  We always
-   set NARGS_PROTOTYPE large so we never return an EXPR_LIST.  */
+   set NARGS_PROTOTYPE large so we never return a PARALLEL.  */
 
 #define INIT_CUMULATIVE_INCOMING_ARGS(CUM,FNTYPE,IGNORE) \
   (CUM).words = 0,                             \
+  (CUM).indirect = 0,                          \
   (CUM).nargs_prototype = 1000
 
 /* Figure out the size in words of the function argument. */
@@ -826,9 +968,7 @@ struct hppa_args {int words, nargs_prototype; };
    The caller must make a distinction between calls to explicitly named
    functions and calls through pointers to functions -- the conventions
    are different!  Calls through pointers to functions only use general
-   registers for the first four argument words.  Note the indirect function
-   calling conventions are in effect during TARGET_LONG_CALLS, but 
-   current_call_is_indirect will not be set in such situations. 
+   registers for the first four argument words.
 
    Of course all this is different for the portable runtime model
    HP wants everyone to use for ELF.  Ugh.  Here's a quick description
@@ -860,32 +1000,42 @@ struct hppa_args {int words, nargs_prototype; };
 #define FUNCTION_ARG(CUM, MODE, TYPE, NAMED)                           \
   (4 >= ((CUM).words + FUNCTION_ARG_SIZE ((MODE), (TYPE)))             \
    ? (!TARGET_PORTABLE_RUNTIME || (TYPE) == 0                          \
-      || !FLOAT_MODE_P (MODE) || (CUM).nargs_prototype > 0)            \
+      || !FLOAT_MODE_P (MODE) || TARGET_SOFT_FLOAT                     \
+      || (CUM).nargs_prototype > 0)                                    \
       ? gen_rtx (REG, (MODE),                                          \
                 (FUNCTION_ARG_SIZE ((MODE), (TYPE)) > 1                \
-                 ? (((!(current_call_is_indirect || TARGET_LONG_CALLS) \
+                 ? (((!(CUM).indirect                                  \
                       || TARGET_PORTABLE_RUNTIME)                      \
-                     && (MODE) == DFmode)                              \
+                     && (MODE) == DFmode                               \
+                     && ! TARGET_SOFT_FLOAT)                           \
                     ? ((CUM).words ? 38 : 34)                          \
                     : ((CUM).words ? 23 : 25))                         \
-                 : (((!(current_call_is_indirect || TARGET_LONG_CALLS) \
+                 : (((!(CUM).indirect                                  \
                       || TARGET_PORTABLE_RUNTIME)                      \
-                     && (MODE) == SFmode)                              \
+                     && (MODE) == SFmode                               \
+                     && ! TARGET_SOFT_FLOAT)                           \
                     ? (32 + 2 * (CUM).words)                           \
                     : (27 - (CUM).words - FUNCTION_ARG_SIZE ((MODE),   \
                                                              (TYPE))))))\
    /* We are calling a non-prototyped function with floating point     \
       arguments using the portable conventions.  */                    \
-   : gen_rtx (EXPR_LIST, VOIDmode,                                     \
-             gen_rtx (REG, (MODE),                                     \
-                      (FUNCTION_ARG_SIZE ((MODE), (TYPE)) > 1          \
-                       ? ((CUM).words ? 38 : 34)                       \
-                       : (32 + 2 * (CUM).words))),                     \
-             gen_rtx (REG, (MODE),                                     \
-                      (FUNCTION_ARG_SIZE ((MODE), (TYPE)) > 1          \
-                       ? ((CUM).words ? 23 : 25)                       \
-                       : (27 - (CUM).words - FUNCTION_ARG_SIZE ((MODE),\
-                                                                (TYPE)))))) \
+   : gen_rtx (PARALLEL, (MODE),                                                \
+             gen_rtvec                                                 \
+             (2,                                                       \
+              gen_rtx (EXPR_LIST, VOIDmode,                            \
+                       gen_rtx (REG, (MODE),                           \
+                                (FUNCTION_ARG_SIZE ((MODE), (TYPE)) > 1 \
+                                 ? ((CUM).words ? 38 : 34)             \
+                                 : (32 + 2 * (CUM).words))),           \
+                       const0_rtx),                                    \
+              gen_rtx (EXPR_LIST, VOIDmode,                            \
+                       gen_rtx (REG, (MODE),                           \
+                                (FUNCTION_ARG_SIZE ((MODE), (TYPE)) > 1 \
+                                 ? ((CUM).words ? 23 : 25)             \
+                                 : (27 - (CUM).words -                 \
+                                    FUNCTION_ARG_SIZE ((MODE),         \
+                                                       (TYPE))))),     \
+                       const0_rtx)))                                   \
   /* Pass this parameter in the stack.  */                             \
   : 0)
 
@@ -910,6 +1060,10 @@ struct hppa_args {int words, nargs_prototype; };
 
 #define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED)         \
   ((TYPE) && int_size_in_bytes (TYPE) > 8)
+#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
+  ((TYPE) && int_size_in_bytes (TYPE) > 8)
+
 \f
 extern struct rtx_def *hppa_compare_op0, *hppa_compare_op1;
 extern enum cmp_type hppa_branch_type;
@@ -925,6 +1079,29 @@ extern enum cmp_type hppa_branch_type;
        fprintf (FILE, ",ARGW%d=FR", (ARG1));} while (0)
 #endif
 
+#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+{ char *my_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (THUNK_FNDECL)); \
+  char *target_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (FUNCTION)); \
+  output_function_prologue (FILE, 0); \
+  if (VAL_14_BITS_P (DELTA)) \
+    fprintf (FILE, "\tb %s\n\tldo %d(%%r26),%%r26\n", target_name, DELTA); \
+  else \
+    fprintf (FILE, "\taddil L%%%d,%r26\n\tb %s\n\tldo R%%%d(%%r1),%%r26\n", \
+            DELTA, target_name, DELTA); \
+  fprintf (FILE, "\n\t.EXIT\n\t.PROCEND\n"); \
+}
+
+#define ASM_OUTPUT_FUNCTION_PREFIX(FILE, NAME) \
+  {                                                                    \
+    char *name;                                                                \
+    STRIP_NAME_ENCODING (name, NAME);                                  \
+    if (!TARGET_PORTABLE_RUNTIME && TARGET_GAS && in_section == in_text) \
+      fputs ("\t.NSUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY\n", FILE); \
+    else if (! TARGET_PORTABLE_RUNTIME && TARGET_GAS)                  \
+      fprintf (FILE,                                                   \
+              "\t.SUBSPA %s\n", name);                         \
+  }
+    
 #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
     do { tree fntype = TREE_TYPE (TREE_TYPE (DECL));                   \
         tree tree_type = TREE_TYPE (DECL);                             \
@@ -952,9 +1129,11 @@ extern enum cmp_type hppa_branch_type;
             for (parm = DECL_ARGUMENTS (DECL), i = 0; parm && i < 4;   \
                  parm = TREE_CHAIN (parm))                             \
               {                                                        \
-                if (TYPE_MODE (DECL_ARG_TYPE (parm)) == SFmode)        \
+                if (TYPE_MODE (DECL_ARG_TYPE (parm)) == SFmode         \
+                    && ! TARGET_SOFT_FLOAT)                            \
                   fprintf (FILE, ",ARGW%d=FR", i++);                   \
-                else if (TYPE_MODE (DECL_ARG_TYPE (parm)) == DFmode)   \
+                else if (TYPE_MODE (DECL_ARG_TYPE (parm)) == DFmode    \
+                         && ! TARGET_SOFT_FLOAT)                       \
                   {                                                    \
                     if (i <= 2)                                        \
                       {                                                \
@@ -969,6 +1148,11 @@ extern enum cmp_type hppa_branch_type;
                     int arg_size =                                     \
                       FUNCTION_ARG_SIZE (TYPE_MODE (DECL_ARG_TYPE (parm)),\
                                          DECL_ARG_TYPE (parm));        \
+                    /* Passing structs by invisible reference uses     \
+                       one general register.  */                       \
+                    if (arg_size > 2                                   \
+                        || TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))    \
+                      arg_size = 1;                                    \
                     if (arg_size == 2 && i <= 2)                       \
                       {                                                \
                         if (i == 1) i++;                               \
@@ -990,12 +1174,12 @@ extern enum cmp_type hppa_branch_type;
                 for (; i < 4; i++)                                     \
                   fprintf (FILE, ",ARGW%d=GR", i);                     \
               }                                                        \
-            if (TYPE_MODE (fntype) == DFmode)                          \
-              fprintf (FILE, ",RTNVAL=FR");                            \
-            else if (TYPE_MODE (fntype) == SFmode)                     \
-              fprintf (FILE, ",RTNVAL=FU");                            \
+            if (TYPE_MODE (fntype) == DFmode && ! TARGET_SOFT_FLOAT)   \
+              fputs (",RTNVAL=FR", FILE);                              \
+            else if (TYPE_MODE (fntype) == SFmode && ! TARGET_SOFT_FLOAT) \
+              fputs (",RTNVAL=FU", FILE);                              \
             else if (fntype != void_type_node)                         \
-              fprintf (FILE, ",RTNVAL=GR");                            \
+              fputs (",RTNVAL=GR", FILE);                              \
             fputs ("\n", FILE);                                        \
           }} while (0)
 
@@ -1075,17 +1259,17 @@ extern union tree_node *current_function_decl;
 
 #define TRAMPOLINE_TEMPLATE(FILE) \
   {                                                    \
-    fprintf (FILE, "\tldw      36(0,%%r22),%%r21\n");  \
-    fprintf (FILE, "\tbb,>=,n  %%r21,30,.+16\n");      \
-    fprintf (FILE, "\tdepi     0,31,2,%%r21\n");       \
-    fprintf (FILE, "\tldw      4(0,%%r21),%%r19\n");   \
-    fprintf (FILE, "\tldw      0(0,%%r21),%%r21\n");   \
-    fprintf (FILE, "\tldsid    (0,%%r21),%%r1\n");     \
-    fprintf (FILE, "\tmtsp     %%r1,%%sr0\n");         \
-    fprintf (FILE, "\tbe       0(%%sr0,%%r21)\n");     \
-    fprintf (FILE, "\tldw      40(0,%%r22),%%r29\n");  \
-    fprintf (FILE, "\t.word    0\n");                  \
-    fprintf (FILE, "\t.word    0\n");                  \
+    fputs ("\tldw      36(0,%r22),%r21\n", FILE);      \
+    fputs ("\tbb,>=,n  %r21,30,.+16\n", FILE); \
+    fputs ("\tdepi     0,31,2,%r21\n", FILE);          \
+    fputs ("\tldw      4(0,%r21),%r19\n", FILE);       \
+    fputs ("\tldw      0(0,%r21),%r21\n", FILE);       \
+    fputs ("\tldsid    (0,%r21),%r1\n", FILE); \
+    fputs ("\tmtsp     %r1,%sr0\n", FILE);             \
+    fputs ("\tbe       0(%sr0,%r21)\n", FILE); \
+    fputs ("\tldw      40(0,%r22),%r29\n", FILE);      \
+    fputs ("\t.word    0\n", FILE);                    \
+    fputs ("\t.word    0\n", FILE);                    \
   }
 
 /* Length in units of the trampoline for entering a nested function.
@@ -1129,7 +1313,8 @@ extern union tree_node *current_function_decl;
    Ordinarily they are not call used registers, but they are for
    _builtin_saveregs, so we must make this explicit.  */
 
-#define EXPAND_BUILTIN_SAVEREGS(ARGLIST) (rtx)hppa_builtin_saveregs (ARGLIST)
+extern struct rtx_def *hppa_builtin_saveregs ();
+#define EXPAND_BUILTIN_SAVEREGS(ARGLIST) hppa_builtin_saveregs (ARGLIST)
 
 \f
 /* Addressing modes, and classification of registers for them.  */
@@ -1185,8 +1370,9 @@ extern union tree_node *current_function_decl;
    floating-point, except for floating-point zero.  */
 
 #define LEGITIMATE_CONSTANT_P(X)               \
-  (GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
-    || (X) == CONST0_RTX (GET_MODE (X)))
+  ((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT        \
+    || (X) == CONST0_RTX (GET_MODE (X)))       \
+   && !(flag_pic && function_label_operand (X, VOIDmode)))
 
 /* Subroutine for EXTRA_CONSTRAINT.
 
@@ -1207,10 +1393,6 @@ extern union tree_node *current_function_decl;
    these things in insns and then not re-recognize the insns, causing
    constrain_operands to fail.
 
-   Also note `Q' accepts any memory operand during the reload pass.
-   This includes out-of-range displacements in reg+d addressing.
-   This makes for better code.  (??? For 2.5 address this issue).
-
    `R' is unused.
 
    `S' is unused.
@@ -1219,16 +1401,29 @@ extern union tree_node *current_function_decl;
 #define EXTRA_CONSTRAINT(OP, C)                                \
   ((C) == 'Q' ?                                                \
    (IS_RELOADING_PSEUDO_P (OP)                         \
-    || (GET_CODE (OP) == MEM                           \
-       && reload_in_progress)                          \
     || (GET_CODE (OP) == MEM                           \
-       && memory_address_p (GET_MODE (OP), XEXP (OP, 0))\
-       && ! symbolic_memory_operand (OP, VOIDmode)))   \
+       && (memory_address_p (GET_MODE (OP), XEXP (OP, 0))\
+           || reload_in_progress)                      \
+       && ! symbolic_memory_operand (OP, VOIDmode)     \
+        && !(GET_CODE (XEXP (OP, 0)) == PLUS           \
+            && (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT\
+                || GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT))))\
+   : ((C) == 'R' ?                                     \
+     (GET_CODE (OP) == MEM                             \
+      && GET_CODE (XEXP (OP, 0)) == PLUS               \
+      && (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT    \
+         || GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT) \
+      && (move_operand (OP, GET_MODE (OP))             \
+         || memory_address_p (GET_MODE (OP), XEXP (OP, 0))\
+         || reload_in_progress))                       \
    : ((C) == 'T' ?                                     \
       (GET_CODE (OP) == MEM                            \
        /* Using DFmode forces only short displacements \
          to be recognized as valid in reg+d addresses.  */\
-       && memory_address_p (DFmode, XEXP (OP, 0))) : 0))
+       && memory_address_p (DFmode, XEXP (OP, 0))      \
+       && !(GET_CODE (XEXP (OP, 0)) == PLUS            \
+           && (GET_CODE (XEXP (XEXP (OP, 0), 0)) == MULT\
+               || GET_CODE (XEXP (XEXP (OP, 0), 1)) == MULT))) : 0)))
 
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
    and check its validity for a certain class.
@@ -1307,9 +1502,7 @@ extern union tree_node *current_function_decl;
              && REG_OK_FOR_BASE_P (XEXP (X, 1)))       \
            goto ADDR;                                  \
          else if (flag_pic == 1                        \
-                  && GET_CODE (XEXP (X, 1)) != REG     \
-                  && GET_CODE (XEXP (X, 1)) != LO_SUM  \
-                  && GET_CODE (XEXP (X, 1)) != MEM)    \
+                  && GET_CODE (XEXP (X, 1)) == SYMBOL_REF)\
            goto ADDR;                                  \
        }                                               \
       else if (REG_P (XEXP (X, 0))                     \
@@ -1320,29 +1513,48 @@ extern union tree_node *current_function_decl;
        base = XEXP (X, 1), index = XEXP (X, 0);        \
       if (base != 0)                                   \
        if (GET_CODE (index) == CONST_INT               \
-           && ((INT_14_BITS (index) && (MODE) != SFmode && (MODE) != DFmode) \
+           && ((INT_14_BITS (index)                    \
+                && (TARGET_SOFT_FLOAT                  \
+                    || ((MODE) != SFmode && (MODE) != DFmode))) \
                || INT_5_BITS (index)))                 \
          goto ADDR;                                    \
+      if (! TARGET_SOFT_FLOAT                          \
+         && base                                       \
+         && (mode == SFmode || mode == DFmode)         \
+         && GET_CODE (index) == MULT                   \
+         && GET_CODE (XEXP (index, 0)) == REG          \
+         && REG_OK_FOR_BASE_P (XEXP (index, 0))        \
+         && GET_CODE (XEXP (index, 1)) == CONST_INT    \
+         && INTVAL (XEXP (index, 1)) == (mode == SFmode ? 4 : 8))\
+       goto ADDR;                                      \
     }                                                  \
   else if (GET_CODE (X) == LO_SUM                      \
           && GET_CODE (XEXP (X, 0)) == REG             \
           && REG_OK_FOR_BASE_P (XEXP (X, 0))           \
           && CONSTANT_P (XEXP (X, 1))                  \
-          && (MODE) != SFmode                          \
-          && (MODE) != DFmode)                         \
+          && (TARGET_SOFT_FLOAT                        \
+              || ((MODE) != SFmode                     \
+                  && (MODE) != DFmode)))               \
     goto ADDR;                                         \
   else if (GET_CODE (X) == LO_SUM                      \
           && GET_CODE (XEXP (X, 0)) == SUBREG          \
           && GET_CODE (SUBREG_REG (XEXP (X, 0))) == REG\
           && REG_OK_FOR_BASE_P (SUBREG_REG (XEXP (X, 0)))\
           && CONSTANT_P (XEXP (X, 1))                  \
-          && (MODE) != SFmode                          \
-          && (MODE) != DFmode)                         \
+          && (TARGET_SOFT_FLOAT                        \
+              || ((MODE) != SFmode                     \
+                  && (MODE) != DFmode)))               \
     goto ADDR;                                         \
   else if (GET_CODE (X) == LABEL_REF                   \
           || (GET_CODE (X) == CONST_INT                \
               && INT_5_BITS (X)))                      \
     goto ADDR;                                         \
+  /* Needed for -fPIC */                               \
+  else if (GET_CODE (X) == LO_SUM                      \
+          && GET_CODE (XEXP (X, 0)) == REG             \
+          && REG_OK_FOR_BASE_P (XEXP (X, 0))           \
+          && GET_CODE (XEXP (X, 1)) == UNSPEC)         \
+    goto ADDR;                                         \
 }
 \f
 /* Try machine-dependent ways of modifying an illegitimate address
@@ -1396,6 +1608,7 @@ extern struct rtx_def *hppa_legitimize_address ();
   (TREE_CODE (DECL) == FUNCTION_DECL                                   \
    || (TREE_CODE (DECL) == VAR_DECL                                    \
        && TREE_READONLY (DECL) && ! TREE_SIDE_EFFECTS (DECL)           \
+       && (! DECL_INITIAL (DECL) || ! reloc_needed (DECL_INITIAL (DECL))) \
        && !flag_pic)                                                   \
    || (*tree_code_type[(int) TREE_CODE (DECL)] == 'c'                  \
        && !(TREE_CODE (DECL) == STRING_CST && flag_writable_strings)))
@@ -1414,7 +1627,7 @@ do                                                        \
          _rtl = TREE_CST_RTL (DECL);                   \
        SYMBOL_REF_FLAG (XEXP (_rtl, 0)) = 1;           \
        if (TREE_CODE (DECL) == FUNCTION_DECL)          \
-         hppa_encode_label (XEXP (DECL_RTL (DECL), 0));\
+         hppa_encode_label (XEXP (DECL_RTL (DECL), 0), 0);\
       }                                                        \
   }                                                    \
 while (0)
@@ -1427,6 +1640,37 @@ while (0)
                             1 + (SYMBOL_NAME)[1] == '@'\
                             : (SYMBOL_NAME)[0] == '@'))
 
+/* On hpux10, the linker will give an error if we have a reference
+   in the read-only data section to a symbol defined in a shared
+   library.  Therefore, expressions that might require a reloc can
+   not be placed in the read-only data section.  */
+#define SELECT_SECTION(EXP,RELOC) \
+  if (TREE_CODE (EXP) == VAR_DECL \
+      && TREE_READONLY (EXP) \
+      && !TREE_THIS_VOLATILE (EXP) \
+      && DECL_INITIAL (EXP) \
+      && (DECL_INITIAL (EXP) == error_mark_node \
+          || TREE_CONSTANT (DECL_INITIAL (EXP))) \
+      && !reloc) \
+    readonly_data_section (); \
+  else if (TREE_CODE_CLASS (TREE_CODE (EXP)) == 'c' \
+          && !(TREE_CODE (EXP) == STRING_CST && flag_writable_strings) \
+          && !reloc) \
+    readonly_data_section (); \
+  else \
+    data_section ();
+   
+/* Arghh.  This is used for stuff in the constant pool; this may include
+   function addresses on the PA, which during PIC code generation must
+   reside in the data space.  Unfortunately, there's no way to determine
+   if a particular label in the constant pool refers to a function address.
+   So just force everything into the data space during PIC generation.  */
+#define SELECT_RTX_SECTION(RTX,MODE)   \
+  if (flag_pic)                                \
+    data_section ();                   \
+  else                                 \
+    readonly_data_section ();
+
 /* Specify the machine mode that this machine uses
    for the index in the tablejump instruction.  */
 #define CASE_VECTOR_MODE DImode
@@ -1450,6 +1694,11 @@ while (0)
    in one reasonably fast instruction.  */
 #define MOVE_MAX 8
 
+/* Higher than the default as we prefer to use simple move insns
+   (better scheduling and delay slot filling) and because our
+   built-in block move is really a 2X unrolled loop.  */
+#define MOVE_RATIO 4
+
 /* Define if operations between registers always perform the operation
    on the full register even if a narrower mode is specified.  */
 #define WORD_REGISTER_OPERATIONS
@@ -1464,7 +1713,7 @@ while (0)
 #define SLOW_BYTE_ACCESS 1
 
 /* Do not break .stabs pseudos into continuations.  */
-#define DBX_CONTIN_LENGTH 0
+#define DBX_CONTIN_LENGTH 4000
 
 /* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
    is done just by pretending it is already truncated.  */
@@ -1564,27 +1813,61 @@ while (0)
    switch on CODE.  The purpose for the cost of MULT is to encourage
    `synth_mult' to find a synthetic multiply when reasonable.  */
 
-#define RTX_COSTS(X,CODE,OUTER_CODE) \
-  case MULT:                                                   \
-    return TARGET_SNAKE && ! TARGET_DISABLE_FPREGS             \
-      ? COSTS_N_INSNS (8) : COSTS_N_INSNS (20);                \
-  case DIV:                                                    \
-  case UDIV:                                                   \
-  case MOD:                                                    \
-  case UMOD:                                                   \
-    return COSTS_N_INSNS (60);                                 \
-  case PLUS:                                                   \
-    if (GET_CODE (XEXP (X, 0)) == MULT                         \
-       && shadd_operand (XEXP (XEXP (X, 0), 1), VOIDmode))     \
-      return (2 + rtx_cost (XEXP (XEXP (X, 0), 0), OUTER_CODE) \
-             + rtx_cost (XEXP (X, 1), OUTER_CODE));            \
-    break;
+#define RTX_COSTS(X,CODE,OUTER_CODE)                                   \
+  case MULT:                                                           \
+    if (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT)                   \
+      return COSTS_N_INSNS (3);                                                \
+    return (TARGET_SNAKE && ! TARGET_DISABLE_FPREGS && ! TARGET_SOFT_FLOAT) \
+           ? COSTS_N_INSNS (8) : COSTS_N_INSNS (20);   \
+  case DIV:                                                            \
+    if (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT)                   \
+      return COSTS_N_INSNS (14);                                       \
+  case UDIV:                                                           \
+  case MOD:                                                            \
+  case UMOD:                                                           \
+    return COSTS_N_INSNS (60);                                         \
+  case PLUS: /* this includes shNadd insns */                          \
+  case MINUS:                                                          \
+    if (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT)                   \
+      return COSTS_N_INSNS (3);                                                \
+    return COSTS_N_INSNS (1);                                          \
+  case ASHIFT:                                                         \
+  case ASHIFTRT:                                                       \
+  case LSHIFTRT:                                                       \
+    return COSTS_N_INSNS (1);
 
 /* Adjust the cost of dependencies.  */
 
 #define ADJUST_COST(INSN,LINK,DEP,COST) \
   (COST) = pa_adjust_cost (INSN, LINK, DEP, COST)
 
+/* Adjust scheduling priorities.  We use this to try and keep addil
+   and the next use of %r1 close together.  */
+#define ADJUST_PRIORITY(PREV) \
+  {                                                            \
+    rtx set = single_set (PREV);                               \
+    rtx src, dest;                                             \
+    if (set)                                                   \
+      {                                                                \
+        src = SET_SRC (set);                                   \
+       dest = SET_DEST (set);                                  \
+       if (GET_CODE (src) == LO_SUM                            \
+           && symbolic_operand (XEXP (src, 1), VOIDmode)       \
+           && ! read_only_operand (XEXP (src, 1), VOIDmode))   \
+         INSN_PRIORITY (PREV) >>= 3;                           \
+        else if (GET_CODE (src) == MEM                         \
+                && GET_CODE (XEXP (src, 0)) == LO_SUM          \
+                && symbolic_operand (XEXP (XEXP (src, 0), 1), VOIDmode)\
+                && ! read_only_operand (XEXP (XEXP (src, 0), 1), VOIDmode))\
+         INSN_PRIORITY (PREV) >>= 1;                           \
+       else if (GET_CODE (dest) == MEM                         \
+                && GET_CODE (XEXP (dest, 0)) == LO_SUM         \
+                && symbolic_operand (XEXP (XEXP (dest, 0), 1), VOIDmode)\
+                && ! read_only_operand (XEXP (XEXP (dest, 0), 1), VOIDmode))\
+         INSN_PRIORITY (PREV) >>= 3;                           \
+      }                                                                \
+  }
+
 /* Handling the special cases is going to get too complicated for a macro,
    just call `pa_adjust_insn_length' to do the real work.  */
 #define ADJUST_INSN_LENGTH(INSN, LENGTH)       \
@@ -1630,14 +1913,14 @@ while (0)
 /* Output at beginning of assembler file.  */
 
 #define ASM_FILE_START(FILE) \
-do { fprintf (FILE, "\t.SPACE $PRIVATE$\n\
+do { fputs ("\t.SPACE $PRIVATE$\n\
 \t.SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31\n\
 \t.SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82\n\
 \t.SPACE $TEXT$\n\
 \t.SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44\n\
 \t.SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY\n\
 \t.IMPORT $global$,DATA\n\
-\t.IMPORT $$dyncall,MILLICODE\n");\
+\t.IMPORT $$dyncall,MILLICODE\n", FILE);\
      if (profile_flag)\
        fprintf (FILE, "\t.IMPORT _mcount, CODE\n");\
      if (write_symbols != NO_DEBUG) \
@@ -1655,7 +1938,7 @@ do { fprintf (FILE, "\t.SPACE $PRIVATE$\n\
 #define ASM_APP_OFF ""
 
 /* We don't yet know how to identify GCC to HP-PA machines.  */
-#define ASM_IDENTIFY_GCC(FILE) fprintf (FILE, "; gcc_compiled.:\n")
+#define ASM_IDENTIFY_GCC(FILE) fputs ("; gcc_compiled.:\n", FILE)
 
 /* Output before code.  */
 
@@ -1680,27 +1963,70 @@ do { fprintf (FILE, "\t.SPACE $PRIVATE$\n\
 
 /* Define the .bss section for ASM_OUTPUT_LOCAL to use. */
 
-#define EXTRA_SECTIONS in_bss, in_readonly_data
+#ifndef CTORS_SECTION_FUNCTION
+#define EXTRA_SECTIONS in_readonly_data
+#define CTORS_SECTION_FUNCTION
+#define DTORS_SECTION_FUNCTION
+#else
+#define EXTRA_SECTIONS in_readonly_data, in_ctors, in_dtors
+#endif
+
+/* Switch into a generic section.
+   This is currently only used to support section attributes.
+
+   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.  */
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME) \
+  if (DECL && TREE_CODE (DECL) == FUNCTION_DECL)               \
+    {                                                          \
+      fputs ("\t.SPACE $TEXT$\n", FILE);                       \
+      fprintf (FILE,                                           \
+              "\t.SUBSPA %s%s%s,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY,SORT=24\n",\
+              TARGET_GAS ? "" : "$", NAME, TARGET_GAS ? "" : "$"); \
+    }                                                          \
+  else if (DECL && TREE_READONLY (DECL))                       \
+    {                                                          \
+      fputs ("\t.SPACE $TEXT$\n", FILE);                       \
+      fprintf (FILE,                                           \
+              "\t.SUBSPA %s%s%s,QUAD=0,ALIGN=8,ACCESS=44,SORT=16\n", \
+              TARGET_GAS ? "" : "$", NAME, TARGET_GAS ? "" : "$"); \
+    }                                                          \
+  else                                                         \
+    {                                                          \
+      fputs ("\t.SPACE $PRIVATE$\n", FILE);                    \
+      fprintf (FILE,                                           \
+              "\t.SUBSPA %s,QUAD=1,ALIGN=8,ACCESS=31,SORT=16\n", \
+              TARGET_GAS ? "" : "$", NAME, TARGET_GAS ? "" : "$"); \
+    }
+
+/* FIXME: HPUX ld generates incorrect GOT entries for "T" fixups
+   which reference data within the $TEXT$ space (for example constant
+   strings in the $LIT$ subspace).
+
+   The assemblers (GAS and HP as) both have problems with handling
+   the difference of two symbols which is the other correct way to
+   reference constant data during PIC code generation.
+
+   So, there's no way to reference constant data which is in the
+   $TEXT$ space during PIC generation.  Instead place all constant
+   data into the $PRIVATE$ subspace (this reduces sharing, but it
+   works correctly).  */
 
 #define EXTRA_SECTION_FUNCTIONS                                                \
 void                                                                   \
-bss_section ()                                                         \
-{                                                                      \
-  if (in_section != in_bss)                                            \
-    {                                                                  \
-      fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);              \
-      in_section = in_bss;                                             \
-    }                                                                  \
-}                                                                      \
-void                                                                   \
 readonly_data ()                                                       \
 {                                                                      \
   if (in_section != in_readonly_data)                                  \
     {                                                                  \
-      fprintf (asm_out_file, "%s\n", READONLY_DATA_ASM_OP);            \
+      if (flag_pic)                                                    \
+       fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);            \
+      else                                                             \
+       fprintf (asm_out_file, "%s\n", READONLY_DATA_ASM_OP);           \
       in_section = in_readonly_data;                                   \
     }                                                                  \
-}
+}                                                                      \
+CTORS_SECTION_FUNCTION                                                 \
+DTORS_SECTION_FUNCTION
 
 
 /* How to refer to registers in assembler output.
@@ -1750,36 +2076,36 @@ readonly_data ()                                                        \
        fputc ('\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.  */
+   defined for reference from other files.
+
+   We call assemble_name, which in turn sets TREE_SYMBOL_REFERENCED.  This
+   macro will restore the original value of TREE_SYMBOL_REFERENCED to avoid
+   placing useless function definitions in the output file.  */
 
 #define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME)  \
-  do { fputs ("\t.IMPORT ", FILE);                             \
+  do { int save_referenced;                                    \
+       save_referenced = TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (DECL)); \
+       fputs ("\t.IMPORT ", FILE);                                     \
         assemble_name (FILE, NAME);                            \
        if (FUNCTION_NAME_P (NAME))                                     \
         fputs (",CODE\n", FILE);                               \
        else                                                    \
         fputs (",DATA\n", FILE);                               \
-     } while (0)
-
-/* hpux ld doesn't output the object file name, or anything useful at
-   all, to indicate the start of an object file's symbols. This screws
-   up gdb, so we'll output this magic cookie at the end of an object
-   file with debugging symbols */
-
-#define ASM_FILE_END(FILE) \
-  do { if (write_symbols == DBX_DEBUG)\
-        { fputs (TEXT_SECTION_ASM_OP, FILE);\
-          fputs ("\t.stabs \"end_file.\",4,0,0,Ltext_end\nLtext_end:\n",\
-                 (FILE));\
-        }\
+       TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (DECL)) = save_referenced; \
      } while (0)
 
 /* The bogus HP assembler requires ALL external references to be
    "imported", even library calls. They look a bit different, so
-   here's this macro. */
+   here's this macro.
+
+   Also note not all libcall names are passed to ENCODE_SECTION_INFO
+   (__main for example).  To make sure all libcall names have section
+   info recorded in them, we do it here.  */
 
 #define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, RTL) \
   do { fputs ("\t.IMPORT ", FILE);                                     \
+       if (!function_label_operand (RTL, VOIDmode))                    \
+        hppa_encode_label (RTL, 1);                                    \
        assemble_name (FILE, XSTR ((RTL), 0));                          \
        fputs (",CODE\n", FILE);                                                \
      } while (0)
@@ -1819,41 +2145,44 @@ readonly_data ()                                                        \
 /* This is how to output an assembler line defining a `double' constant.  */
 
 #define ASM_OUTPUT_DOUBLE(FILE,VALUE)  \
-  do { union { double d; int i[2];} __u;       \
-    __u.d = (VALUE);                           \
-    fprintf (FILE, "\t; .double %.20e\n\t.word %d ; = 0x%x\n\t.word %d ; = 0x%x\n",    \
-            __u.d, __u.i[0], __u.i[0], __u.i[1], __u.i[1]);    \
-  } while (0)
+  do { long l[2];                                                      \
+       REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l);                         \
+       fprintf (FILE, "\t.word 0x%lx\n\t.word 0x%lx\n", l[0], l[1]);   \
+     } while (0)
 
 /* This is how to output an assembler line defining a `float' constant.  */
 
 #define ASM_OUTPUT_FLOAT(FILE,VALUE)  \
-  do { union { float f; int i;} __u;           \
-    __u.f = (VALUE);                           \
-    fprintf (FILE, "\t; .float %.12e\n\t.word %d ; = 0x%x\n", __u.f, __u.i, __u.i); \
-  } while (0)
+  do { long l;                                                         \
+       REAL_VALUE_TO_TARGET_SINGLE (VALUE, l);                         \
+       fprintf (FILE, "\t.word 0x%lx\n", l);                           \
+     } while (0)
+
+/* This is how to output an assembler line defining an `int' constant. 
 
-/* This is how to output an assembler line defining an `int' constant.  */
+   This is made more complicated by the fact that functions must be
+   prefixed by a P% as well as code label references for the exception
+   table -- otherwise the linker chokes.  */
 
 #define ASM_OUTPUT_INT(FILE,VALUE)  \
-{ fprintf (FILE, "\t.word ");                  \
+{ fputs ("\t.word ", FILE);                    \
   if (function_label_operand (VALUE, VOIDmode) \
       && !TARGET_PORTABLE_RUNTIME)             \
-    fprintf (FILE, "P%%");                     \
+    fputs ("P%", FILE);                                \
   output_addr_const (FILE, (VALUE));           \
-  fprintf (FILE, "\n");}
+  fputs ("\n", FILE);}
 
 /* Likewise for `short' and `char' constants.  */
 
 #define ASM_OUTPUT_SHORT(FILE,VALUE)  \
-( fprintf (FILE, "\t.half "),                  \
+( fputs ("\t.half ", FILE),                    \
   output_addr_const (FILE, (VALUE)),           \
-  fprintf (FILE, "\n"))
+  fputs ("\n", FILE))
 
 #define ASM_OUTPUT_CHAR(FILE,VALUE)  \
-( fprintf (FILE, "\t.byte "),                  \
+( fputs ("\t.byte ", FILE),                    \
   output_addr_const (FILE, (VALUE)),           \
-  fprintf (FILE, "\n"))
+  fputs ("\n", FILE))
 
 /* This is how to output an assembler line for a numeric constant byte.  */
 
@@ -1878,7 +2207,7 @@ readonly_data ()                                                  \
 /* This is how to output an element of a case-vector that is relative.
    This must be defined correctly as it is used when generating PIC code.
 
-   I belive it safe to use the same definition as ASM_OUTPUT_ADDR_VEC_ELT
+   I believe it safe to use the same definition as ASM_OUTPUT_ADDR_VEC_ELT
    on the PA since ASM_OUTPUT_ADDR_VEC_ELT uses pc-relative jump instructions
    rather than a table of absolute addresses.  */
 
@@ -1980,8 +2309,15 @@ readonly_data ()                                                 \
       fprintf (FILE, "%d(0,%s)", offset, reg_names [REGNO (base)]);    \
       break;                                                           \
     case LO_SUM:                                                       \
-      fputs ("R'", FILE);                                              \
-      output_global_address (FILE, XEXP (addr, 1));                    \
+      if (!symbolic_operand (XEXP (addr, 1)))                          \
+       fputs ("R'", FILE);                                             \
+      else if (flag_pic == 0)                                          \
+       fputs ("RR'", FILE);                                            \
+      else if (flag_pic == 1)                                          \
+       abort ();                                                       \
+      else if (flag_pic == 2)                                          \
+       fputs ("RT'", FILE);                                            \
+      output_global_address (FILE, XEXP (addr, 1), 0);                 \
       fputs ("(", FILE);                                               \
       output_operand (XEXP (addr, 0), 0);                              \
       fputs (")", FILE);                                               \
@@ -2003,10 +2339,14 @@ extern char *output_fp_move_double ();
 extern char *output_block_move ();
 extern char *output_cbranch ();
 extern char *output_bb ();
+extern char *output_bvb ();
 extern char *output_dbra ();
 extern char *output_movb ();
+extern char *output_parallel_movb ();
+extern char *output_parallel_addb ();
 extern char *output_return ();
 extern char *output_call ();
+extern char *output_millicode_call ();
 extern char *output_mul_insn ();
 extern char *output_div_insn ();
 extern char *output_mod_insn ();
@@ -2017,39 +2357,37 @@ extern struct rtx_def *legitimize_pic_address ();
 extern struct rtx_def *gen_cmp_fp ();
 extern void hppa_encode_label ();
 
-extern struct rtx_def *hppa_save_pic_table_rtx;
-
-#if 0
-#define PREDICATE_CODES \
-  {"reg_or_0_operand", {SUBREG, REG, CONST_INT}},                      \
-  {"reg_or_cint_move_operand", {SUBREG, REG, CONST_INT}},              \
-  {"arith_operand", {SUBREG, REG, CONST_INT}},                         \
-  {"arith32_operand", {SUBREG, REG, CONST_INT}},                       \
-  {"arith11_operand", {SUBREG, REG, CONST_INT}},                       \
-  {"arith5_operand", {SUBREG, REG, CONST_INT}},                                \
-  {"pre_cint_operand", {CONST_INT}},                                   \
-  {"post_cint_operand", {CONST_INT}},                                  \
-  {"int5_operand", {CONST_INT}},                                       \
-  {"uint5_operand", {CONST_INT}},                                      \
-  {"uint32_operand", {CONST_INT}},                                     \
-  {"int11_operand", {CONST_INT}},                                      \
-  {"and_operand", {SUBREG, REG, CONST_INT}},                           \
-  {"ior_operand", {CONST_INT}},                                                \
-  {"lhs_lshift_operand", {SUBREG, REG, CONST_INT}},                    \
-  {"lhs_lshift_cint_operand", {CONST_INT}},                            \
-  {"plus_xor_ior_operator", {PLUS, XOR, IOR}},                         \
-  {"shadd_operand", {CONST_INT}},                                      \
-  {"eq_neq_comparison_operator", {EQ, NE}},                            \
-  {"movb_comparison_operator", {EQ, NE, LT, GE}},                      \
-  {"pc_or_label_operand", {LABEL_REF, PC}},                            \
-  {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}},                        \
-  {"reg_or_nonsymb_mem_operand", {REG, SUBREG, MEM}},                  \
-  {"move_operand", {REG, SUBREG, CONST_INT, MEM}},                     \
-  {"pic_operand", {REG, SUBREG, CONST_INT, SYMBOL_REF, LABEL_REF,      \
-                  CONST, HIGH, PC}},   /* No clue */                   \
-  {"function_label_operand", {SYMBOL_REF}},                            \
-  {"reg_or_0_or_nonsymb_mem_operand", {REG, SUBREG, CONST_INT, MEM}},  \
-  {"div_operand", {REG, CONST_INT}},                                   \
-  {"call_operand_address", {LABEL_REF, SYMBOL_REF, CONST_INT,          \
-                           CONST, HIGH}},
-#endif
+/* Declare functions defined in pa.c and used in templates.  */
+
+extern struct rtx_def *return_addr_rtx ();
+
+/* We want __gcc_plt_call to appear in every program built by
+   gcc, so we make a reference to it out of __main.
+   We use the asm statement to fool the optimizer into not
+   removing the dead (but important) initialization of
+   REFERENCE.  */
+
+#define DO_GLOBAL_DTORS_BODY                   \
+do {                                           \
+  extern void __gcc_plt_call ();               \
+  void (*reference)() = &__gcc_plt_call;       \
+  func_ptr *p;                                 \
+  __asm__ ("" : : "r" (reference));            \
+  for (p = __DTOR_LIST__ + 1; *p; )            \
+    (*p++) ();                                 \
+} while (0)
+
+/* Find the return address associated with the frame given by
+   FRAMEADDR.  */
+#define RETURN_ADDR_RTX(COUNT, FRAMEADDR)                               \
+  (return_addr_rtx (COUNT, FRAMEADDR))
+
+/* Used to mask out junk bits from the return address, such as
+   processor state, interrupt status, condition codes and the like.  */
+#define MASK_RETURN_ADDR                                               \
+  /* The privilege level is in the two low order bits, mask em out     \
+     of the return address.  */                                                \
+  (GEN_INT (0xfffffffc))
+
+/* The number of Pmode words for the setjmp buffer.  */
+#define JMP_BUF_SIZE 50