OSDN Git Service

* pa.c (compute_zdepwi_operands): Limit deposit length to 32 - lsb.
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.c
index 29e449d..8e8db86 100644 (file)
@@ -1,13 +1,14 @@
 /* Subroutines for insn-output.c for HPPA.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    Contributed by Tim Moore (moore@cs.utah.edu), based on sparc.c
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -16,9 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -47,6 +47,7 @@ Boston, MA 02110-1301, USA.  */
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
+#include "df.h"
 
 /* Return nonzero if there is a bypass for the output of 
    OUT_INSN and the fp store IN_INSN.  */
@@ -58,7 +59,8 @@ hppa_fpstore_bypass_p (rtx out_insn, rtx in_insn)
   rtx set;
 
   if (recog_memoized (in_insn) < 0
-      || get_attr_type (in_insn) != TYPE_FPSTORE
+      || (get_attr_type (in_insn) != TYPE_FPSTORE
+         && get_attr_type (in_insn) != TYPE_FPSTORE_LOAD)
       || recog_memoized (out_insn) < 0)
     return 0;
 
@@ -85,13 +87,13 @@ hppa_fpstore_bypass_p (rtx out_insn, rtx in_insn)
 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_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,7 +104,7 @@ 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 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);
@@ -123,11 +125,13 @@ static void pa_asm_out_destructor (rtx, int);
 #endif
 static void pa_init_builtins (void);
 static rtx hppa_builtin_saveregs (void);
-static tree hppa_gimplify_va_arg_expr (tree, tree, tree *, tree *);
+static void hppa_va_start (tree, rtx);
+static tree hppa_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
 static bool pa_scalar_mode_supported_p (enum machine_mode);
-static bool pa_commutative_p (rtx x, int outer_code);
+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;
@@ -147,25 +151,20 @@ static void pa_hpux_init_libfuncs (void);
 #endif
 static rtx pa_struct_value_rtx (tree, int);
 static bool pa_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
-                                 tree, bool);
+                                 const_tree, bool);
 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 void pa_extra_live_on_entry (bitmap);
 
 /* 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;
 
@@ -176,6 +175,10 @@ int flag_pa_unix = TARGET_HPUX_11_11 ? 1998 : TARGET_HPUX_10_10 ? 1995 : 1993;
    registers which were saved by the current function's prologue.  */
 static int gr_saved, fr_saved;
 
+/* Boolean indicating whether the return pointer was saved by the
+   current function's prologue.  */
+static bool rp_saved;
+
 static rtx find_addr_reg (rtx);
 
 /* Keep track of the number of bytes we have output in the CODE subspace
@@ -185,11 +188,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;
@@ -221,6 +224,9 @@ static size_t n_deferred_plabels = 0;
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE pa_output_function_epilogue
 
+#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
@@ -280,9 +286,9 @@ static size_t n_deferred_plabels = 0;
 #endif
 
 #undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
 #undef TARGET_PROMOTE_PROTOTYPES
-#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
 
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX pa_struct_value_rtx
@@ -299,6 +305,8 @@ static size_t n_deferred_plabels = 0;
 
 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS hppa_builtin_saveregs
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START hppa_va_start
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR hppa_gimplify_va_arg_expr
 
@@ -311,6 +319,9 @@ static size_t n_deferred_plabels = 0;
 #undef TARGET_SECONDARY_RELOAD
 #define TARGET_SECONDARY_RELOAD pa_secondary_reload
 
+#undef TARGET_EXTRA_LIVE_ON_ENTRY
+#define TARGET_EXTRA_LIVE_ON_ENTRY pa_extra_live_on_entry
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Parse the -mfixed-range= option string.  */
@@ -512,6 +523,12 @@ pa_init_builtins (void)
   implicit_built_in_decls[(int) BUILT_IN_FPUTC_UNLOCKED]
     = implicit_built_in_decls[(int) BUILT_IN_PUTC_UNLOCKED];
 #endif
+#if TARGET_HPUX_11
+  if (built_in_decls [BUILT_IN_FINITE])
+    set_user_assembler_name (built_in_decls [BUILT_IN_FINITE], "_Isfinite");
+  if (built_in_decls [BUILT_IN_FINITEF])
+    set_user_assembler_name (built_in_decls [BUILT_IN_FINITEF], "_Isfinitef");
+#endif
 }
 
 /* Function to init struct machine_function.
@@ -521,7 +538,7 @@ pa_init_builtins (void)
 static struct machine_function *
 pa_init_machine_status (void)
 {
-  return ggc_alloc_cleared (sizeof (machine_function));
+  return GGC_CNEW (machine_function);
 }
 
 /* If FROM is a probable pointer register, mark TO as a probable
@@ -551,12 +568,12 @@ symbolic_expression_p (rtx x)
 /* Accept any constant that can be moved in one instruction into a
    general register.  */
 int
-cint_ok_for_move (HOST_WIDE_INT intval)
+cint_ok_for_move (HOST_WIDE_INT ival)
 {
   /* OK if ldo, ldil, or zdepi, can be used.  */
-  return (CONST_OK_FOR_LETTER_P (intval, 'J')
-         || CONST_OK_FOR_LETTER_P (intval, 'N')
-         || CONST_OK_FOR_LETTER_P (intval, 'K'));
+  return (VAL_14_BITS_P (ival)
+         || ldil_cint_p (ival)
+         || zdepi_cint_p (ival));
 }
 \f
 /* Return truth value of whether OP can be used as an operand in a
@@ -569,8 +586,38 @@ adddi3_operand (rtx op, enum machine_mode mode)
              && (TARGET_64BIT ? INT_14_BITS (op) : INT_11_BITS (op))));
 }
 
+/* True iff the operand OP can be used as the destination operand of
+   an integer store.  This also implies the operand could be used as
+   the source operand of an integer load.  Symbolic, lo_sum and indexed
+   memory operands are not allowed.  We accept reloading pseudos and
+   other memory operands.  */
+int
+integer_store_memory_operand (rtx op, enum machine_mode mode)
+{
+  return ((reload_in_progress
+          && REG_P (op)
+          && REGNO (op) >= FIRST_PSEUDO_REGISTER
+          && reg_renumber [REGNO (op)] < 0)
+         || (GET_CODE (op) == MEM
+             && (reload_in_progress || memory_address_p (mode, XEXP (op, 0)))
+             && !symbolic_memory_operand (op, VOIDmode)
+             && !IS_LO_SUM_DLT_ADDR_P (XEXP (op, 0))
+             && !IS_INDEX_ADDR_P (XEXP (op, 0))));
+}
+
+/* True iff ldil can be used to load this CONST_INT.  The least
+   significant 11 bits of the value must be zero and the value must
+   not change sign when extended from 32 to 64 bits.  */
+int
+ldil_cint_p (HOST_WIDE_INT ival)
+{
+  HOST_WIDE_INT x = ival & (((HOST_WIDE_INT) -1 << 31) | 0x7ff);
+
+  return x == 0 || x == ((HOST_WIDE_INT) -1 << 31);
+}
+
 /* True iff zdepi can be used to generate this CONST_INT.
-   zdepi first sign extends a 5 bit signed number to a given field
+   zdepi first sign extends a 5-bit signed number to a given field
    length, then places this field anywhere in a zero.  */
 int
 zdepi_cint_p (unsigned HOST_WIDE_INT x)
@@ -621,6 +668,8 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
   /* Labels need special handling.  */
   if (pic_label_operand (orig, mode))
     {
+      rtx insn;
+
       /* We do not want to go through the movXX expanders here since that
         would create recursion.
 
@@ -631,8 +680,24 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
         So instead we just emit the raw set, which avoids the movXX
         expanders completely.  */
       mark_reg_pointer (reg, BITS_PER_UNIT);
-      emit_insn (gen_rtx_SET (VOIDmode, reg, orig));
-      current_function_uses_pic_offset_table = 1;
+      insn = emit_insn (gen_rtx_SET (VOIDmode, reg, orig));
+
+      /* Put a REG_EQUAL note on this insn, so that it can be optimized.  */
+      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.  */
+      if (reload_in_progress || reload_completed)
+       {
+         /* Extract LABEL_REF.  */
+         if (GET_CODE (orig) == CONST)
+           orig = XEXP (XEXP (orig, 0), 0);
+         /* Extract CODE_LABEL.  */
+         orig = XEXP (orig, 0);
+         add_reg_note (insn, REG_LABEL_OPERAND, orig);
+         LABEL_NUSES (orig)++;
+       }
+      crtl->uses_pic_offset_table = 1;
       return reg;
     }
   if (GET_CODE (orig) == SYMBOL_REF)
@@ -647,22 +712,44 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
       tmp_reg = ((reload_in_progress || reload_completed)
                 ? reg : gen_reg_rtx (Pmode));
 
-      emit_move_insn (tmp_reg,
-                     gen_rtx_PLUS (word_mode, pic_offset_table_rtx,
-                                   gen_rtx_HIGH (word_mode, orig)));
-      pic_ref
-       = gen_const_mem (Pmode,
-                        gen_rtx_LO_SUM (Pmode, tmp_reg,
-                                        gen_rtx_UNSPEC (Pmode,
+      if (function_label_operand (orig, mode))
+       {
+         /* 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,
+                                       gen_rtx_HIGH (word_mode, orig)));
+         pic_ref
+           = gen_const_mem (Pmode,
+                            gen_rtx_LO_SUM (Pmode, tmp_reg,
+                                            gen_rtx_UNSPEC (Pmode,
+                                                        gen_rtvec (1, orig),
+                                                        UNSPEC_DLTIND14R)));
+         emit_move_insn (reg, pic_ref);
+         /* Now load address of function descriptor.  */
+         pic_ref = gen_rtx_MEM (Pmode, reg);
+       }
+      else
+       {
+         /* Load symbol reference from DLT.  */
+         emit_move_insn (tmp_reg,
+                         gen_rtx_PLUS (word_mode, pic_offset_table_rtx,
+                                       gen_rtx_HIGH (word_mode, orig)));
+         pic_ref
+           = gen_const_mem (Pmode,
+                            gen_rtx_LO_SUM (Pmode, tmp_reg,
+                                            gen_rtx_UNSPEC (Pmode,
                                                         gen_rtvec (1, orig),
                                                         UNSPEC_DLTIND14R)));
+       }
 
-      current_function_uses_pic_offset_table = 1;
+      crtl->uses_pic_offset_table = 1;
       mark_reg_pointer (reg, BITS_PER_UNIT);
       insn = emit_move_insn (reg, pic_ref);
 
       /* 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));
+      set_unique_reg_note (insn, REG_EQUAL, orig);
 
       return reg;
     }
@@ -726,7 +813,10 @@ legitimize_tls_address (rtx addr)
     {
       case TLS_MODEL_GLOBAL_DYNAMIC:
        tmp = gen_reg_rtx (Pmode);
-       emit_insn (gen_tgd_load (tmp, addr));
+       if (flag_pic)
+         emit_insn (gen_tgd_load_pic (tmp, addr));
+       else
+         emit_insn (gen_tgd_load (tmp, addr));
        ret = hppa_tls_call (tmp);
        break;
 
@@ -734,7 +824,10 @@ legitimize_tls_address (rtx addr)
        ret = gen_reg_rtx (Pmode);
        tmp = gen_reg_rtx (Pmode);
        start_sequence ();
-       emit_insn (gen_tld_load (tmp, addr));
+       if (flag_pic)
+         emit_insn (gen_tld_load_pic (tmp, addr));
+       else
+         emit_insn (gen_tld_load (tmp, addr));
        t1 = hppa_tls_call (tmp);
        insn = get_insns ();
        end_sequence ();
@@ -750,7 +843,10 @@ legitimize_tls_address (rtx addr)
        tmp = gen_reg_rtx (Pmode);
        ret = gen_reg_rtx (Pmode);
        emit_insn (gen_tp_load (tp));
-       emit_insn (gen_tie_load (tmp, addr));
+       if (flag_pic)
+         emit_insn (gen_tie_load_pic (tmp, addr));
+       else
+         emit_insn (gen_tie_load (tmp, addr));
        emit_move_insn (ret, gen_rtx_PLUS (Pmode, tp, tmp));
        break;
 
@@ -775,9 +871,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.
 
@@ -870,7 +963,7 @@ hppa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
       int mask;
 
       mask = (GET_MODE_CLASS (mode) == MODE_FLOAT
-             ? (TARGET_PA_20 ? 0x3fff : 0x1f) : 0x3fff);
+             ? (INT14_OK_STRICT ? 0x3fff : 0x1f) : 0x3fff);
 
       /* Choose which way to round the offset.  Round up if we
         are >= halfway to the next boundary.  */
@@ -1183,7 +1276,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))
     {
@@ -1203,7 +1297,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)
     {
@@ -1330,8 +1425,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
      addresses from the destination operand.  */
   if (GET_CODE (operand0) == MEM && IS_INDEX_ADDR_P (XEXP (operand0, 0)))
     {
-      /* This is only safe up to the beginning of life analysis.  */
-      gcc_assert (!no_new_pseudos);
+      gcc_assert (can_create_pseudo_p ());
 
       tem = copy_to_mode_reg (Pmode, XEXP (operand0, 0));
       operand0 = replace_equiv_address (operand0, tem);
@@ -1616,8 +1710,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
                    decl = TREE_OPERAND (decl, 1);
 
                  type = TREE_TYPE (decl);
-                 if (TREE_CODE (type) == ARRAY_TYPE)
-                   type = get_inner_array_type (type);
+                 type = strip_array_types (type);
 
                  if (POINTER_TYPE_P (type))
                    {
@@ -1978,8 +2071,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
                }
            }
 
-         REG_NOTES (insn)
-           = gen_rtx_EXPR_LIST (REG_EQUAL, op1, REG_NOTES (insn));
+         set_unique_reg_note (insn, REG_EQUAL, op1);
 
          return 1;
        }
@@ -2001,14 +2093,14 @@ reloc_needed (tree exp)
     case ADDR_EXPR:
       return 1;
 
+    case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
     case MINUS_EXPR:
       reloc = reloc_needed (TREE_OPERAND (exp, 0));
       reloc |= reloc_needed (TREE_OPERAND (exp, 1));
       break;
 
-    case NOP_EXPR:
-    case CONVERT_EXPR:
+    CASE_CONVERT:
     case NON_LVALUE_EXPR:
       reloc = reloc_needed (TREE_OPERAND (exp, 0));
       break;
@@ -2121,9 +2213,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;
        }
 
@@ -2142,10 +2234,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;
@@ -2154,17 +2248,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;
     }
@@ -2338,12 +2435,11 @@ output_move_double (rtx *operands)
       else if (GET_CODE (addr) == PLUS
               && GET_CODE (XEXP (addr, 0)) == MULT)
        {
+         rtx xoperands[4];
          rtx high_reg = gen_rtx_SUBREG (SImode, operands[0], 0);
 
          if (!reg_overlap_mentioned_p (high_reg, addr))
            {
-             rtx xoperands[3];
-
              xoperands[0] = high_reg;
              xoperands[1] = XEXP (addr, 1);
              xoperands[2] = XEXP (XEXP (addr, 0), 0);
@@ -2354,8 +2450,6 @@ output_move_double (rtx *operands)
            }
          else
            {
-             rtx xoperands[3];
-
              xoperands[0] = high_reg;
              xoperands[1] = XEXP (addr, 1);
              xoperands[2] = XEXP (XEXP (addr, 0), 0);
@@ -3302,11 +3396,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);
@@ -3322,16 +3414,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)
@@ -3391,11 +3480,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
     {
@@ -3438,7 +3525,7 @@ compute_frame_size (HOST_WIDE_INT size, int *fregs_live)
   /* If the current function calls __builtin_eh_return, then we need
      to allocate stack space for registers that will hold data for
      the exception handler.  */
-  if (DO_FRAME_NOTES && current_function_calls_eh_return)
+  if (DO_FRAME_NOTES && crtl->calls_eh_return)
     {
       unsigned int i;
 
@@ -3449,13 +3536,13 @@ compute_frame_size (HOST_WIDE_INT size, int *fregs_live)
 
   /* Account for space used by the callee general register saves.  */
   for (i = 18, j = frame_pointer_needed ? 4 : 3; i >= j; i--)
-    if (regs_ever_live[i])
+    if (df_regs_ever_live_p (i))
       size += UNITS_PER_WORD;
 
   /* Account for space used by the callee floating point register saves.  */
   for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
-    if (regs_ever_live[i]
-       || (!TARGET_64BIT && regs_ever_live[i + 1]))
+    if (df_regs_ever_live_p (i)
+       || (!TARGET_64BIT && df_regs_ever_live_p (i + 1)))
       {
        freg_saved = 1;
 
@@ -3477,7 +3564,7 @@ compute_frame_size (HOST_WIDE_INT size, int *fregs_live)
      size of the current function's stack frame.  We don't need to align
      for the outgoing arguments as their alignment is set by the final
      rounding for the frame as a whole.  */
-  size += current_function_outgoing_args_size;
+  size += crtl->outgoing_args_size;
 
   /* Allocate space for the fixed frame marker.  This space must be
      allocated for any function that makes calls or allocates
@@ -3520,10 +3607,12 @@ pa_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
      to output the assembler directives which denote the start
      of a function.  */
   fprintf (file, "\t.CALLINFO FRAME=" HOST_WIDE_INT_PRINT_DEC, actual_fsize);
-  if (regs_ever_live[2])
-    fputs (",CALLS,SAVE_RP", file);
-  else
+  if (current_function_is_leaf)
     fputs (",NO_CALLS", file);
+  else
+    fputs (",CALLS", file);
+  if (rp_saved)
+    fputs (",SAVE_RP", file);
 
   /* The SAVE_SP flag is used to indicate that register %r3 is stored
      at the beginning of the frame and that it is used as the frame
@@ -3584,8 +3673,13 @@ hppa_expand_prologue (void)
   /* Save RP first.  The calling conventions manual states RP will
      always be stored into the caller's frame at sp - 20 or sp - 16
      depending on which ABI is in use.  */
-  if (regs_ever_live[2] || current_function_calls_eh_return)
-    store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
+  if (df_regs_ever_live_p (2) || crtl->calls_eh_return)
+    {
+      store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
+      rp_saved = true;
+    }
+  else
+    rp_saved = false;
 
   /* Allocate the local frame and set up the frame pointer if needed.  */
   if (actual_fsize != 0)
@@ -3679,7 +3773,7 @@ hppa_expand_prologue (void)
       /* Saving the EH return data registers in the frame is the simplest
         way to get the frame unwind information emitted.  We put them
         just before the general registers.  */
-      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+      if (DO_FRAME_NOTES && crtl->calls_eh_return)
        {
          unsigned int i, regno;
 
@@ -3695,7 +3789,7 @@ hppa_expand_prologue (void)
        }
 
       for (i = 18; i >= 4; i--)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_used_regs[i])
          {
            store_reg (i, offset, FRAME_POINTER_REGNUM);
            offset += UNITS_PER_WORD;
@@ -3711,7 +3805,7 @@ hppa_expand_prologue (void)
 
       /* Saving the EH return data registers in the frame is the simplest
          way to get the frame unwind information emitted.  */
-      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+      if (DO_FRAME_NOTES && crtl->calls_eh_return)
        {
          unsigned int i, regno;
 
@@ -3735,7 +3829,7 @@ hppa_expand_prologue (void)
        }
 
       for (i = 18; i >= 3; i--)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_used_regs[i])
          {
            /* If merge_sp_adjust_with_store is nonzero, then we can
               optimize the first GR save.  */
@@ -3798,8 +3892,8 @@ hppa_expand_prologue (void)
       /* Now actually save the FP registers.  */
       for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
        {
-         if (regs_ever_live[i]
-             || (! TARGET_64BIT && regs_ever_live[i + 1]))
+         if (df_regs_ever_live_p (i)
+             || (! TARGET_64BIT && df_regs_ever_live_p (i + 1)))
            {
              rtx addr, insn, reg;
              addr = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
@@ -3812,10 +3906,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
                    {
@@ -3832,10 +3924,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);
@@ -3887,23 +3977,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;
     }
 }
 
@@ -3967,6 +4052,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);
@@ -3987,7 +4074,7 @@ hppa_expand_epilogue (void)
   /* Try to restore RP early to avoid load/use interlocks when
      RP gets used in the return (bv) instruction.  This appears to still
      be necessary even when we schedule the prologue and epilogue.  */
-  if (regs_ever_live [2] || current_function_calls_eh_return)
+  if (rp_saved)
     {
       ret_off = TARGET_64BIT ? -16 : -20;
       if (frame_pointer_needed)
@@ -4013,7 +4100,7 @@ hppa_expand_epilogue (void)
 
       /* If the current function calls __builtin_eh_return, then we need
          to restore the saved EH data registers.  */
-      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+      if (DO_FRAME_NOTES && crtl->calls_eh_return)
        {
          unsigned int i, regno;
 
@@ -4029,7 +4116,7 @@ hppa_expand_epilogue (void)
        }
 
       for (i = 18; i >= 4; i--)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_used_regs[i])
          {
            load_reg (i, offset, FRAME_POINTER_REGNUM);
            offset += UNITS_PER_WORD;
@@ -4041,7 +4128,7 @@ hppa_expand_epilogue (void)
 
       /* If the current function calls __builtin_eh_return, then we need
          to restore the saved EH data registers.  */
-      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+      if (DO_FRAME_NOTES && crtl->calls_eh_return)
        {
          unsigned int i, regno;
 
@@ -4066,7 +4153,7 @@ hppa_expand_epilogue (void)
 
       for (i = 18; i >= 3; i--)
        {
-         if (regs_ever_live[i] && ! call_used_regs[i])
+         if (df_regs_ever_live_p (i) && ! call_used_regs[i])
            {
              /* Only for the first load.
                 merge_sp_adjust_with_load holds the register load
@@ -4096,8 +4183,8 @@ hppa_expand_epilogue (void)
 
       /* Actually do the restores now.  */
       for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
-       if (regs_ever_live[i]
-           || (! TARGET_64BIT && regs_ever_live[i + 1]))
+       if (df_regs_ever_live_p (i)
+           || (! TARGET_64BIT && df_regs_ever_live_p (i + 1)))
          {
            rtx src = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
            rtx dest = gen_rtx_REG (DFmode, i);
@@ -4138,7 +4225,7 @@ hppa_expand_epilogue (void)
   if (ret_off != 0)
     load_reg (2, ret_off, STACK_POINTER_REGNUM);
 
-  if (DO_FRAME_NOTES && current_function_calls_eh_return)
+  if (DO_FRAME_NOTES && crtl->calls_eh_return)
     {
       rtx sa = EH_RETURN_STACKADJ_RTX;
 
@@ -4208,7 +4295,7 @@ hppa_profile_hook (int label_no)
 
   emit_move_insn (gen_rtx_REG (word_mode, 26), gen_rtx_REG (word_mode, 2));
 
-  /* The address of the function is loaded into %r25 with a instruction-
+  /* The address of the function is loaded into %r25 with an instruction-
      relative sequence that avoids the use of relocations.  The sequence
      is split so that the load_offset_label_address instruction can
      occupy the delay slot of the call to _mcount.  */
@@ -4256,8 +4343,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));
+  add_reg_note (call_insn, REG_EH_REGION, constm1_rtx);
 }
 
 /* Fetch the return address for the frame COUNT steps up from
@@ -4294,6 +4380,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;
 
@@ -4302,6 +4401,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);
 
@@ -4313,37 +4415,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:
+     export stub.  If it is an export stub, than our return address is
+     really in -24[frameaddr].  */
 
-       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)
-
-     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,
@@ -4357,46 +4437,32 @@ return_addr_rtx (int count, rtx frameaddr)
                                                              -24))));
 
   emit_label (label);
-  return saved_rp;
-}
 
-/* This is only valid once reload has completed because it depends on
-   knowing exactly how much (if any) frame there is and...
-
-   It's only valid if there is no frame marker to de-allocate and...
-
-   It's only valid if %r2 hasn't been saved into the caller's frame
-   (we're not profiling and %r2 isn't live anywhere).  */
-int
-hppa_can_use_return_insn_p (void)
-{
-  return (reload_completed
-         && (compute_frame_size (get_frame_size (), 0) ? 0 : 1)
-         && ! regs_ever_live[2]
-         && ! frame_pointer_needed);
+  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.  */
 
@@ -4690,6 +4756,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
@@ -5333,7 +5400,7 @@ output_deferred_plabels (void)
   /* Now output the deferred plabels.  */
   for (i = 0; i < n_deferred_plabels; i++)
     {
-      (*targetm.asm_out.internal_label) (asm_out_file, "L",
+      targetm.asm_out.internal_label (asm_out_file, "L",
                 CODE_LABEL_NUMBER (deferred_plabels[i].internal_label));
       assemble_integer (deferred_plabels[i].symbol,
                        TARGET_64BIT ? 8 : 4, TARGET_64BIT ? 64 : 32, 1);
@@ -5603,19 +5670,19 @@ output_arg_descriptor (rtx call_insn)
 }
 \f
 static enum reg_class
-pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
+pa_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
                     enum machine_mode mode, secondary_reload_info *sri)
 {
   int is_symbolic, regno;
 
   /* 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
@@ -5631,7 +5698,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
@@ -5644,12 +5711,49 @@ pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
   if (regno >= FIRST_PSEUDO_REGISTER || GET_CODE (x) == SUBREG)
     regno = true_regnum (x);
 
-  /* Handle out of range displacement for integer mode loads/stores of
-     FP registers.  */
-  if (((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
-       && GET_MODE_CLASS (mode) == MODE_INT
-       && FP_REG_CLASS_P (class))
-      || (class == SHIFT_REGS && (regno <= 0 || regno >= 32)))
+  /* In order to allow 14-bit displacements in integer loads and stores,
+     we need to prevent reload from generating out of range integer mode
+     loads and stores to the floating point registers.  Previously, we
+     used to call for a secondary reload and have emit_move_sequence()
+     fix the instruction sequence.  However, reload occasionally wouldn't
+     generate the reload and we would end up with an invalid REG+D memory
+     address.  So, now we use an intermediate general register for most
+     memory loads and stores.  */
+  if ((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
+      && GET_MODE_CLASS (mode) == MODE_INT
+      && 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
+        REG+D address.  */
+      if (GET_CODE (x) == MEM)
+       {
+         x = XEXP (x, 0);
+
+         /* We don't need an intermediate for indexed and LO_SUM DLT
+            memory addresses.  When INT14_OK_STRICT is true, it might
+            appear that we could directly allow register indirect
+            memory addresses.  However, this doesn't work because we
+            don't support SUBREGs in floating-point register copies
+            and reload doesn't tell us when it's going to use a SUBREG.  */
+         if (IS_INDEX_ADDR_P (x)
+             || IS_LO_SUM_DLT_ADDR_P (x))
+           return NO_REGS;
+
+         /* Otherwise, we need an intermediate general register.  */
+         return GENERAL_REGS;
+       }
+
+      /* 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];
+      return NO_REGS;
+    }
+
+  /* We need a secondary register (GPR) for copies between the SAR
+     and anything other than a general register.  */
+  if (rclass == SHIFT_REGS && (regno <= 0 || regno >= 32))
     {
       sri->icode = in_p ? reload_in_optab[mode] : reload_out_optab[mode];
       return NO_REGS;
@@ -5658,16 +5762,15 @@ pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
   /* A SAR<->FP register copy requires a secondary register (GPR) as
      well as secondary memory.  */
   if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
-      && ((REGNO_REG_CLASS (regno) == SHIFT_REGS && FP_REG_CLASS_P (class))
-         || (class == SHIFT_REGS
-             && FP_REG_CLASS_P (REGNO_REG_CLASS (regno)))))
+      && (REGNO_REG_CLASS (regno) == SHIFT_REGS
+      && FP_REG_CLASS_P (rclass)))
     {
       sri->icode = in_p ? reload_in_optab[mode] : reload_out_optab[mode];
       return NO_REGS;
     }
 
   /* Secondary reloads of symbolic operands require %r1 as a scratch
-     register when we're generating PIC code and the operand isn't
+     register when we're generating PIC code and when the operand isn't
      readonly.  */
   if (GET_CODE (x) == HIGH)
     x = XEXP (x, 0);
@@ -5707,6 +5810,33 @@ pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
   return NO_REGS;
 }
 
+/* Implement TARGET_EXTRA_LIVE_ON_ENTRY.  The argument pointer
+   is only marked as live on entry by df-scan when it is a fixed
+   register.  It isn't a fixed register in the 64-bit runtime,
+   so we need to mark it here.  */
+
+static void
+pa_extra_live_on_entry (bitmap regs)
+{
+  if (TARGET_64BIT)
+    bitmap_set_bit (regs, ARG_POINTER_REGNUM);
+}
+
+/* Implement EH_RETURN_HANDLER_RTX.  The MEM needs to be volatile
+   to prevent it from being deleted.  */
+
+rtx
+pa_eh_return_handler_rtx (void)
+{
+  rtx tmp;
+
+  tmp = gen_rtx_PLUS (word_mode, frame_pointer_rtx,
+                     TARGET_64BIT ? GEN_INT (-16) : GEN_INT (-20));
+  tmp = gen_rtx_MEM (word_mode, tmp);
+  tmp->volatil = 1;
+  return tmp;
+}
+
 /* In the 32-bit runtime, arguments larger than eight bytes are passed
    by invisible reference.  As a GCC extension, we also pass anything
    with a zero or variable size by reference.
@@ -5722,7 +5852,7 @@ pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
 
 static bool
 pa_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
-                     enum machine_mode mode, tree type,
+                     enum machine_mode mode, const_tree type,
                      bool named ATTRIBUTE_UNUSED)
 {
   HOST_WIDE_INT size;
@@ -5739,10 +5869,14 @@ pa_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
 }
 
 enum direction
-function_arg_padding (enum machine_mode mode, tree type)
+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
@@ -5788,9 +5922,9 @@ hppa_builtin_saveregs (void)
                ? UNITS_PER_WORD : 0);
 
   if (argadj)
-    offset = plus_constant (current_function_arg_offset_rtx, argadj);
+    offset = plus_constant (crtl->args.arg_offset_rtx, argadj);
   else
-    offset = current_function_arg_offset_rtx;
+    offset = crtl->args.arg_offset_rtx;
 
   if (TARGET_64BIT)
     {
@@ -5798,9 +5932,9 @@ hppa_builtin_saveregs (void)
 
       /* Adjust for varargs/stdarg differences.  */
       if (argadj)
-       offset = plus_constant (current_function_arg_offset_rtx, -argadj);
+       offset = plus_constant (crtl->args.arg_offset_rtx, -argadj);
       else
-       offset = current_function_arg_offset_rtx;
+       offset = crtl->args.arg_offset_rtx;
 
       /* We need to save %r26 .. %r19 inclusive starting at offset -64
         from the incoming arg pointer and growing to larger addresses.  */
@@ -5824,7 +5958,7 @@ hppa_builtin_saveregs (void)
 
   /* Store general registers on the stack.  */
   dest = gen_rtx_MEM (BLKmode,
-                     plus_constant (current_function_internal_arg_pointer,
+                     plus_constant (crtl->args.internal_arg_pointer,
                                     -16));
   set_mem_alias_set (dest, get_varargs_alias_set ());
   set_mem_align (dest, BITS_PER_WORD);
@@ -5842,11 +5976,11 @@ hppa_builtin_saveregs (void)
   emit_insn (gen_blockage ());
 
   return copy_to_reg (expand_binop (Pmode, add_optab,
-                                   current_function_internal_arg_pointer,
+                                   crtl->args.internal_arg_pointer,
                                    offset, 0, 0, OPTAB_LIB_WIDEN));
 }
 
-void
+static void
 hppa_va_start (tree valist, rtx nextarg)
 {
   nextarg = expand_builtin_saveregs ();
@@ -5854,7 +5988,8 @@ hppa_va_start (tree valist, rtx nextarg)
 }
 
 static tree
-hppa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
+hppa_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
+                          gimple_seq *post_p)
 {
   if (TARGET_64BIT)
     {
@@ -5880,21 +6015,24 @@ hppa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
 
       /* Args grow down.  Not handled by generic routines.  */
 
-      u = fold_convert (valist_type, size_in_bytes (type));
-      t = build2 (MINUS_EXPR, valist_type, valist, u);
+      u = fold_convert (sizetype, size_in_bytes (type));
+      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 = build_int_cst (valist_type, (size > 4 ? -8 : -4));
-      t = build2 (BIT_AND_EXPR, valist_type, t, u);
+      u = size_int (size > 4 ? -8 : -4);
+      t = fold_convert (sizetype, t);
+      t = build2 (BIT_AND_EXPR, sizetype, t, u);
+      t = fold_convert (valist_type, t);
 
       t = build2 (MODIFY_EXPR, valist_type, valist, t);
 
       ofs = (8 - size) % 4;
       if (ofs != 0)
        {
-         u = fold_convert (valist_type, size_int (ofs));
-         t = build2 (PLUS_EXPR, valist_type, t, u);
+         u = size_int (ofs);
+         t = build2 (POINTER_PLUS_EXPR, valist_type, t, u);
        }
 
       t = fold_convert (ptr, t);
@@ -5954,6 +6092,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,
@@ -5979,7 +6149,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
@@ -6028,7 +6198,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;
@@ -6189,9 +6364,7 @@ output_lbranch (rtx dest, rtx insn, int xdelay)
                       optimize, 0, NULL);
 
       /* Now delete the delay insn.  */
-      PUT_CODE (NEXT_INSN (insn), NOTE);
-      NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-      NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+      SET_INSN_DELETED (NEXT_INSN (insn));
     }
 
   /* Output an insn to save %r1.  The runtime documentation doesn't
@@ -6216,7 +6389,7 @@ output_lbranch (rtx dest, rtx insn, int xdelay)
      for other purposes.  */
   if (TARGET_64BIT)
     {
-      if (actual_fsize == 0 && !regs_ever_live[2])
+      if (actual_fsize == 0 && !df_regs_ever_live_p (2))
        /* Use the return pointer slot in the frame marker.  */
        output_asm_insn ("std %%r1,-16(%%r30)", xoperands);
       else
@@ -6226,7 +6399,7 @@ output_lbranch (rtx dest, rtx insn, int xdelay)
     }
   else
     {
-      if (actual_fsize == 0 && !regs_ever_live[2])
+      if (actual_fsize == 0 && !df_regs_ever_live_p (2))
        /* Use the return pointer slot in the frame marker.  */
        output_asm_insn ("stw %%r1,-20(%%r30)", xoperands);
       else
@@ -6252,8 +6425,8 @@ output_lbranch (rtx dest, rtx insn, int xdelay)
        {
          xoperands[1] = gen_label_rtx ();
          output_asm_insn ("addil L'%l0-%l1,%%r1", xoperands);
-         (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                            CODE_LABEL_NUMBER (xoperands[1]));
+         targetm.asm_out.internal_label (asm_out_file, "L",
+                                         CODE_LABEL_NUMBER (xoperands[1]));
          output_asm_insn ("ldo R'%l0-%l1(%%r1),%%r1", xoperands);
        }
       else
@@ -6270,14 +6443,14 @@ output_lbranch (rtx dest, rtx insn, int xdelay)
   /* Now restore the value of %r1 in the delay slot.  */
   if (TARGET_64BIT)
     {
-      if (actual_fsize == 0 && !regs_ever_live[2])
+      if (actual_fsize == 0 && !df_regs_ever_live_p (2))
        return "ldd -16(%%r30),%%r1";
       else
        return "ldd -40(%%r30),%%r1";
     }
   else
     {
-      if (actual_fsize == 0 && !regs_ever_live[2])
+      if (actual_fsize == 0 && !df_regs_ever_live_p (2))
        return "ldw -20(%%r30),%%r1";
       else
        return "ldw -12(%%r30),%%r1";
@@ -6303,7 +6476,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'
@@ -6349,11 +6522,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;
@@ -6484,7 +6667,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'
@@ -6530,11 +6713,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;
@@ -6656,7 +6849,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";
@@ -6693,7 +6886,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";
       
@@ -6801,7 +6999,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";
@@ -6839,7 +7037,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";
 
@@ -7112,7 +7315,7 @@ output_millicode_call (rtx insn, rtx call_dest)
            {
              xoperands[1] = gen_label_rtx ();
              output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
-             (*targetm.asm_out.internal_label) (asm_out_file, "L",
+             targetm.asm_out.internal_label (asm_out_file, "L",
                                         CODE_LABEL_NUMBER (xoperands[1]));
              output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
            }
@@ -7156,7 +7359,7 @@ output_millicode_call (rtx insn, rtx call_dest)
                 millicode symbol but not an arbitrary external
                 symbol when generating SOM output.  */
              xoperands[1] = gen_label_rtx ();
-             (*targetm.asm_out.internal_label) (asm_out_file, "L",
+             targetm.asm_out.internal_label (asm_out_file, "L",
                                         CODE_LABEL_NUMBER (xoperands[1]));
              output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
              output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
@@ -7195,8 +7398,8 @@ output_millicode_call (rtx insn, rtx call_dest)
        {
          xoperands[1] = gen_label_rtx ();
          output_asm_insn ("ldo %0-%1(%2),%2", xoperands);
-         (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                            CODE_LABEL_NUMBER (xoperands[1]));
+         targetm.asm_out.internal_label (asm_out_file, "L",
+                                         CODE_LABEL_NUMBER (xoperands[1]));
        }
       else
        /* ??? This branch may not reach its target.  */
@@ -7207,9 +7410,7 @@ output_millicode_call (rtx insn, rtx call_dest)
     output_asm_insn ("nop\n\tb,n %0", xoperands);
 
   /* Delete the jump.  */
-  PUT_CODE (NEXT_INSN (insn), NOTE);
-  NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-  NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+  SET_INSN_DELETED (NEXT_INSN (insn));
 
   return "";
 }
@@ -7231,12 +7432,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;
@@ -7247,14 +7450,19 @@ 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);
+  local_call = call_decl && targetm.binds_local_p (call_decl);
 
   /* pc-relative branch.  */
   if (!TARGET_LONG_CALLS
@@ -7271,13 +7479,13 @@ attr_length_call (rtx insn, int sibcall)
     length += 12;
 
   /* long pc-relative branch sequence.  */
-  else if ((TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
-          || (TARGET_64BIT && !TARGET_GAS)
-          || (TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call)))
+  else if (TARGET_LONG_PIC_SDIFF_CALL
+          || (TARGET_GAS && !TARGET_SOM
+              && (TARGET_LONG_PIC_PCREL_CALL || local_call)))
     {
       length += 20;
 
-      if (!TARGET_PA_20 && !TARGET_NO_SPACE_REGS)
+      if (!TARGET_PA_20 && !TARGET_NO_SPACE_REGS && flag_pic)
        length += 8;
     }
 
@@ -7297,7 +7505,7 @@ attr_length_call (rtx insn, int sibcall)
          if (!sibcall)
            length += 8;
 
-         if (!TARGET_NO_SPACE_REGS)
+         if (!TARGET_NO_SPACE_REGS && flag_pic)
            length += 8;
        }
     }
@@ -7317,7 +7525,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
   int delay_slot_filled = 0;
   int seq_length = dbr_sequence_length ();
   tree call_decl = SYMBOL_REF_DECL (call_dest);
-  int local_call = call_decl && (*targetm.binds_local_p) (call_decl);
+  int local_call = call_decl && targetm.binds_local_p (call_decl);
   rtx xoperands[2];
 
   xoperands[0] = call_dest;
@@ -7351,9 +7559,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
                               optimize, 0, NULL);
 
              /* Now delete the delay insn.  */
-             PUT_CODE (NEXT_INSN (insn), NOTE);
-             NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+             SET_INSN_DELETED (NEXT_INSN (insn));
              delay_insn_deleted = 1;
            }
 
@@ -7383,15 +7589,18 @@ output_call (rtx insn, rtx call_dest, int sibcall)
             of increasing length and complexity.  In most cases,
              they don't allow an instruction in the delay slot.  */
          if (!((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)
-             && !(TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
-             && !(TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call))
+             && !TARGET_LONG_PIC_SDIFF_CALL
+             && !(TARGET_GAS && !TARGET_SOM
+                  && (TARGET_LONG_PIC_PCREL_CALL || local_call))
              && !TARGET_64BIT)
            indirect_call = 1;
 
          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
@@ -7400,9 +7609,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
                               NULL);
 
              /* Now delete the delay insn.  */
-             PUT_CODE (NEXT_INSN (insn), NOTE);
-             NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+             SET_INSN_DELETED (NEXT_INSN (insn));
              delay_insn_deleted = 1;
            }
 
@@ -7430,21 +7637,21 @@ output_call (rtx insn, rtx call_dest, int sibcall)
            }
          else
            {
-             if ((TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
-                 || (TARGET_64BIT && !TARGET_GAS))
+             if (TARGET_LONG_PIC_SDIFF_CALL)
                {
                  /* The HP assembler and linker can handle relocations
-                    for the difference of two symbols.  GAS and the HP
-                    linker can't do this when one of the symbols is
-                    external.  */
+                    for the difference of two symbols.  The HP assembler
+                    recognizes the sequence as a pc-relative call and
+                    the linker provides stubs when needed.  */
                  xoperands[1] = gen_label_rtx ();
                  output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
                  output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
-                 (*targetm.asm_out.internal_label) (asm_out_file, "L",
+                 targetm.asm_out.internal_label (asm_out_file, "L",
                                             CODE_LABEL_NUMBER (xoperands[1]));
                  output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
                }
-             else if (TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call))
+             else if (TARGET_GAS && !TARGET_SOM
+                      && (TARGET_LONG_PIC_PCREL_CALL || local_call))
                {
                  /*  GAS currently can't generate the relocations that
                      are needed for the SOM linker under HP-UX using this
@@ -7520,20 +7727,20 @@ output_call (rtx insn, rtx call_dest, int sibcall)
                }
              else
                {
-                 if (!TARGET_NO_SPACE_REGS)
+                 if (!TARGET_NO_SPACE_REGS && flag_pic)
                    output_asm_insn ("ldsid (%%r1),%%r31\n\tmtsp %%r31,%%sr0",
                                     xoperands);
 
                  if (sibcall)
                    {
-                     if (TARGET_NO_SPACE_REGS)
+                     if (TARGET_NO_SPACE_REGS || !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)
+                     if (TARGET_NO_SPACE_REGS || !flag_pic)
                        output_asm_insn ("ble 0(%%sr4,%%r1)", xoperands);
                      else
                        output_asm_insn ("ble 0(%%sr0,%%r1)", xoperands);
@@ -7567,17 +7774,20 @@ 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);
-         (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                            CODE_LABEL_NUMBER (xoperands[1]));
+         targetm.asm_out.internal_label (asm_out_file, "L",
+                                         CODE_LABEL_NUMBER (xoperands[1]));
        }
       else
        output_asm_insn ("nop\n\tb,n %0", xoperands);
@@ -7586,9 +7796,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
     output_asm_insn ("b,n %0", xoperands);
 
   /* Delete the jump.  */
-  PUT_CODE (NEXT_INSN (insn), NOTE);
-  NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-  NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+  SET_INSN_DELETED (NEXT_INSN (insn));
 
   return "";
 }
@@ -7680,8 +7888,8 @@ output_indirect_call (rtx insn, rtx call_dest)
     {
       xoperands[0] = gen_label_rtx ();
       output_asm_insn ("addil L'$$dyncall-%0,%%r1", xoperands);
-      (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                        CODE_LABEL_NUMBER (xoperands[0]));
+      targetm.asm_out.internal_label (asm_out_file, "L",
+                                     CODE_LABEL_NUMBER (xoperands[0]));
       output_asm_insn ("ldo R'$$dyncall-%0(%%r1),%%r1", xoperands);
     }
   else
@@ -7722,7 +7930,7 @@ hppa_encode_label (rtx sym)
   int len = strlen (str) + 1;
   char *newstr, *p;
 
-  p = newstr = alloca (len + 1);
+  p = newstr = XALLOCAVEC (char, len + 1);
   *p++ = '@';
   strcpy (p, str);
 
@@ -7732,6 +7940,12 @@ hppa_encode_label (rtx sym)
 static void
 pa_encode_section_info (tree decl, rtx rtl, int first)
 {
+  int old_referenced = 0;
+
+  if (!first && MEM_P (rtl) && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF)
+    old_referenced
+      = SYMBOL_REF_FLAGS (XEXP (rtl, 0)) & SYMBOL_FLAG_REFERENCED;
+
   default_encode_section_info (decl, rtl, first);
 
   if (first && TEXT_SPACE_P (decl))
@@ -7740,6 +7954,8 @@ pa_encode_section_info (tree decl, rtx rtl, int first)
       if (TREE_CODE (decl) == FUNCTION_DECL)
        hppa_encode_label (XEXP (rtl, 0));
     }
+  else if (old_referenced)
+    SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= old_referenced;
 }
 
 /* This is sort of inverse to pa_encode_section_info.  */
@@ -7782,7 +7998,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];
 
@@ -7821,6 +8037,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)
@@ -8015,6 +8235,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);
 }
 
@@ -8072,7 +8294,7 @@ pa_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
    space register selection rules for memory addresses.  Therefore, we
    don't consider a + b == b + a, as this might be inside a MEM.  */
 static bool
-pa_commutative_p (rtx x, int outer_code)
+pa_commutative_p (const_rtx x, int outer_code)
 {
   return (COMMUTATIVE_P (x)
          && (TARGET_NO_SPACE_REGS
@@ -8347,7 +8569,7 @@ borx_reg_operand (rtx op, enum machine_mode mode)
      profitable to do so when the frame pointer is being eliminated.  */
   if (!reload_completed
       && flag_omit_frame_pointer
-      && !current_function_calls_alloca
+      && !cfun->calls_alloca
       && op == frame_pointer_rtx)
     return 0;
 
@@ -8362,22 +8584,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.  */
@@ -8684,7 +8912,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
@@ -8696,8 +8924,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))
     {
@@ -8753,7 +8981,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)))
@@ -8765,7 +8993,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)))
@@ -8773,7 +9001,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))))
@@ -8815,7 +9043,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),
@@ -8839,9 +9067,7 @@ pa_combine_instructions (void)
                                            PATTERN (floater))),
                                anchor);
 
-             PUT_CODE (anchor, NOTE);
-             NOTE_LINE_NUMBER (anchor) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (anchor) = 0;
+             SET_INSN_DELETED (anchor);
 
              /* Emit a special USE insn for FLOATER, then delete
                 the floating insn.  */
@@ -8863,9 +9089,7 @@ pa_combine_instructions (void)
                                         anchor);
 
              JUMP_LABEL (temp) = JUMP_LABEL (anchor);
-             PUT_CODE (anchor, NOTE);
-             NOTE_LINE_NUMBER (anchor) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (anchor) = 0;
+             SET_INSN_DELETED (anchor);
 
              /* Emit a special USE insn for FLOATER, then delete
                 the floating insn.  */
@@ -8878,7 +9102,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;
@@ -8891,12 +9115,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)
@@ -8973,7 +9197,7 @@ insn_refs_are_delayed (rtx insn)
    to match the HP Compiler ABI.  */
 
 rtx
-function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
+function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
 {
   enum machine_mode valmode;
 
@@ -9016,7 +9240,7 @@ function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
     }
 
   if ((INTEGRAL_TYPE_P (valtype)
-       && TYPE_PRECISION (valtype) < BITS_PER_WORD)
+       && GET_MODE_BITSIZE (TYPE_MODE (valtype)) < BITS_PER_WORD)
       || POINTER_TYPE_P (valtype))
     valmode = word_mode;
   else
@@ -9273,7 +9497,7 @@ som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
   gcc_assert (TARGET_SOM);
   if (TARGET_GAS)
     {
-      if (cfun && !cfun->machine->in_nsubspa)
+      if (cfun && cfun->machine && !cfun->machine->in_nsubspa)
        {
          /* We only want to emit a .nsubspa directive once at the
             start of the function.  */
@@ -9298,7 +9522,8 @@ som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
             text section to output debugging information.  Thus, we
             need to forget that we are in the text section so that
             varasm.c will call us when text_section is selected again.  */
-         gcc_assert (!cfun || cfun->machine->in_nsubspa == 2);
+         gcc_assert (!cfun || !cfun->machine
+                     || cfun->machine->in_nsubspa == 2);
          in_section = NULL;
        }
       output_section_asm_op ("\t.SPACE $TEXT$\n\t.NSUBSPA $CODE$");
@@ -9432,7 +9657,7 @@ pa_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
 
 bool
-pa_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+pa_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   /* SOM ABI says that objects larger than 64 bits are returned in memory.
      PA64 ABI says that objects larger than 128 bits are returned in memory.
@@ -9451,7 +9676,7 @@ pa_return_in_memory (tree type, 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;
@@ -9507,4 +9732,62 @@ pa_hpux_file_end (void)
 }
 #endif
 
+/* Return true if a change from mode FROM to mode TO for a register
+   in register class RCLASS is invalid.  */
+
+bool
+pa_cannot_change_mode_class (enum machine_mode from, enum machine_mode to,
+                            enum reg_class rclass)
+{
+  if (from == to)
+    return false;
+
+  /* Reject changes to/from complex and vector modes.  */
+  if (COMPLEX_MODE_P (from) || VECTOR_MODE_P (from)
+      || COMPLEX_MODE_P (to) || VECTOR_MODE_P (to))
+    return true;
+      
+  if (GET_MODE_SIZE (from) == GET_MODE_SIZE (to))
+    return false;
+
+  /* There is no way to load QImode or HImode values directly from
+     memory.  SImode loads to the FP registers are not zero extended.
+     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 (rclass))
+    return true;
+
+  /* HARD_REGNO_MODE_OK places modes with sizes larger than a word
+     in specific sets of registers.  Thus, we cannot allow changing
+     to a larger mode when it's larger than a word.  */
+  if (GET_MODE_SIZE (to) > UNITS_PER_WORD
+      && GET_MODE_SIZE (to) > GET_MODE_SIZE (from))
+    return true;
+
+  return false;
+}
+
+/* Returns TRUE if it is a good idea to tie two pseudo registers
+   when one has mode MODE1 and one has mode MODE2.
+   If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
+   for any hard reg, then this must be FALSE for correct output.
+   
+   We should return FALSE for QImode and HImode because these modes
+   are not ok in the floating-point registers.  However, this prevents
+   tieing these modes to SImode and DImode in the general registers.
+   So, this isn't a good idea.  We rely on HARD_REGNO_MODE_OK and
+   CANNOT_CHANGE_MODE_CLASS to prevent these modes from being used
+   in the floating-point registers.  */
+
+bool
+pa_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
+{
+  /* Don't tie modes in different classes.  */
+  if (GET_MODE_CLASS (mode1) != GET_MODE_CLASS (mode2))
+    return false;
+
+  return true;
+}
+
 #include "gt-pa.h"