OSDN Git Service

Stack usage support
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.c
index 76d84ba..9c24f01 100644 (file)
@@ -1,6 +1,7 @@
 /* Subroutines for insn-output.c for HPPA.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
    Contributed by Tim Moore (moore@cs.utah.edu), based on sparc.c
 
 This file is part of GCC.
@@ -26,7 +27,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
-#include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
 #include "insn-attr.h"
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "reload.h"
 #include "integrate.h"
 #include "function.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
 #include "ggc.h"
 #include "recog.h"
@@ -83,16 +84,19 @@ hppa_fpstore_bypass_p (rtx out_insn, rtx in_insn)
 #endif
 #endif
 
+static void pa_option_override (void);
 static void copy_reg_pointer (rtx, rtx);
 static void fix_range (const char *);
 static bool pa_handle_option (size_t, const char *, int);
-static int hppa_address_cost (rtx);
-static bool hppa_rtx_costs (rtx, int, int, int *);
+static int hppa_register_move_cost (enum machine_mode mode, reg_class_t,
+                                   reg_class_t);
+static int hppa_address_cost (rtx, bool);
+static bool hppa_rtx_costs (rtx, int, int, int *, bool);
 static inline rtx force_mode (enum machine_mode, rtx);
 static void pa_reorg (void);
 static void pa_combine_instructions (void);
 static int pa_can_combine_p (rtx, rtx, rtx, int, rtx, rtx, rtx);
-static int forward_branch_p (rtx);
+static bool forward_branch_p (rtx);
 static void compute_zdepwi_operands (unsigned HOST_WIDE_INT, unsigned *);
 static int compute_movmem_length (rtx);
 static int compute_clrmem_length (rtx);
@@ -102,8 +106,11 @@ static void store_reg (int, HOST_WIDE_INT, int);
 static void store_reg_modify (int, int, HOST_WIDE_INT);
 static void load_reg (int, HOST_WIDE_INT, int);
 static void set_reg_plus_d (int, int, HOST_WIDE_INT, int);
+static rtx pa_function_value (const_tree, const_tree, bool);
+static rtx pa_libcall_value (enum machine_mode, const_rtx);
+static bool pa_function_value_regno_p (const unsigned int);
 static void pa_output_function_prologue (FILE *, HOST_WIDE_INT);
-static void update_total_code_bytes (int);
+static void update_total_code_bytes (unsigned int);
 static void pa_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static int pa_adjust_cost (rtx, rtx, rtx, int);
 static int pa_adjust_priority (rtx, int);
@@ -130,6 +137,7 @@ static bool pa_scalar_mode_supported_p (enum machine_mode);
 static bool pa_commutative_p (const_rtx x, int outer_code);
 static void copy_fp_args (rtx) ATTRIBUTE_UNUSED;
 static int length_fp_args (rtx) ATTRIBUTE_UNUSED;
+static rtx hppa_legitimize_address (rtx, rtx, enum machine_mode);
 static inline void pa_file_start_level (void) ATTRIBUTE_UNUSED;
 static inline void pa_file_start_space (int) ATTRIBUTE_UNUSED;
 static inline void pa_file_start_file (int) ATTRIBUTE_UNUSED;
@@ -153,21 +161,25 @@ static bool pa_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
 static int pa_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
                                 tree, bool);
 static struct machine_function * pa_init_machine_status (void);
-static enum reg_class pa_secondary_reload (bool, rtx, enum reg_class,
-                                          enum machine_mode,
-                                          secondary_reload_info *);
+static reg_class_t pa_secondary_reload (bool, rtx, reg_class_t,
+                                       enum machine_mode,
+                                       secondary_reload_info *);
 static void pa_extra_live_on_entry (bitmap);
+static enum machine_mode pa_promote_function_mode (const_tree,
+                                                  enum machine_mode, int *,
+                                                  const_tree, int);
+
+static void pa_asm_trampoline_template (FILE *);
+static void pa_trampoline_init (rtx, tree, rtx);
+static rtx pa_trampoline_adjust_address (rtx);
+static rtx pa_delegitimize_address (rtx);
+static bool pa_print_operand_punct_valid_p (unsigned char);
 
 /* The following extra sections are only used for SOM.  */
 static GTY(()) section *som_readonly_data_section;
 static GTY(()) section *som_one_only_readonly_data_section;
 static GTY(()) section *som_one_only_data_section;
 
-/* Save the operands last given to a compare for use when we
-   generate a scc or bcc insn.  */
-rtx hppa_compare_op0, hppa_compare_op1;
-enum cmp_type hppa_branch_type;
-
 /* Which cpu we are scheduling for.  */
 enum processor_type pa_cpu = TARGET_SCHED_DEFAULT;
 
@@ -191,11 +203,11 @@ unsigned long total_code_bytes;
 /* The last address of the previous function plus the number of bytes in
    associated thunks that have been output.  This is used to determine if
    a thunk can use an IA-relative branch to reach its target function.  */
-static int last_address;
+static unsigned int last_address;
 
 /* Variables to handle plabels that we discover are necessary at assembly
    output time.  They are output after the current function.  */
-struct deferred_plabel GTY(())
+struct GTY(()) deferred_plabel
 {
   rtx internal_label;
   rtx symbol;
@@ -207,6 +219,9 @@ static size_t n_deferred_plabels = 0;
 \f
 /* Initialize the GCC target structure.  */
 
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE pa_option_override
+
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
 #undef TARGET_ASM_ALIGNED_SI_OP
@@ -227,6 +242,16 @@ static size_t n_deferred_plabels = 0;
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE pa_output_function_epilogue
 
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE pa_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE pa_libcall_value
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P pa_function_value_regno_p
+
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS hppa_legitimize_address
+
 #undef TARGET_SCHED_ADJUST_COST
 #define TARGET_SCHED_ADJUST_COST pa_adjust_cost
 #undef TARGET_SCHED_ADJUST_PRIORITY
@@ -257,6 +282,9 @@ static size_t n_deferred_plabels = 0;
 #define TARGET_ASM_FILE_END output_deferred_plabels
 #endif
 
+#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
+#define TARGET_PRINT_OPERAND_PUNCT_VALID_P pa_print_operand_punct_valid_p
+
 #if !defined(USE_COLLECT2)
 #undef TARGET_ASM_CONSTRUCTOR
 #define TARGET_ASM_CONSTRUCTOR pa_asm_out_constructor
@@ -272,6 +300,8 @@ static size_t n_deferred_plabels = 0;
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS pa_init_builtins
 
+#undef TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST hppa_register_move_cost
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS hppa_rtx_costs
 #undef TARGET_ADDRESS_COST
@@ -285,8 +315,8 @@ static size_t n_deferred_plabels = 0;
 #define TARGET_INIT_LIBFUNCS pa_hpux_init_libfuncs
 #endif
 
-#undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE pa_promote_function_mode
 #undef TARGET_PROMOTE_PROTOTYPES
 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
 
@@ -322,6 +352,15 @@ static size_t n_deferred_plabels = 0;
 #undef TARGET_EXTRA_LIVE_ON_ENTRY
 #define TARGET_EXTRA_LIVE_ON_ENTRY pa_extra_live_on_entry
 
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE pa_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT pa_trampoline_init
+#undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
+#define TARGET_TRAMPOLINE_ADJUST_ADDRESS pa_trampoline_adjust_address
+#undef TARGET_DELEGITIMIZE_ADDRESS
+#define TARGET_DELEGITIMIZE_ADDRESS pa_delegitimize_address
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Parse the -mfixed-range= option string.  */
@@ -466,8 +505,10 @@ pa_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
     }
 }
 
-void
-override_options (void)
+/* Implement the TARGET_OPTION_OVERRIDE hook.  */
+
+static void
+pa_option_override (void)
 {
   /* Unconditional branches in the delay slot are not compatible with dwarf2
      call frame information.  There is no benefit in using this optimization
@@ -499,6 +540,17 @@ override_options (void)
   if (flag_pic == 1 || TARGET_64BIT)
     flag_pic = 2;
 
+  /* Disable -freorder-blocks-and-partition as we don't support hot and
+     cold partitioning.  */
+  if (flag_reorder_blocks_and_partition)
+    {
+      inform (input_location,
+              "-freorder-blocks-and-partition does not work "
+              "on this architecture");
+      flag_reorder_blocks_and_partition = 0;
+      flag_reorder_blocks = 1;
+    }
+
   /* We can't guarantee that .dword is available for 32-bit targets.  */
   if (UNITS_PER_WORD == 4)
     targetm.asm_out.aligned_op.di = NULL;
@@ -538,7 +590,7 @@ pa_init_builtins (void)
 static struct machine_function *
 pa_init_machine_status (void)
 {
-  return GGC_CNEW (machine_function);
+  return ggc_alloc_cleared_machine_function ();
 }
 
 /* If FROM is a probable pointer register, mark TO as a probable
@@ -683,7 +735,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
       insn = emit_insn (gen_rtx_SET (VOIDmode, reg, orig));
 
       /* Put a REG_EQUAL note on this insn, so that it can be optimized.  */
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, REG_NOTES (insn));
+      add_reg_note (insn, REG_EQUAL, orig);
 
       /* During and after reload, we need to generate a REG_LABEL_OPERAND note
         and update LABEL_NUSES because this is not done automatically.  */
@@ -714,8 +766,8 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 
       if (function_label_operand (orig, mode))
        {
-         /* Force function label into memory.  */
-         orig = XEXP (force_const_mem (mode, orig), 0);
+         /* Force function label into memory in word mode.  */
+         orig = XEXP (force_const_mem (word_mode, orig), 0);
          /* Load plabel address from DLT.  */
          emit_move_insn (tmp_reg,
                          gen_rtx_PLUS (word_mode, pic_offset_table_rtx,
@@ -871,9 +923,6 @@ legitimize_tls_address (rtx addr)
    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.
 
@@ -1048,7 +1097,7 @@ hppa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
     {
 
       /* First, try and figure out what to use as a base register.  */
-      rtx reg1, reg2, base, idx, orig_base;
+      rtx reg1, reg2, base, idx;
 
       reg1 = XEXP (XEXP (x, 0), 1);
       reg2 = XEXP (x, 1);
@@ -1070,7 +1119,6 @@ hppa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
          && REG_POINTER (reg1))
        {
          base = reg1;
-         orig_base = XEXP (XEXP (x, 0), 1);
          idx = gen_rtx_PLUS (Pmode,
                              gen_rtx_MULT (Pmode,
                                            XEXP (XEXP (XEXP (x, 0), 0), 0),
@@ -1081,7 +1129,6 @@ hppa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
               && REG_POINTER (reg2))
        {
          base = reg2;
-         orig_base = XEXP (x, 1);
          idx = XEXP (x, 0);
        }
 
@@ -1270,6 +1317,32 @@ hppa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
   return orig;
 }
 
+/* Implement the TARGET_REGISTER_MOVE_COST hook.
+
+   Compute extra cost of moving data between one register class
+   and another.
+
+   Make moves from SAR so expensive they should never happen.  We used to
+   have 0xffff here, but that generates overflow in rare cases.
+
+   Copies involving a FP register and a non-FP register are relatively
+   expensive because they must go through memory.
+
+   Other copies are reasonably cheap.  */
+
+static int
+hppa_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+                        reg_class_t from, reg_class_t to)
+{
+  if (from == SHIFT_REGS)
+    return 0x100;
+  else if ((FP_REG_CLASS_P (from) && ! FP_REG_CLASS_P (to))
+           || (FP_REG_CLASS_P (to) && ! FP_REG_CLASS_P (from)))
+    return 16;
+  else
+    return 2;
+}
+
 /* For the HPPA, REG and REG+CONST is cost 0
    and addresses involving symbolic constants are cost 2.
 
@@ -1279,7 +1352,8 @@ hppa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
    as GO_IF_LEGITIMATE_ADDRESS.  */
 
 static int
-hppa_address_cost (rtx X)
+hppa_address_cost (rtx X,
+                  bool speed ATTRIBUTE_UNUSED)
 {
   switch (GET_CODE (X))
     {
@@ -1299,7 +1373,8 @@ hppa_address_cost (rtx X)
    scanned.  In either case, *TOTAL contains the cost result.  */
 
 static bool
-hppa_rtx_costs (rtx x, int code, int outer_code, int *total)
+hppa_rtx_costs (rtx x, int code, int outer_code, int *total,
+               bool speed ATTRIBUTE_UNUSED)
 {
   switch (code)
     {
@@ -1617,7 +1692,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
       /* D might not fit in 14 bits either; for such cases load D into
         scratch reg.  */
       if (GET_CODE (operand1) == MEM
-         && !memory_address_p (Pmode, XEXP (operand1, 0)))
+         && !memory_address_p (GET_MODE (operand0), XEXP (operand1, 0)))
        {
          /* We are reloading the address into the scratch register, so we
             want to make sure the scratch register is a full register.  */
@@ -1679,10 +1754,6 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
                  && !REG_POINTER (operand0)
                  && !HARD_REGISTER_P (operand0))
                copy_reg_pointer (operand0, operand1);
-             else if (REG_POINTER (operand0)
-                      && !REG_POINTER (operand1)
-                      && !HARD_REGISTER_P (operand1))
-               copy_reg_pointer (operand1, operand0);
            }
          
          /* When MEMs are broken out, the REG_POINTER flag doesn't
@@ -1696,12 +1767,8 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
 
              /* Set the register pointer flag and register alignment
                 if the declaration for this memory reference is a
-                pointer type.  Fortran indirect argument references
-                are ignored.  */
-             if (decl
-                 && !(flag_argument_noalias > 1
-                      && TREE_CODE (decl) == INDIRECT_REF
-                      && TREE_CODE (TREE_OPERAND (decl, 0)) == PARM_DECL))
+                pointer type.  */
+             if (decl)
                {
                  tree type;
 
@@ -2214,9 +2281,9 @@ compute_zdepwi_operands (unsigned HOST_WIDE_INT imm, unsigned *op)
   else
     {
       /* Find the width of the bitstring in IMM.  */
-      for (len = 5; len < 32; len++)
+      for (len = 5; len < 32 - lsb; len++)
        {
-         if ((imm & (1 << len)) == 0)
+         if ((imm & ((unsigned HOST_WIDE_INT) 1 << len)) == 0)
            break;
        }
 
@@ -2235,10 +2302,12 @@ compute_zdepwi_operands (unsigned HOST_WIDE_INT imm, unsigned *op)
 void
 compute_zdepdi_operands (unsigned HOST_WIDE_INT imm, unsigned *op)
 {
-  HOST_WIDE_INT lsb, len;
+  int lsb, len, maxlen;
+
+  maxlen = MIN (HOST_BITS_PER_WIDE_INT, 64);
 
   /* Find the least significant set bit in IMM.  */
-  for (lsb = 0; lsb < HOST_BITS_PER_WIDE_INT; lsb++)
+  for (lsb = 0; lsb < maxlen; lsb++)
     {
       if ((imm & 1) != 0)
         break;
@@ -2247,17 +2316,20 @@ compute_zdepdi_operands (unsigned HOST_WIDE_INT imm, unsigned *op)
 
   /* Choose variants based on *sign* of the 5-bit field.  */
   if ((imm & 0x10) == 0)
-    len = ((lsb <= HOST_BITS_PER_WIDE_INT - 4)
-          ? 4 : HOST_BITS_PER_WIDE_INT - lsb);
+    len = (lsb <= maxlen - 4) ? 4 : maxlen - lsb;
   else
     {
       /* Find the width of the bitstring in IMM.  */
-      for (len = 5; len < HOST_BITS_PER_WIDE_INT; len++)
+      for (len = 5; len < maxlen - lsb; len++)
        {
          if ((imm & ((unsigned HOST_WIDE_INT) 1 << len)) == 0)
            break;
        }
 
+      /* Extend length if host is narrow and IMM is negative.  */
+      if (HOST_BITS_PER_WIDE_INT == 32 && len == maxlen - lsb)
+       len += 32;
+
       /* Sign extend IMM as a 5-bit value.  */
       imm = (imm & 0xf) - 0x10;
     }
@@ -3392,11 +3464,9 @@ store_reg (int reg, HOST_WIDE_INT disp, int base)
       insn = emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg));
       if (DO_FRAME_NOTES)
        {
-         REG_NOTES (insn)
-           = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-               gen_rtx_SET (VOIDmode, tmpreg,
-                            gen_rtx_PLUS (Pmode, basereg, delta)),
-                REG_NOTES (insn));
+         add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                       gen_rtx_SET (VOIDmode, tmpreg,
+                                    gen_rtx_PLUS (Pmode, basereg, delta)));
          RTX_FRAME_RELATED_P (insn) = 1;
        }
       dest = gen_rtx_MEM (word_mode, tmpreg);
@@ -3412,16 +3482,13 @@ store_reg (int reg, HOST_WIDE_INT disp, int base)
       dest = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta));
       insn = emit_move_insn (dest, src);
       if (DO_FRAME_NOTES)
-       {
-         REG_NOTES (insn)
-           = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-               gen_rtx_SET (VOIDmode,
-                            gen_rtx_MEM (word_mode,
-                                         gen_rtx_PLUS (word_mode, basereg,
-                                                       delta)),
-                             src),
-                REG_NOTES (insn));
-       }
+       add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                     gen_rtx_SET (VOIDmode,
+                                  gen_rtx_MEM (word_mode,
+                                               gen_rtx_PLUS (word_mode,
+                                                             basereg,
+                                                             delta)),
+                                  src));
     }
 
   if (DO_FRAME_NOTES)
@@ -3481,11 +3548,9 @@ set_reg_plus_d (int reg, int base, HOST_WIDE_INT disp, int note)
       insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
                             gen_rtx_PLUS (Pmode, tmpreg, basereg));
       if (DO_FRAME_NOTES)
-       REG_NOTES (insn)
-         = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-             gen_rtx_SET (VOIDmode, tmpreg,
-                          gen_rtx_PLUS (Pmode, basereg, delta)),
-             REG_NOTES (insn));
+       add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                     gen_rtx_SET (VOIDmode, tmpreg,
+                                  gen_rtx_PLUS (Pmode, basereg, delta)));
     }
   else
     {
@@ -3669,6 +3734,8 @@ hppa_expand_prologue (void)
     local_fsize += STARTING_FRAME_OFFSET;
 
   actual_fsize = compute_frame_size (size, &save_fregs);
+  if (flag_stack_usage)
+    current_function_static_stack_size = actual_fsize;
 
   /* Compute a few things we will use often.  */
   tmpreg = gen_rtx_REG (word_mode, 1);
@@ -3909,10 +3976,8 @@ hppa_expand_prologue (void)
                    {
                      rtx mem = gen_rtx_MEM (DFmode,
                                             plus_constant (base, offset));
-                     REG_NOTES (insn)
-                       = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-                                            gen_rtx_SET (VOIDmode, mem, reg),
-                                            REG_NOTES (insn));
+                     add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                                   gen_rtx_SET (VOIDmode, mem, reg));
                    }
                  else
                    {
@@ -3929,10 +3994,8 @@ hppa_expand_prologue (void)
                      RTX_FRAME_RELATED_P (setl) = 1;
                      RTX_FRAME_RELATED_P (setr) = 1;
                      vec = gen_rtvec (2, setl, setr);
-                     REG_NOTES (insn)
-                       = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-                                            gen_rtx_SEQUENCE (VOIDmode, vec),
-                                            REG_NOTES (insn));
+                     add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                                   gen_rtx_SEQUENCE (VOIDmode, vec));
                    }
                }
              offset += GET_MODE_SIZE (DFmode);
@@ -3984,23 +4047,18 @@ load_reg (int reg, HOST_WIDE_INT disp, int base)
 /* Update the total code bytes output to the text section.  */
 
 static void
-update_total_code_bytes (int nbytes)
+update_total_code_bytes (unsigned int nbytes)
 {
   if ((TARGET_PORTABLE_RUNTIME || !TARGET_GAS || !TARGET_SOM)
       && !IN_NAMED_SECTION_P (cfun->decl))
     {
-      if (INSN_ADDRESSES_SET_P ())
-       {
-         unsigned long old_total = total_code_bytes;
+      unsigned int old_total = total_code_bytes;
 
-         total_code_bytes += nbytes;
+      total_code_bytes += nbytes;
 
-         /* Be prepared to handle overflows.  */
-         if (old_total > total_code_bytes)
-           total_code_bytes = -1;
-       }
-      else
-       total_code_bytes = -1;
+      /* Be prepared to handle overflows.  */
+      if (old_total > total_code_bytes)
+        total_code_bytes = UINT_MAX;
     }
 }
 
@@ -4064,6 +4122,8 @@ pa_output_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
       last_address = ((last_address + FUNCTION_BOUNDARY / BITS_PER_UNIT - 1)
                      & ~(FUNCTION_BOUNDARY / BITS_PER_UNIT - 1));
     }
+  else
+    last_address = UINT_MAX;
 
   /* Finally, update the total number of code bytes output so far.  */
   update_total_code_bytes (last_address);
@@ -4353,8 +4413,7 @@ hppa_profile_hook (int label_no)
 
   /* Indicate the _mcount call cannot throw, nor will it execute a
      non-local goto.  */
-  REG_NOTES (call_insn)
-    = gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx, REG_NOTES (call_insn));
+  make_reg_eh_region_note_nothrow_nononlocal (call_insn);
 }
 
 /* Fetch the return address for the frame COUNT steps up from
@@ -4391,6 +4450,19 @@ return_addr_rtx (int count, rtx frameaddr)
   rtx saved_rp;
   rtx ins;
 
+  /* Instruction stream at the normal return address for the export stub:
+
+       0x4bc23fd1 | stub+8:   ldw -18(sr0,sp),rp
+       0x004010a1 | stub+12:  ldsid (sr0,rp),r1
+       0x00011820 | stub+16:  mtsp r1,sr0
+       0xe0400002 | stub+20:  be,n 0(sr0,rp)
+
+     0xe0400002 must be specified as -532676606 so that it won't be
+     rejected as an invalid immediate operand on 64-bit hosts.  */
+
+  HOST_WIDE_INT insns[4] = {0x4bc23fd1, 0x004010a1, 0x00011820, -532676606};
+  int i;
+
   if (count != 0)
     return NULL_RTX;
 
@@ -4399,6 +4471,9 @@ return_addr_rtx (int count, rtx frameaddr)
   if (TARGET_64BIT || TARGET_NO_SPACE_REGS)
     return rp;
 
+  /* If there is no export stub then just use the value saved from
+     the return pointer register.  */
+
   saved_rp = gen_reg_rtx (Pmode);
   emit_move_insn (saved_rp, rp);
 
@@ -4410,37 +4485,15 @@ return_addr_rtx (int count, rtx frameaddr)
   label = gen_label_rtx ();
 
   /* Check the instruction stream at the normal return address for the
-     export stub:
-
-       0x4bc23fd1 | stub+8:   ldw -18(sr0,sp),rp
-       0x004010a1 | stub+12:  ldsid (sr0,rp),r1
-       0x00011820 | stub+16:  mtsp r1,sr0
-       0xe0400002 | stub+20:  be,n 0(sr0,rp)
+     export stub.  If it is an export stub, than our return address is
+     really in -24[frameaddr].  */
 
-     If it is an export stub, than our return address is really in
-     -24[frameaddr].  */
-
-  emit_cmp_insn (gen_rtx_MEM (SImode, ins), GEN_INT (0x4bc23fd1), NE,
-                NULL_RTX, SImode, 1);
-  emit_jump_insn (gen_bne (label));
-
-  emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 4)),
-                GEN_INT (0x004010a1), NE, NULL_RTX, SImode, 1);
-  emit_jump_insn (gen_bne (label));
-
-  emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 8)),
-                GEN_INT (0x00011820), NE, NULL_RTX, SImode, 1);
-  emit_jump_insn (gen_bne (label));
-
-  /* 0xe0400002 must be specified as -532676606 so that it won't be
-     rejected as an invalid immediate operand on 64-bit hosts.  */
-  emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 12)),
-                GEN_INT (-532676606), NE, NULL_RTX, SImode, 1);
-
-  /* If there is no export stub then just use the value saved from
-     the return pointer register.  */
-
-  emit_jump_insn (gen_bne (label));
+  for (i = 0; i < 3; i++)
+    {
+      rtx op0 = gen_rtx_MEM (SImode, plus_constant (ins, i * 4)); 
+      rtx op1 = GEN_INT (insns[i]);
+      emit_cmp_and_jump_insns (op0, op1, NE, NULL, SImode, 0, label);
+    }
 
   /* Here we know that our return address points to an export
      stub.  We don't want to return the address of the export stub,
@@ -4454,30 +4507,32 @@ return_addr_rtx (int count, rtx frameaddr)
                                                              -24))));
 
   emit_label (label);
+
   return saved_rp;
 }
 
 void
-emit_bcond_fp (enum rtx_code code, rtx operand0)
+emit_bcond_fp (rtx operands[])
 {
+  enum rtx_code code = GET_CODE (operands[0]);
+  rtx operand0 = operands[1];
+  rtx operand1 = operands[2];
+  rtx label = operands[3];
+
+  emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (CCFPmode, 0),
+                         gen_rtx_fmt_ee (code, CCFPmode, operand0, operand1)));
+
   emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
                               gen_rtx_IF_THEN_ELSE (VOIDmode,
-                                                    gen_rtx_fmt_ee (code,
+                                                    gen_rtx_fmt_ee (NE,
                                                              VOIDmode,
                                                              gen_rtx_REG (CCFPmode, 0),
                                                              const0_rtx),
-                                                    gen_rtx_LABEL_REF (VOIDmode, operand0),
+                                                    gen_rtx_LABEL_REF (VOIDmode, label),
                                                     pc_rtx)));
 
 }
 
-rtx
-gen_cmp_fp (enum rtx_code code, rtx operand0, rtx operand1)
-{
-  return gen_rtx_SET (VOIDmode, gen_rtx_REG (CCFPmode, 0),
-                     gen_rtx_fmt_ee (code, CCFPmode, operand0, operand1));
-}
-
 /* 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.  */
 
@@ -4771,6 +4826,7 @@ pa_adjust_insn_length (rtx insn, int length)
       /* Adjust a short backwards conditional with an unfilled delay slot.  */
       if (GET_CODE (pat) == SET
          && length == 4
+         && JUMP_LABEL (insn) != NULL_RTX
          && ! forward_branch_p (insn))
        return 4;
       else if (GET_CODE (pat) == PARALLEL
@@ -4793,6 +4849,20 @@ pa_adjust_insn_length (rtx insn, int length)
   return 0;
 }
 
+/* Implement the TARGET_PRINT_OPERAND_PUNCT_VALID_P hook.  */
+
+static bool
+pa_print_operand_punct_valid_p (unsigned char code)
+{
+  if (code == '@'
+      || code == '#'
+      || code == '*'
+      || code == '^')
+    return true;
+
+  return false;
+}
+
 /* 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.  */
@@ -5375,13 +5445,11 @@ get_deferred_plabel (rtx symbol)
       tree id;
 
       if (deferred_plabels == 0)
-       deferred_plabels = (struct deferred_plabel *)
-         ggc_alloc (sizeof (struct deferred_plabel));
+       deferred_plabels =  ggc_alloc_deferred_plabel ();
       else
-       deferred_plabels = (struct deferred_plabel *)
-         ggc_realloc (deferred_plabels,
-                      ((n_deferred_plabels + 1)
-                       * sizeof (struct deferred_plabel)));
+        deferred_plabels = GGC_RESIZEVEC (struct deferred_plabel,
+                                          deferred_plabels,
+                                          n_deferred_plabels + 1);
 
       i = n_deferred_plabels++;
       deferred_plabels[i].internal_label = gen_label_rtx ();
@@ -5683,20 +5751,21 @@ output_arg_descriptor (rtx call_insn)
   fputc ('\n', asm_out_file);
 }
 \f
-static enum reg_class
-pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
+static reg_class_t
+pa_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
                     enum machine_mode mode, secondary_reload_info *sri)
 {
   int is_symbolic, regno;
+  enum reg_class rclass = (enum reg_class) rclass_i;
 
   /* Handle the easy stuff first.  */
-  if (class == R1_REGS)
+  if (rclass == R1_REGS)
     return NO_REGS;
 
   if (REG_P (x))
     {
       regno = REGNO (x);
-      if (class == BASE_REG_CLASS && regno < FIRST_PSEUDO_REGISTER)
+      if (rclass == BASE_REG_CLASS && regno < FIRST_PSEUDO_REGISTER)
        return NO_REGS;
     }
   else
@@ -5712,7 +5781,7 @@ pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
      generation requires %r1 as a scratch register.  */
   if (flag_pic
       && (mode == SImode || mode == DImode)
-      && FP_REG_CLASS_P (class)
+      && FP_REG_CLASS_P (rclass)
       && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
     {
       sri->icode = (mode == SImode ? CODE_FOR_reload_insi_r1
@@ -5735,7 +5804,7 @@ pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
      memory loads and stores.  */
   if ((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
       && GET_MODE_CLASS (mode) == MODE_INT
-      && FP_REG_CLASS_P (class))
+      && FP_REG_CLASS_P (rclass))
     {
       /* Reload passes (mem:SI (reg/f:DI 30 %r30) when it wants to check
         the secondary reload needed for a pseudo.  It never passes a
@@ -5761,15 +5830,19 @@ pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
       /* Request a secondary reload with a general scratch register
         for everthing else.  ??? Could symbolic operands be handled
         directly when generating non-pic PA 2.0 code?  */
-      sri->icode = in_p ? reload_in_optab[mode] : reload_out_optab[mode];
+      sri->icode = (in_p
+                   ? direct_optab_handler (reload_in_optab, mode)
+                   : direct_optab_handler (reload_out_optab, mode));
       return NO_REGS;
     }
 
   /* We need a secondary register (GPR) for copies between the SAR
      and anything other than a general register.  */
-  if (class == SHIFT_REGS && (regno <= 0 || regno >= 32))
+  if (rclass == SHIFT_REGS && (regno <= 0 || regno >= 32))
     {
-      sri->icode = in_p ? reload_in_optab[mode] : reload_out_optab[mode];
+      sri->icode = (in_p
+                   ? direct_optab_handler (reload_in_optab, mode)
+                   : direct_optab_handler (reload_out_optab, mode));
       return NO_REGS;
     }
 
@@ -5777,9 +5850,11 @@ pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
      well as secondary memory.  */
   if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
       && (REGNO_REG_CLASS (regno) == SHIFT_REGS
-      && FP_REG_CLASS_P (class)))
+      && FP_REG_CLASS_P (rclass)))
     {
-      sri->icode = in_p ? reload_in_optab[mode] : reload_out_optab[mode];
+      sri->icode = (in_p
+                   ? direct_optab_handler (reload_in_optab, mode)
+                   : direct_optab_handler (reload_out_optab, mode));
       return NO_REGS;
     }
 
@@ -5804,9 +5879,10 @@ pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
         break;
       case CONST:
        op = XEXP (x, 0);
-       is_symbolic = (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
-                        && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
-                       || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+       is_symbolic = (GET_CODE (op) == PLUS
+                      && ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+                           && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
+                          || GET_CODE (XEXP (op, 0)) == LABEL_REF)
                       && GET_CODE (XEXP (op, 1)) == CONST_INT);
         break;
       default:
@@ -5886,7 +5962,11 @@ enum direction
 function_arg_padding (enum machine_mode mode, const_tree type)
 {
   if (mode == BLKmode
-      || (TARGET_64BIT && type && AGGREGATE_TYPE_P (type)))
+      || (TARGET_64BIT
+         && type
+         && (AGGREGATE_TYPE_P (type)
+             || TREE_CODE (type) == COMPLEX_TYPE
+             || TREE_CODE (type) == VECTOR_TYPE)))
     {
       /* Return none if justification is not required.  */
       if (type
@@ -5926,9 +6006,7 @@ hppa_builtin_saveregs (void)
 {
   rtx offset, dest;
   tree fntype = TREE_TYPE (current_function_decl);
-  int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
-                  && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
-                      != void_type_node)))
+  int argadj = ((!stdarg_p (fntype))
                ? UNITS_PER_WORD : 0);
 
   if (argadj)
@@ -6029,11 +6107,10 @@ hppa_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
       u = fold_build1 (NEGATE_EXPR, sizetype, u);
       t = build2 (POINTER_PLUS_EXPR, valist_type, valist, u);
 
-      /* Copied from va-pa.h, but we probably don't need to align to
-        word size, since we generate and preserve that invariant.  */
-      u = size_int (size > 4 ? -8 : -4);
-      t = fold_convert (sizetype, t);
-      t = build2 (BIT_AND_EXPR, sizetype, t, u);
+      /* Align to 4 or 8 byte boundary depending on argument size.  */
+
+      u = build_int_cst (TREE_TYPE (t), (HOST_WIDE_INT)(size > 4 ? -8 : -4));
+      t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t, u);
       t = fold_convert (valist_type, t);
 
       t = build2 (MODIFY_EXPR, valist_type, valist, t);
@@ -6102,6 +6179,38 @@ pa_scalar_mode_supported_p (enum machine_mode mode)
     }
 }
 
+/* Return TRUE if INSN, a jump insn, has an unfilled delay slot and
+   it branches to the next real instruction.  Otherwise, return FALSE.  */
+
+static bool
+branch_to_delay_slot_p (rtx insn)
+{
+  if (dbr_sequence_length ())
+    return FALSE;
+
+  return next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn);
+}
+
+/* Return TRUE if INSN, a jump insn, needs a nop in its delay slot.
+
+   This occurs when INSN has an unfilled delay slot and is followed
+   by an ASM_INPUT.  Disaster can occur if the ASM_INPUT is empty and
+   the jump branches into the delay slot.  So, we add a nop in the delay
+   slot just to be safe.  This messes up our instruction count, but we
+   don't know how big the ASM_INPUT insn is anyway.  */
+
+static bool
+branch_needs_nop_p (rtx insn)
+{
+  rtx next_insn;
+
+  if (dbr_sequence_length ())
+    return FALSE;
+
+  next_insn = next_real_insn (insn);
+  return GET_CODE (PATTERN (next_insn)) == ASM_INPUT;
+}
+
 /* This routine handles all the normal conditional branch sequences we
    might need to generate.  It handles compare immediate vs compare
    register, nullification of delay slots, varying length branches,
@@ -6127,7 +6236,7 @@ output_cbranch (rtx *operands, int negated, rtx insn)
      slot and the same branch target as this branch.  We could check
      for this but jump optimization should eliminate nop jumps.  It
      is always safe to emit a nop.  */
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     return "nop";
 
   /* The doubleword form of the cmpib instruction doesn't have the LEU
@@ -6176,7 +6285,12 @@ output_cbranch (rtx *operands, int negated, rtx insn)
        if (useskip)
          strcat (buf, " %2,%r1,%%r0");
        else if (nullify)
-         strcat (buf, ",n %2,%r1,%0");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, ",n %2,%r1,%0%#");
+           else
+             strcat (buf, ",n %2,%r1,%0");
+         }
        else
          strcat (buf, " %2,%r1,%0");
        break;
@@ -6449,7 +6563,7 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
      is only used when optimizing; jump optimization should eliminate the
      jump.  But be prepared just in case.  */
 
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     return "nop";
 
   /* If this is a long branch with its delay slot unfilled, set `nullify'
@@ -6495,11 +6609,21 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
        if (useskip)
          strcat (buf, " %0,%1,1,%%r0");
        else if (nullify && negated)
-         strcat (buf, ",n %0,%1,%3");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, ",n %0,%1,%3%#");
+           else
+             strcat (buf, ",n %0,%1,%3");
+         }
        else if (nullify && ! negated)
-         strcat (buf, ",n %0,%1,%2");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, ",n %0,%1,%2%#");
+           else
+             strcat (buf, ",n %0,%1,%2");
+         }
        else if (! nullify && negated)
-         strcat (buf, "%0,%1,%3");
+         strcat (buf, " %0,%1,%3");
        else if (! nullify && ! negated)
          strcat (buf, " %0,%1,%2");
        break;
@@ -6630,7 +6754,7 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
      is only used when optimizing; jump optimization should eliminate the
      jump.  But be prepared just in case.  */
 
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     return "nop";
 
   /* If this is a long branch with its delay slot unfilled, set `nullify'
@@ -6676,11 +6800,21 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
        if (useskip)
          strcat (buf, "{ %0,1,%%r0| %0,%%sar,1,%%r0}");
        else if (nullify && negated)
-         strcat (buf, "{,n %0,%3|,n %0,%%sar,%3}");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, "{,n %0,%3%#|,n %0,%%sar,%3%#}");
+           else
+             strcat (buf, "{,n %0,%3|,n %0,%%sar,%3}");
+         }
        else if (nullify && ! negated)
-         strcat (buf, "{,n %0,%2|,n %0,%%sar,%2}");
+         {
+           if (branch_needs_nop_p (insn))
+             strcat (buf, "{,n %0,%2%#|,n %0,%%sar,%2%#}");
+           else
+             strcat (buf, "{,n %0,%2|,n %0,%%sar,%2}");
+         }
        else if (! nullify && negated)
-         strcat (buf, "{%0,%3|%0,%%sar,%3}");
+         strcat (buf, "{ %0,%3| %0,%%sar,%3}");
        else if (! nullify && ! negated)
          strcat (buf, "{ %0,%2| %0,%%sar,%2}");
        break;
@@ -6802,7 +6936,7 @@ output_dbra (rtx *operands, rtx insn, int which_alternative)
   /* A conditional branch to the following instruction (e.g. the delay slot) is
      asking for a disaster.  Be prepared!  */
 
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     {
       if (which_alternative == 0)
        return "ldo %1(%0),%0";
@@ -6839,7 +6973,12 @@ output_dbra (rtx *operands, rtx insn, int which_alternative)
        {
        case 4:
          if (nullify)
-           return "addib,%C2,n %1,%0,%3";
+           {
+             if (branch_needs_nop_p (insn))
+               return "addib,%C2,n %1,%0,%3%#";
+             else
+               return "addib,%C2,n %1,%0,%3";
+           }
          else
            return "addib,%C2 %1,%0,%3";
       
@@ -6947,7 +7086,7 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
   /* A conditional branch to the following instruction (e.g. the delay slot) is
      asking for a disaster.  Be prepared!  */
 
-  if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
+  if (branch_to_delay_slot_p (insn))
     {
       if (which_alternative == 0)
        return "copy %1,%0";
@@ -6985,7 +7124,12 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
        {
        case 4:
          if (nullify)
-           return "movb,%C2,n %1,%0,%3";
+           {
+             if (branch_needs_nop_p (insn))
+               return "movb,%C2,n %1,%0,%3%#";
+             else
+               return "movb,%C2,n %1,%0,%3";
+           }
          else
            return "movb,%C2 %1,%0,%3";
 
@@ -7375,12 +7519,14 @@ int
 attr_length_call (rtx insn, int sibcall)
 {
   int local_call;
-  rtx call_dest;
+  rtx call, call_dest;
   tree call_decl;
   int length = 0;
   rtx pat = PATTERN (insn);
   unsigned long distance = -1;
 
+  gcc_assert (GET_CODE (insn) == CALL_INSN);
+
   if (INSN_ADDRESSES_SET_P ())
     {
       unsigned long total;
@@ -7391,12 +7537,17 @@ attr_length_call (rtx insn, int sibcall)
        distance = -1;
     }
 
-  /* Determine if this is a local call.  */
-  if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL)
-    call_dest = XEXP (XEXP (XVECEXP (pat, 0, 0), 0), 0);
-  else
-    call_dest = XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0);
+  gcc_assert (GET_CODE (pat) == PARALLEL);
+
+  /* Get the call rtx.  */
+  call = XVECEXP (pat, 0, 0);
+  if (GET_CODE (call) == SET)
+    call = SET_SRC (call);
 
+  gcc_assert (GET_CODE (call) == CALL);
+
+  /* Determine if this is a local call.  */
+  call_dest = XEXP (XEXP (call, 0), 0);
   call_decl = SYMBOL_REF_DECL (call_dest);
   local_call = call_decl && targetm.binds_local_p (call_decl);
 
@@ -7421,7 +7572,7 @@ attr_length_call (rtx insn, int sibcall)
     {
       length += 20;
 
-      if (!TARGET_PA_20 && !TARGET_NO_SPACE_REGS && flag_pic)
+      if (!TARGET_PA_20 && !TARGET_NO_SPACE_REGS && (!local_call || flag_pic))
        length += 8;
     }
 
@@ -7441,7 +7592,7 @@ attr_length_call (rtx insn, int sibcall)
          if (!sibcall)
            length += 8;
 
-         if (!TARGET_NO_SPACE_REGS && flag_pic)
+         if (!TARGET_NO_SPACE_REGS && (!local_call || flag_pic))
            length += 8;
        }
     }
@@ -7534,7 +7685,9 @@ output_call (rtx insn, rtx call_dest, int sibcall)
          if (seq_length != 0
              && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
              && !sibcall
-             && (!TARGET_PA_20 || indirect_call))
+             && (!TARGET_PA_20
+                 || indirect_call
+                 || ((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)))
            {
              /* A non-jump insn in the delay slot.  By definition we can
                 emit this insn before the call (and in fact before argument
@@ -7636,7 +7789,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
                  if (!sibcall && !TARGET_PA_20)
                    {
                      output_asm_insn ("{bl|b,l} .+8,%%r2", xoperands);
-                     if (TARGET_NO_SPACE_REGS)
+                     if (TARGET_NO_SPACE_REGS || (local_call && !flag_pic))
                        output_asm_insn ("addi 8,%%r2,%%r2", xoperands);
                      else
                        output_asm_insn ("addi 16,%%r2,%%r2", xoperands);
@@ -7661,20 +7814,20 @@ output_call (rtx insn, rtx call_dest, int sibcall)
                }
              else
                {
-                 if (!TARGET_NO_SPACE_REGS && flag_pic)
+                 if (!TARGET_NO_SPACE_REGS && (!local_call || flag_pic))
                    output_asm_insn ("ldsid (%%r1),%%r31\n\tmtsp %%r31,%%sr0",
                                     xoperands);
 
                  if (sibcall)
                    {
-                     if (TARGET_NO_SPACE_REGS || !flag_pic)
+                     if (TARGET_NO_SPACE_REGS || (local_call && !flag_pic))
                        output_asm_insn ("be 0(%%sr4,%%r1)", xoperands);
                      else
                        output_asm_insn ("be 0(%%sr0,%%r1)", xoperands);
                    }
                  else
                    {
-                     if (TARGET_NO_SPACE_REGS || !flag_pic)
+                     if (TARGET_NO_SPACE_REGS || (local_call && !flag_pic))
                        output_asm_insn ("ble 0(%%sr4,%%r1)", xoperands);
                      else
                        output_asm_insn ("ble 0(%%sr0,%%r1)", xoperands);
@@ -7708,12 +7861,15 @@ output_call (rtx insn, rtx call_dest, int sibcall)
   if (!delay_slot_filled && INSN_ADDRESSES_SET_P ())
     {
       /* See if the return address can be adjusted.  Use the containing
-         sequence insn's address.  */
+         sequence insn's address.  This would break the regular call/return@
+         relationship assumed by the table based eh unwinder, so only do that
+         if the call is not possibly throwing.  */
       rtx seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
       int distance = (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
                      - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8);
 
-      if (VAL_14_BITS_P (distance))
+      if (VAL_14_BITS_P (distance)
+         && !(can_throw_internal (insn) || can_throw_external (insn)))
        {
          xoperands[1] = gen_label_rtx ();
          output_asm_insn ("ldo %0-%1(%%r2),%%r2", xoperands);
@@ -7929,7 +8085,7 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
 {
   static unsigned int current_thunk_number;
   int val_14 = VAL_14_BITS_P (delta);
-  int nbytes = 0;
+  unsigned int old_last_address = last_address, nbytes = 0;
   char label[16];
   rtx xoperands[4];
 
@@ -7968,6 +8124,10 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
                   || ((DECL_SECTION_NAME (thunk_fndecl)
                        == DECL_SECTION_NAME (function))
                       && last_address < 262132)))
+             || (targetm.have_named_sections
+                 && DECL_SECTION_NAME (thunk_fndecl) == NULL
+                 && DECL_SECTION_NAME (function) == NULL
+                 && last_address < 262132)
              || (!targetm.have_named_sections && last_address < 262132))))
     {
       if (!val_14)
@@ -8162,6 +8322,8 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
   nbytes = ((nbytes + FUNCTION_BOUNDARY / BITS_PER_UNIT - 1)
            & ~(FUNCTION_BOUNDARY / BITS_PER_UNIT - 1));
   last_address += nbytes;
+  if (old_last_address > last_address)
+    last_address = UINT_MAX;
   update_total_code_bytes (nbytes);
 }
 
@@ -8509,22 +8671,28 @@ non_hard_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   return ! (GET_CODE (op) == REG && REGNO (op) < FIRST_PSEUDO_REGISTER);
 }
 
-/* Return 1 if INSN branches forward.  Should be using insn_addresses
-   to avoid walking through all the insns...  */
-static int
+/* Return TRUE if INSN branches forward.  */
+
+static bool
 forward_branch_p (rtx insn)
 {
-  rtx label = JUMP_LABEL (insn);
+  rtx lab = JUMP_LABEL (insn);
+
+  /* The INSN must have a jump label.  */
+  gcc_assert (lab != NULL_RTX);
+
+  if (INSN_ADDRESSES_SET_P ())
+    return INSN_ADDRESSES (INSN_UID (lab)) > INSN_ADDRESSES (INSN_UID (insn));  
 
   while (insn)
     {
-      if (insn == label)
-       break;
+      if (insn == lab)
+       return true;
       else
        insn = NEXT_INSN (insn);
     }
 
-  return (insn == label);
+  return false;
 }
 
 /* Return 1 if OP is an equality comparison, else return 0.  */
@@ -8831,7 +8999,7 @@ pa_reorg (void)
 static void
 pa_combine_instructions (void)
 {
-  rtx anchor, new;
+  rtx anchor, new_rtx;
 
   /* This can get expensive since the basic algorithm is on the
      order of O(n^2) (or worse).  Only do it for -O2 or higher
@@ -8843,8 +9011,8 @@ pa_combine_instructions (void)
      may be combined with "floating" insns.  As the name implies,
      "anchor" instructions don't move, while "floating" insns may
      move around.  */
-  new = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, NULL_RTX, NULL_RTX));
-  new = make_insn_raw (new);
+  new_rtx = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, NULL_RTX, NULL_RTX));
+  new_rtx = make_insn_raw (new_rtx);
 
   for (anchor = get_insns (); anchor; anchor = NEXT_INSN (anchor))
     {
@@ -8900,7 +9068,7 @@ pa_combine_instructions (void)
                {
                  /* If ANCHOR and FLOATER can be combined, then we're
                     done with this pass.  */
-                 if (pa_can_combine_p (new, anchor, floater, 0,
+                 if (pa_can_combine_p (new_rtx, anchor, floater, 0,
                                        SET_DEST (PATTERN (floater)),
                                        XEXP (SET_SRC (PATTERN (floater)), 0),
                                        XEXP (SET_SRC (PATTERN (floater)), 1)))
@@ -8912,7 +9080,7 @@ pa_combine_instructions (void)
                {
                  if (GET_CODE (SET_SRC (PATTERN (floater))) == PLUS)
                    {
-                     if (pa_can_combine_p (new, anchor, floater, 0,
+                     if (pa_can_combine_p (new_rtx, anchor, floater, 0,
                                            SET_DEST (PATTERN (floater)),
                                        XEXP (SET_SRC (PATTERN (floater)), 0),
                                        XEXP (SET_SRC (PATTERN (floater)), 1)))
@@ -8920,7 +9088,7 @@ pa_combine_instructions (void)
                    }
                  else
                    {
-                     if (pa_can_combine_p (new, anchor, floater, 0,
+                     if (pa_can_combine_p (new_rtx, anchor, floater, 0,
                                            SET_DEST (PATTERN (floater)),
                                            SET_SRC (PATTERN (floater)),
                                            SET_SRC (PATTERN (floater))))
@@ -8962,7 +9130,7 @@ pa_combine_instructions (void)
                    {
                      /* If ANCHOR and FLOATER can be combined, then we're
                         done with this pass.  */
-                     if (pa_can_combine_p (new, anchor, floater, 1,
+                     if (pa_can_combine_p (new_rtx, anchor, floater, 1,
                                            SET_DEST (PATTERN (floater)),
                                            XEXP (SET_SRC (PATTERN (floater)),
                                                  0),
@@ -9021,7 +9189,7 @@ pa_combine_instructions (void)
 }
 
 static int
-pa_can_combine_p (rtx new, rtx anchor, rtx floater, int reversed, rtx dest,
+pa_can_combine_p (rtx new_rtx, rtx anchor, rtx floater, int reversed, rtx dest,
                  rtx src1, rtx src2)
 {
   int insn_code_number;
@@ -9034,12 +9202,12 @@ pa_can_combine_p (rtx new, rtx anchor, rtx floater, int reversed, rtx dest,
      If the pattern doesn't match or the constraints
      aren't met keep searching for a suitable floater
      insn.  */
-  XVECEXP (PATTERN (new), 0, 0) = PATTERN (anchor);
-  XVECEXP (PATTERN (new), 0, 1) = PATTERN (floater);
-  INSN_CODE (new) = -1;
-  insn_code_number = recog_memoized (new);
+  XVECEXP (PATTERN (new_rtx), 0, 0) = PATTERN (anchor);
+  XVECEXP (PATTERN (new_rtx), 0, 1) = PATTERN (floater);
+  INSN_CODE (new_rtx) = -1;
+  insn_code_number = recog_memoized (new_rtx);
   if (insn_code_number < 0
-      || (extract_insn (new), ! constrain_operands (1)))
+      || (extract_insn (new_rtx), ! constrain_operands (1)))
     return 0;
 
   if (reversed)
@@ -9106,17 +9274,33 @@ insn_refs_are_delayed (rtx insn)
           && get_attr_type (insn) == TYPE_MILLI));
 }
 
+/* Promote the return value, but not the arguments.  */
+
+static enum machine_mode
+pa_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
+                          enum machine_mode mode,
+                          int *punsignedp ATTRIBUTE_UNUSED,
+                          const_tree fntype ATTRIBUTE_UNUSED,
+                          int for_return)
+{
+  if (for_return == 0)
+    return mode;
+  return promote_mode (type, mode, punsignedp);
+}
+
 /* On the HP-PA the value is found in register(s) 28(-29), unless
    the mode is SF or DF. Then the value is returned in fr4 (32).
 
-   This must perform the same promotions as PROMOTE_MODE, else
-   TARGET_PROMOTE_FUNCTION_RETURN will not work correctly.
+   This must perform the same promotions as PROMOTE_MODE, else promoting
+   return values in TARGET_PROMOTE_FUNCTION_MODE will not work correctly.
 
    Small structures must be returned in a PARALLEL on PA64 in order
    to match the HP Compiler ABI.  */
 
-rtx
-function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
+static rtx
+pa_function_value (const_tree valtype, 
+                   const_tree func ATTRIBUTE_UNUSED, 
+                   bool outgoing ATTRIBUTE_UNUSED)
 {
   enum machine_mode valmode;
 
@@ -9174,6 +9358,31 @@ function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
   return gen_rtx_REG (valmode, 28);
 }
 
+/* Implement the TARGET_LIBCALL_VALUE hook.  */
+
+static rtx
+pa_libcall_value (enum machine_mode mode,
+                 const_rtx fun ATTRIBUTE_UNUSED)
+{
+  if (! TARGET_SOFT_FLOAT
+      && (mode == SFmode || mode == DFmode))
+    return  gen_rtx_REG (mode, 32);
+  else
+    return  gen_rtx_REG (mode, 28);
+}
+
+/* Implement the TARGET_FUNCTION_VALUE_REGNO_P hook.  */
+
+static bool
+pa_function_value_regno_p (const unsigned int regno)
+{
+  if (regno == 28
+      || (! TARGET_SOFT_FLOAT &&  regno == 32))
+    return true;
+
+  return false;
+}
+
 /* Return the location of a parameter that is passed in a register or NULL
    if the parameter has any component that is passed in memory.
 
@@ -9595,7 +9804,7 @@ pa_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
    at the end of the file if and only if SYMBOL_REF_REFERENCED_P is true.
    This avoids putting out names that are never really used.  */
 
-typedef struct extern_symbol GTY(())
+typedef struct GTY(()) extern_symbol
 {
   tree decl;
   const char *name;
@@ -9652,11 +9861,11 @@ pa_hpux_file_end (void)
 #endif
 
 /* Return true if a change from mode FROM to mode TO for a register
-   in register class CLASS is invalid.  */
+   in register class RCLASS is invalid.  */
 
 bool
 pa_cannot_change_mode_class (enum machine_mode from, enum machine_mode to,
-                            enum reg_class class)
+                            enum reg_class rclass)
 {
   if (from == to)
     return false;
@@ -9674,7 +9883,7 @@ pa_cannot_change_mode_class (enum machine_mode from, enum machine_mode to,
      On the 64-bit target, this conflicts with the definition of
      LOAD_EXTEND_OP.  Thus, we can't allow changing between modes
      with different sizes in the floating-point registers.  */
-  if (MAYBE_FP_REG_CLASS_P (class))
+  if (MAYBE_FP_REG_CLASS_P (rclass))
     return true;
 
   /* HARD_REGNO_MODE_OK places modes with sizes larger than a word
@@ -9709,4 +9918,186 @@ pa_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
   return true;
 }
 
+\f
+/* Length in units of the trampoline instruction code.  */
+
+#define TRAMPOLINE_CODE_SIZE (TARGET_64BIT ? 24 : (TARGET_PA_20 ? 32 : 40))
+
+
+/* Output assembler code for a block containing the constant parts
+   of a trampoline, leaving space for the variable parts.\
+
+   The trampoline sets the static chain pointer to STATIC_CHAIN_REGNUM
+   and then branches to the specified routine.
+
+   This code template is copied from text segment to stack location
+   and then patched with pa_trampoline_init to contain valid values,
+   and then entered as a subroutine.
+
+   It is best to keep this as small as possible to avoid having to
+   flush multiple lines in the cache.  */
+
+static void
+pa_asm_trampoline_template (FILE *f)
+{
+  if (!TARGET_64BIT)
+    {
+      fputs ("\tldw    36(%r22),%r21\n", f);
+      fputs ("\tbb,>=,n        %r21,30,.+16\n", f);
+      if (ASSEMBLER_DIALECT == 0)
+       fputs ("\tdepi  0,31,2,%r21\n", f);
+      else
+       fputs ("\tdepwi 0,31,2,%r21\n", f);
+      fputs ("\tldw    4(%r21),%r19\n", f);
+      fputs ("\tldw    0(%r21),%r21\n", f);
+      if (TARGET_PA_20)
+       {
+         fputs ("\tbve (%r21)\n", f);
+         fputs ("\tldw 40(%r22),%r29\n", f);
+         fputs ("\t.word       0\n", f);
+         fputs ("\t.word       0\n", f);
+       }
+      else
+       {
+         fputs ("\tldsid       (%r21),%r1\n", f);
+         fputs ("\tmtsp        %r1,%sr0\n", f);
+         fputs ("\tbe  0(%sr0,%r21)\n", f);
+         fputs ("\tldw 40(%r22),%r29\n", f);
+       }
+      fputs ("\t.word  0\n", f);
+      fputs ("\t.word  0\n", f);
+      fputs ("\t.word  0\n", f);
+      fputs ("\t.word  0\n", f);
+    }
+  else
+    {
+      fputs ("\t.dword 0\n", f);
+      fputs ("\t.dword 0\n", f);
+      fputs ("\t.dword 0\n", f);
+      fputs ("\t.dword 0\n", f);
+      fputs ("\tmfia   %r31\n", f);
+      fputs ("\tldd    24(%r31),%r1\n", f);
+      fputs ("\tldd    24(%r1),%r27\n", f);
+      fputs ("\tldd    16(%r1),%r1\n", f);
+      fputs ("\tbve    (%r1)\n", f);
+      fputs ("\tldd    32(%r31),%r31\n", f);
+      fputs ("\t.dword 0  ; fptr\n", f);
+      fputs ("\t.dword 0  ; static link\n", f);
+    }
+}
+
+/* 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.
+
+   Move the function address to the trampoline template at offset 36.
+   Move the static chain value to trampoline template at offset 40.
+   Move the trampoline address to trampoline template at offset 44.
+   Move r19 to trampoline template at offset 48.  The latter two
+   words create a plabel for the indirect call to the trampoline.
+
+   A similar sequence is used for the 64-bit port but the plabel is
+   at the beginning of the trampoline.
+
+   Finally, the cache entries for the trampoline code are flushed.
+   This is necessary to ensure that the trampoline instruction sequence
+   is written to memory prior to any attempts at prefetching the code
+   sequence.  */
+
+static void
+pa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx start_addr = gen_reg_rtx (Pmode);
+  rtx end_addr = gen_reg_rtx (Pmode);
+  rtx line_length = gen_reg_rtx (Pmode);
+  rtx r_tramp, tmp;
+
+  emit_block_move (m_tramp, assemble_trampoline_template (),
+                  GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+  r_tramp = force_reg (Pmode, XEXP (m_tramp, 0));
+
+  if (!TARGET_64BIT)
+    {
+      tmp = adjust_address (m_tramp, Pmode, 36);
+      emit_move_insn (tmp, fnaddr);
+      tmp = adjust_address (m_tramp, Pmode, 40);
+      emit_move_insn (tmp, chain_value);
+
+      /* Create a fat pointer for the trampoline.  */
+      tmp = adjust_address (m_tramp, Pmode, 44);
+      emit_move_insn (tmp, r_tramp);
+      tmp = adjust_address (m_tramp, Pmode, 48);
+      emit_move_insn (tmp, gen_rtx_REG (Pmode, 19));
+
+      /* fdc and fic only use registers for the address to flush,
+        they do not accept integer displacements.  We align the
+        start and end addresses to the beginning of their respective
+        cache lines to minimize the number of lines flushed.  */
+      emit_insn (gen_andsi3 (start_addr, r_tramp,
+                            GEN_INT (-MIN_CACHELINE_SIZE)));
+      tmp = force_reg (Pmode, plus_constant (r_tramp, TRAMPOLINE_CODE_SIZE-1));
+      emit_insn (gen_andsi3 (end_addr, tmp,
+                            GEN_INT (-MIN_CACHELINE_SIZE)));
+      emit_move_insn (line_length, GEN_INT (MIN_CACHELINE_SIZE));
+      emit_insn (gen_dcacheflushsi (start_addr, end_addr, line_length));
+      emit_insn (gen_icacheflushsi (start_addr, end_addr, line_length,
+                                   gen_reg_rtx (Pmode),
+                                   gen_reg_rtx (Pmode)));
+    }
+  else
+    {
+      tmp = adjust_address (m_tramp, Pmode, 56);
+      emit_move_insn (tmp, fnaddr);
+      tmp = adjust_address (m_tramp, Pmode, 64);
+      emit_move_insn (tmp, chain_value);
+
+      /* Create a fat pointer for the trampoline.  */
+      tmp = adjust_address (m_tramp, Pmode, 16);
+      emit_move_insn (tmp, force_reg (Pmode, plus_constant (r_tramp, 32)));
+      tmp = adjust_address (m_tramp, Pmode, 24);
+      emit_move_insn (tmp, gen_rtx_REG (Pmode, 27));
+
+      /* fdc and fic only use registers for the address to flush,
+        they do not accept integer displacements.  We align the
+        start and end addresses to the beginning of their respective
+        cache lines to minimize the number of lines flushed.  */
+      tmp = force_reg (Pmode, plus_constant (r_tramp, 32));
+      emit_insn (gen_anddi3 (start_addr, tmp,
+                            GEN_INT (-MIN_CACHELINE_SIZE)));
+      tmp = force_reg (Pmode, plus_constant (tmp, TRAMPOLINE_CODE_SIZE - 1));
+      emit_insn (gen_anddi3 (end_addr, tmp,
+                            GEN_INT (-MIN_CACHELINE_SIZE)));
+      emit_move_insn (line_length, GEN_INT (MIN_CACHELINE_SIZE));
+      emit_insn (gen_dcacheflushdi (start_addr, end_addr, line_length));
+      emit_insn (gen_icacheflushdi (start_addr, end_addr, line_length,
+                                   gen_reg_rtx (Pmode),
+                                   gen_reg_rtx (Pmode)));
+    }
+}
+
+/* Perform any machine-specific adjustment in the address of the trampoline.
+   ADDR contains the address that was passed to pa_trampoline_init.
+   Adjust the trampoline address to point to the plabel at offset 44.  */
+
+static rtx
+pa_trampoline_adjust_address (rtx addr)
+{
+  if (!TARGET_64BIT)
+    addr = memory_address (Pmode, plus_constant (addr, 46));
+  return addr;
+}
+
+static rtx
+pa_delegitimize_address (rtx orig_x)
+{
+  rtx x = delegitimize_mem_from_attrs (orig_x);
+
+  if (GET_CODE (x) == LO_SUM
+      && GET_CODE (XEXP (x, 1)) == UNSPEC
+      && XINT (XEXP (x, 1), 1) == UNSPEC_DLTIND14R)
+    return gen_const_mem (Pmode, XVECEXP (XEXP (x, 1), 0, 0));
+  return x;
+}
+\f
 #include "gt-pa.h"