OSDN Git Service

* config/ia64/ia64.c (ia64_load_pair_ok): Return 0 if the second member
[pf3gnuchains/gcc-fork.git] / gcc / config / ia64 / ia64.c
index 1f433a6..77be757 100644 (file)
@@ -1,6 +1,7 @@
 /* Definitions of target machine for GNU compiler.
    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009  Free Software Foundation, Inc.
+   2009, 2010, 2011
+   Free Software Foundation, Inc.
    Contributed by James E. Wilson <wilson@cygnus.com> and
                  David Mosberger <davidm@hpl.hp.com>.
 
@@ -28,7 +29,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "regs.h"
 #include "hard-reg-set.h"
-#include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
 #include "output.h"
@@ -41,7 +41,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "function.h"
 #include "ggc.h"
 #include "basic-block.h"
-#include "toplev.h"
+#include "libfuncs.h"
+#include "diagnostic-core.h"
 #include "sched-int.h"
 #include "timevar.h"
 #include "target.h"
@@ -58,6 +59,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "tm-constrs.h"
 #include "sel-sched.h"
+#include "reload.h"
+#include "dwarf2out.h"
+#include "opts.h"
 
 /* This is used for communication between ASM_OUTPUT_LABEL and
    ASM_OUTPUT_LABELREF.  */
@@ -99,17 +103,6 @@ static const char * const ia64_local_reg_names[80] =
 static const char * const ia64_output_reg_names[8] =
 { "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7" };
 
-/* Which cpu are we scheduling for.  */
-enum processor_type ia64_tune = PROCESSOR_ITANIUM2;
-
-/* Determines whether we run our final scheduling pass or not.  We always
-   avoid the normal second scheduling pass.  */
-static int ia64_flag_schedule_insns2;
-
-/* Determines whether we run variable tracking in machine dependent
-   reorganization.  */
-static int ia64_flag_var_tracking;
-
 /* Variables which are this size or smaller are put in the sdata/sbss
    sections.  */
 
@@ -198,17 +191,35 @@ static rtx gen_movdi_x (rtx, rtx, rtx);
 static rtx gen_fr_spill_x (rtx, rtx, rtx);
 static rtx gen_fr_restore_x (rtx, rtx, rtx);
 
+static void ia64_option_override (void);
+static bool ia64_can_eliminate (const int, const int);
 static enum machine_mode hfa_element_mode (const_tree, bool);
-static void ia64_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
+static void ia64_setup_incoming_varargs (cumulative_args_t, enum machine_mode,
                                         tree, int *, int);
-static int ia64_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+static int ia64_arg_partial_bytes (cumulative_args_t, enum machine_mode,
                                   tree, bool);
+static rtx ia64_function_arg_1 (cumulative_args_t, enum machine_mode,
+                               const_tree, bool, bool);
+static rtx ia64_function_arg (cumulative_args_t, enum machine_mode,
+                             const_tree, bool);
+static rtx ia64_function_incoming_arg (cumulative_args_t,
+                                      enum machine_mode, const_tree, bool);
+static void ia64_function_arg_advance (cumulative_args_t, enum machine_mode,
+                                      const_tree, bool);
+static unsigned int ia64_function_arg_boundary (enum machine_mode,
+                                               const_tree);
 static bool ia64_function_ok_for_sibcall (tree, tree);
 static bool ia64_return_in_memory (const_tree, const_tree);
-static bool ia64_rtx_costs (rtx, int, int, int *, bool);
+static rtx ia64_function_value (const_tree, const_tree, bool);
+static rtx ia64_libcall_value (enum machine_mode, const_rtx);
+static bool ia64_function_value_regno_p (const unsigned int);
+static int ia64_register_move_cost (enum machine_mode, reg_class_t,
+                                    reg_class_t);
+static int ia64_memory_move_cost (enum machine_mode mode, reg_class_t,
+                                 bool);
+static bool ia64_rtx_costs (rtx, int, int, int, int *, bool);
 static int ia64_unspec_may_trap_p (const_rtx, unsigned);
 static void fix_range (const char *);
-static bool ia64_handle_option (size_t, const char *, int);
 static struct machine_function * ia64_init_machine_status (void);
 static void emit_insn_group_barriers (FILE *);
 static void emit_all_insn_group_barriers (FILE *);
@@ -217,13 +228,16 @@ static void emit_predicate_relation_info (void);
 static void ia64_reorg (void);
 static bool ia64_in_small_data_p (const_tree);
 static void process_epilogue (FILE *, rtx, bool, bool);
-static int process_set (FILE *, rtx, rtx, bool, bool);
 
 static bool ia64_assemble_integer (rtx, unsigned int, int);
 static void ia64_output_function_prologue (FILE *, HOST_WIDE_INT);
 static void ia64_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void ia64_output_function_end_prologue (FILE *);
 
+static void ia64_print_operand (FILE *, rtx, int);
+static void ia64_print_operand_address (FILE *, rtx);
+static bool ia64_print_operand_punct_valid_p (unsigned char code);
+
 static int ia64_issue_rate (void);
 static int ia64_adjust_cost_2 (rtx, int, rtx, int, dw_t);
 static void ia64_sched_init (FILE *, int, int);
@@ -235,6 +249,12 @@ static int ia64_sched_reorder (FILE *, int, rtx *, int *, int);
 static int ia64_sched_reorder2 (FILE *, int, rtx *, int *, int);
 static int ia64_variable_issue (FILE *, int, rtx, int);
 
+static void ia64_asm_unwind_emit (FILE *, rtx);
+static void ia64_asm_emit_except_personality (rtx);
+static void ia64_asm_init_sections (void);
+
+static enum unwind_info_type ia64_debug_unwind_info (void);
+
 static struct bundle_state *get_free_bundle_state (void);
 static void free_bundle_state (struct bundle_state *);
 static void initiate_bundle_states (void);
@@ -276,6 +296,10 @@ static void ia64_vms_init_libfuncs (void)
      ATTRIBUTE_UNUSED;
 static void ia64_soft_fp_init_libfuncs (void)
      ATTRIBUTE_UNUSED;
+static bool ia64_vms_valid_pointer_mode (enum machine_mode mode)
+     ATTRIBUTE_UNUSED;
+static tree ia64_vms_common_object_attribute (tree *, tree, tree, int, bool *)
+     ATTRIBUTE_UNUSED;
 
 static tree ia64_handle_model_attribute (tree *, tree, tree, int, bool *);
 static tree ia64_handle_version_id_attribute (tree *, tree, tree, int, bool *);
@@ -284,22 +308,57 @@ static rtx ia64_struct_value_rtx (tree, int);
 static tree ia64_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
 static bool ia64_scalar_mode_supported_p (enum machine_mode mode);
 static bool ia64_vector_mode_supported_p (enum machine_mode mode);
-static bool ia64_cannot_force_const_mem (rtx);
+static bool ia64_legitimate_constant_p (enum machine_mode, rtx);
+static bool ia64_legitimate_address_p (enum machine_mode, rtx, bool);
+static bool ia64_cannot_force_const_mem (enum machine_mode, rtx);
 static const char *ia64_mangle_type (const_tree);
 static const char *ia64_invalid_conversion (const_tree, const_tree);
 static const char *ia64_invalid_unary_op (int, const_tree);
 static const char *ia64_invalid_binary_op (int, const_tree, const_tree);
 static enum machine_mode ia64_c_mode_for_suffix (char);
+static void ia64_trampoline_init (rtx, tree, rtx);
+static void ia64_override_options_after_change (void);
+
+static tree ia64_builtin_decl (unsigned, bool);
+
+static reg_class_t ia64_preferred_reload_class (rtx, reg_class_t);
+static enum machine_mode ia64_get_reg_raw_mode (int regno);
+static section * ia64_hpux_function_section (tree, enum node_frequency,
+                                            bool, bool);
+
+static bool ia64_vectorize_vec_perm_const_ok (enum machine_mode vmode,
+                                             const unsigned char *sel);
+
+#define MAX_VECT_LEN   8
+
+struct expand_vec_perm_d
+{
+  rtx target, op0, op1;
+  unsigned char perm[MAX_VECT_LEN];
+  enum machine_mode vmode;
+  unsigned char nelt;
+  bool one_operand_p;
+  bool testing_p; 
+};
+
+static bool ia64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d);
+
 \f
 /* Table of valid machine attributes.  */
 static const struct attribute_spec ia64_attribute_table[] =
 {
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
-  { "syscall_linkage", 0, 0, false, true,  true,  NULL },
-  { "model",          1, 1, true, false, false, ia64_handle_model_attribute },
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+       affects_type_identity } */
+  { "syscall_linkage", 0, 0, false, true,  true,  NULL, false },
+  { "model",          1, 1, true, false, false, ia64_handle_model_attribute,
+    false },
+#if TARGET_ABI_OPEN_VMS
+  { "common_object",   1, 1, true, false, false,
+    ia64_vms_common_object_attribute, false },
+#endif
   { "version_id",      1, 1, true, false, false,
-    ia64_handle_version_id_attribute },
-  { NULL,             0, 0, false, false, false, NULL }
+    ia64_handle_version_id_attribute, false },
+  { NULL,             0, 0, false, false, false, NULL, false }
 };
 
 /* Initialize the GCC target structure.  */
@@ -312,6 +371,9 @@ static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN ia64_expand_builtin
 
+#undef TARGET_BUILTIN_DECL
+#define TARGET_BUILTIN_DECL ia64_builtin_decl
+
 #undef TARGET_ASM_BYTE_OP
 #define TARGET_ASM_BYTE_OP "\tdata1\t"
 #undef TARGET_ASM_ALIGNED_HI_OP
@@ -329,6 +391,9 @@ static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_ASM_INTEGER
 #define TARGET_ASM_INTEGER ia64_assemble_integer
 
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE ia64_option_override
+
 #undef TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE ia64_output_function_prologue
 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
@@ -336,6 +401,13 @@ static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE ia64_output_function_epilogue
 
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND ia64_print_operand
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS ia64_print_operand_address
+#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
+#define TARGET_PRINT_OPERAND_PUNCT_VALID_P ia64_print_operand_punct_valid_p
+
 #undef TARGET_IN_SMALL_DATA_P
 #define TARGET_IN_SMALL_DATA_P  ia64_in_small_data_p
 
@@ -423,6 +495,14 @@ static const struct attribute_spec ia64_attribute_table[] =
 #define TARGET_FUNCTION_OK_FOR_SIBCALL ia64_function_ok_for_sibcall
 #undef TARGET_ARG_PARTIAL_BYTES
 #define TARGET_ARG_PARTIAL_BYTES ia64_arg_partial_bytes
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG ia64_function_arg
+#undef TARGET_FUNCTION_INCOMING_ARG
+#define TARGET_FUNCTION_INCOMING_ARG ia64_function_incoming_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE ia64_function_arg_advance
+#undef TARGET_FUNCTION_ARG_BOUNDARY
+#define TARGET_FUNCTION_ARG_BOUNDARY ia64_function_arg_boundary
 
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK ia64_output_mi_thunk
@@ -435,6 +515,10 @@ static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_ASM_GLOBALIZE_DECL_NAME
 #define TARGET_ASM_GLOBALIZE_DECL_NAME ia64_globalize_decl_name
 
+#undef TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST ia64_register_move_cost
+#undef TARGET_MEMORY_MOVE_COST
+#define TARGET_MEMORY_MOVE_COST ia64_memory_move_cost
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS ia64_rtx_costs
 #undef TARGET_ADDRESS_COST
@@ -457,24 +541,19 @@ static const struct attribute_spec ia64_attribute_table[] =
 #define TARGET_ASM_OUTPUT_DWARF_DTPREL ia64_output_dwarf_dtprel
 #endif
 
-/* ??? ABI doesn't allow us to define this.  */
-#if 0
-#undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
-#endif
-
-/* ??? ABI doesn't allow us to define this.  */
-#if 0
-#undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
-#endif
-
 /* ??? Investigate.  */
 #if 0
 #undef TARGET_PROMOTE_PROTOTYPES
 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
 #endif
 
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE ia64_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE ia64_libcall_value
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P ia64_function_value_regno_p
+
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX ia64_struct_value_rtx
 #undef TARGET_RETURN_IN_MEMORY
@@ -485,12 +564,23 @@ static const struct attribute_spec ia64_attribute_table[] =
 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
 #undef TARGET_MUST_PASS_IN_STACK
 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+#undef TARGET_GET_RAW_RESULT_MODE
+#define TARGET_GET_RAW_RESULT_MODE ia64_get_reg_raw_mode
+#undef TARGET_GET_RAW_ARG_MODE
+#define TARGET_GET_RAW_ARG_MODE ia64_get_reg_raw_mode
 
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg
 
-#undef TARGET_UNWIND_EMIT
-#define TARGET_UNWIND_EMIT process_for_unwind_directive
+#undef TARGET_ASM_UNWIND_EMIT
+#define TARGET_ASM_UNWIND_EMIT ia64_asm_unwind_emit
+#undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
+#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY  ia64_asm_emit_except_personality
+#undef TARGET_ASM_INIT_SECTIONS
+#define TARGET_ASM_INIT_SECTIONS  ia64_asm_init_sections
+
+#undef TARGET_DEBUG_UNWIND_INFO
+#define TARGET_DEBUG_UNWIND_INFO  ia64_debug_unwind_info
 
 #undef TARGET_SCALAR_MODE_SUPPORTED_P
 #define TARGET_SCALAR_MODE_SUPPORTED_P ia64_scalar_mode_supported_p
@@ -502,10 +592,10 @@ static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_RELAXED_ORDERING
 #define TARGET_RELAXED_ORDERING true
 
-#undef TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | TARGET_CPU_DEFAULT)
-#undef TARGET_HANDLE_OPTION
-#define TARGET_HANDLE_OPTION ia64_handle_option
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P ia64_legitimate_constant_p
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P ia64_legitimate_address_p
 
 #undef TARGET_CANNOT_FORCE_CONST_MEM
 #define TARGET_CANNOT_FORCE_CONST_MEM ia64_cannot_force_const_mem
@@ -523,6 +613,32 @@ static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_C_MODE_FOR_SUFFIX
 #define TARGET_C_MODE_FOR_SUFFIX ia64_c_mode_for_suffix
 
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE ia64_can_eliminate
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT ia64_trampoline_init
+
+#undef TARGET_INVALID_WITHIN_DOLOOP
+#define TARGET_INVALID_WITHIN_DOLOOP hook_constcharptr_const_rtx_null
+
+#undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE
+#define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE ia64_override_options_after_change
+
+#undef TARGET_PREFERRED_RELOAD_CLASS
+#define TARGET_PREFERRED_RELOAD_CLASS ia64_preferred_reload_class
+
+#undef TARGET_DELAY_SCHED2
+#define TARGET_DELAY_SCHED2 true
+
+/* Variable tracking should be run after all optimizations which
+   change order of insns.  It also needs a valid CFG.  */
+#undef TARGET_DELAY_VARTRACK
+#define TARGET_DELAY_VARTRACK true
+
+#undef TARGET_VECTORIZE_VEC_PERM_CONST_OK
+#define TARGET_VECTORIZE_VEC_PERM_CONST_OK ia64_vectorize_vec_perm_const_ok
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 typedef enum
@@ -593,8 +709,9 @@ ia64_handle_model_attribute (tree *node, tree name, tree args,
           == FUNCTION_DECL)
          && !TREE_STATIC (decl))
        {
-         error ("%Jan address area attribute cannot be specified for "
-                "local variables", decl);
+         error_at (DECL_SOURCE_LOCATION (decl),
+                   "an address area attribute cannot be specified for "
+                   "local variables");
          *no_add_attrs = true;
        }
       area = ia64_get_addr_area (decl);
@@ -607,8 +724,9 @@ ia64_handle_model_attribute (tree *node, tree name, tree args,
       break;
 
     case FUNCTION_DECL:
-      error ("%Jaddress area attribute cannot be specified for functions",
-            decl);
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "address area attribute cannot be specified for "
+               "functions");
       *no_add_attrs = true;
       break;
 
@@ -622,6 +740,95 @@ ia64_handle_model_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
+/* The section must have global and overlaid attributes.  */
+#define SECTION_VMS_OVERLAY SECTION_MACH_DEP
+
+/* Part of the low level implementation of DEC Ada pragma Common_Object which
+   enables the shared use of variables stored in overlaid linker areas
+   corresponding to the use of Fortran COMMON.  */
+
+static tree
+ia64_vms_common_object_attribute (tree *node, tree name, tree args,
+                                 int flags ATTRIBUTE_UNUSED,
+                                 bool *no_add_attrs)
+{
+    tree decl = *node;
+    tree id, val;
+    if (! DECL_P (decl))
+      abort ();
+  
+    DECL_COMMON (decl) = 1;
+    id = TREE_VALUE (args);
+    if (TREE_CODE (id) == IDENTIFIER_NODE)
+      val = build_string (IDENTIFIER_LENGTH (id), IDENTIFIER_POINTER (id));
+    else if (TREE_CODE (id) == STRING_CST)
+      val = id;
+    else
+      {
+       warning (OPT_Wattributes,
+                "%qE attribute requires a string constant argument", name);
+       *no_add_attrs = true;
+       return NULL_TREE;
+      }
+    DECL_SECTION_NAME (decl) = val;
+    return NULL_TREE;
+}
+
+/* Part of the low level implementation of DEC Ada pragma Common_Object.  */
+
+void
+ia64_vms_output_aligned_decl_common (FILE *file, tree decl, const char *name,
+                                    unsigned HOST_WIDE_INT size,
+                                    unsigned int align)
+{
+  tree attr = DECL_ATTRIBUTES (decl);
+
+  /* As common_object attribute set DECL_SECTION_NAME check it before
+     looking up the attribute.  */
+  if (DECL_SECTION_NAME (decl) && attr)
+    attr = lookup_attribute ("common_object", attr);
+  else
+    attr = NULL_TREE;
+
+  if (!attr)
+    {
+      /*  Code from elfos.h.  */
+      fprintf (file, "%s", COMMON_ASM_OP);
+      assemble_name (file, name);
+      fprintf (file, ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n",
+              size, align / BITS_PER_UNIT);
+    }
+  else
+    {
+      ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+      ASM_OUTPUT_LABEL (file, name);
+      ASM_OUTPUT_SKIP (file, size ? size : 1);
+    }
+}
+
+/* Definition of TARGET_ASM_NAMED_SECTION for VMS.  */
+
+void
+ia64_vms_elf_asm_named_section (const char *name, unsigned int flags,
+                               tree decl)
+{
+  if (!(flags & SECTION_VMS_OVERLAY))
+    {
+      default_elf_asm_named_section (name, flags, decl);
+      return;
+    }
+  if (flags != (SECTION_VMS_OVERLAY | SECTION_WRITE))
+    abort ();
+
+  if (flags & SECTION_DECLARED)
+    {
+      fprintf (asm_out_file, "\t.section\t%s\n", name);
+      return;
+    }
+
+  fprintf (asm_out_file, "\t.section\t%s,\"awgO\"\n", name);
+}
+
 static void
 ia64_encode_addr_area (tree decl, rtx symbol)
 {
@@ -678,7 +885,11 @@ ia64_move_ok (rtx dst, rtx src)
 int
 ia64_load_pair_ok (rtx dst, rtx src)
 {
-  if (GET_CODE (dst) != REG || !FP_REGNO_P (REGNO (dst)))
+  /* ??? There is a thinko in the implementation of the "x" constraint and the
+     FP_REGS class.  The constraint will also reject (reg f30:TI) so we must
+     also return false for it.  */
+  if (GET_CODE (dst) != REG
+      || !(FP_REGNO_P (REGNO (dst)) && FP_REGNO_P (REGNO (dst) + 1)))
     return 0;
   if (GET_CODE (src) != MEM || MEM_VOLATILE_P (src))
     return 0;
@@ -746,11 +957,73 @@ tls_symbolic_operand_type (rtx addr)
   return tls_kind;
 }
 
+/* Returns true if REG (assumed to be a `reg' RTX) is valid for use
+   as a base register.  */
+
+static inline bool
+ia64_reg_ok_for_base_p (const_rtx reg, bool strict)
+{
+  if (strict
+      && REGNO_OK_FOR_BASE_P (REGNO (reg)))
+    return true;
+  else if (!strict
+          && (GENERAL_REGNO_P (REGNO (reg))
+              || !HARD_REGISTER_P (reg)))
+    return true;
+  else
+    return false;
+}
+
+static bool
+ia64_legitimate_address_reg (const_rtx reg, bool strict)
+{
+  if ((REG_P (reg) && ia64_reg_ok_for_base_p (reg, strict))
+      || (GET_CODE (reg) == SUBREG && REG_P (XEXP (reg, 0))
+         && ia64_reg_ok_for_base_p (XEXP (reg, 0), strict)))
+    return true;
+
+  return false;
+}
+
+static bool
+ia64_legitimate_address_disp (const_rtx reg, const_rtx disp, bool strict)
+{
+  if (GET_CODE (disp) == PLUS
+      && rtx_equal_p (reg, XEXP (disp, 0))
+      && (ia64_legitimate_address_reg (XEXP (disp, 1), strict)
+         || (CONST_INT_P (XEXP (disp, 1))
+             && IN_RANGE (INTVAL (XEXP (disp, 1)), -256, 255))))
+    return true;
+
+  return false;
+}
+
+/* Implement TARGET_LEGITIMATE_ADDRESS_P.  */
+
+static bool
+ia64_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+                          rtx x, bool strict)
+{
+  if (ia64_legitimate_address_reg (x, strict))
+    return true;
+  else if ((GET_CODE (x) == POST_INC || GET_CODE (x) == POST_DEC)
+          && ia64_legitimate_address_reg (XEXP (x, 0), strict)
+          && XEXP (x, 0) != arg_pointer_rtx) 
+    return true;
+  else if (GET_CODE (x) == POST_MODIFY
+          && ia64_legitimate_address_reg (XEXP (x, 0), strict)
+          && XEXP (x, 0) != arg_pointer_rtx
+          && ia64_legitimate_address_disp (XEXP (x, 0), XEXP (x, 1), strict))
+    return true;
+  else
+    return false;
+}
+
 /* Return true if X is a constant that is valid for some immediate
    field in an instruction.  */
 
-bool
-ia64_legitimate_constant_p (rtx x)
+static bool
+ia64_legitimate_constant_p (enum machine_mode mode, rtx x)
 {
   switch (GET_CODE (x))
     {
@@ -759,8 +1032,7 @@ ia64_legitimate_constant_p (rtx x)
       return true;
 
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode || GET_MODE (x) == SFmode
-         || GET_MODE (x) == DFmode)
+      if (GET_MODE (x) == VOIDmode || mode == SFmode || mode == DFmode)
        return true;
       return satisfies_constraint_G (x);
 
@@ -782,25 +1054,21 @@ ia64_legitimate_constant_p (rtx x)
              op = XEXP (XEXP (op, 0), 0);
            }
 
-          if (any_offset_symbol_operand (op, GET_MODE (op))
-              || function_operand (op, GET_MODE (op)))
+          if (any_offset_symbol_operand (op, mode)
+              || function_operand (op, mode))
             return true;
-         if (aligned_offset_symbol_operand (op, GET_MODE (op)))
+         if (aligned_offset_symbol_operand (op, mode))
            return (addend & 0x3fff) == 0;
          return false;
        }
       return false;
 
     case CONST_VECTOR:
-      {
-       enum machine_mode mode = GET_MODE (x);
+      if (mode == V2SFmode)
+       return satisfies_constraint_Y (x);
 
-       if (mode == V2SFmode)
-         return satisfies_constraint_Y (x);
-
-       return (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
-               && GET_MODE_SIZE (mode) <= 8);
-      }
+      return (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+             && GET_MODE_SIZE (mode) <= 8);
 
     default:
       return false;
@@ -810,9 +1078,9 @@ ia64_legitimate_constant_p (rtx x)
 /* Don't allow TLS addresses to get spilled to memory.  */
 
 static bool
-ia64_cannot_force_const_mem (rtx x)
+ia64_cannot_force_const_mem (enum machine_mode mode, rtx x)
 {
-  if (GET_MODE (x) == RFmode)
+  if (mode == RFmode)
     return true;
   return tls_symbolic_operand_type (x) != 0;
 }
@@ -872,7 +1140,7 @@ ia64_expand_load_address (rtx dest, rtx src)
       tmp = gen_rtx_PLUS (Pmode, tmp, pic_offset_table_rtx);
       emit_insn (gen_rtx_SET (VOIDmode, dest, tmp));
 
-      tmp = gen_rtx_LO_SUM (Pmode, dest, src);
+      tmp = gen_rtx_LO_SUM (Pmode, gen_const_mem (Pmode, dest), src);
       emit_insn (gen_rtx_SET (VOIDmode, dest, tmp));
 
       if (addend)
@@ -1625,25 +1893,18 @@ ia64_expand_vecint_compare (enum rtx_code code, enum machine_mode mode,
          {
            rtx t1, t2, mask;
 
-           /* Perform a parallel modulo subtraction.  */
-           t1 = gen_reg_rtx (V2SImode);
-           emit_insn (gen_subv2si3 (t1, op0, op1));
-
-           /* Extract the original sign bit of op0.  */
-           mask = GEN_INT (-0x80000000);
+           /* Subtract (-(INT MAX) - 1) from both operands to make
+              them signed.  */
+           mask = GEN_INT (0x80000000);
            mask = gen_rtx_CONST_VECTOR (V2SImode, gen_rtvec (2, mask, mask));
-           mask = force_reg (V2SImode, mask);
-           t2 = gen_reg_rtx (V2SImode);
-           emit_insn (gen_andv2si3 (t2, op0, mask));
-
-           /* XOR it back into the result of the subtraction.  This results
-              in the sign bit set iff we saw unsigned underflow.  */
-           x = gen_reg_rtx (V2SImode);
-           emit_insn (gen_xorv2si3 (x, t1, t2));
-
+           mask = force_reg (mode, mask);
+           t1 = gen_reg_rtx (mode);
+           emit_insn (gen_subv2si3 (t1, op0, mask));
+           t2 = gen_reg_rtx (mode);
+           emit_insn (gen_subv2si3 (t2, op1, mask));
+           op0 = t1;
+           op1 = t2;
            code = GT;
-           op0 = x;
-           op1 = CONST0_RTX (mode);
          }
          break;
 
@@ -1777,58 +2038,88 @@ ia64_expand_vecint_minmax (enum rtx_code code, enum machine_mode mode,
   return true;
 }
 
-/* Emit an integral vector widening sum operations.  */
+/* The vectors LO and HI each contain N halves of a double-wide vector.
+   Reassemble either the first N/2 or the second N/2 elements.  */
 
 void
-ia64_expand_widen_sum (rtx operands[3], bool unsignedp)
+ia64_unpack_assemble (rtx out, rtx lo, rtx hi, bool highp)
 {
-  rtx l, h, x, s;
-  enum machine_mode wmode, mode;
-  rtx (*unpack_l) (rtx, rtx, rtx);
-  rtx (*unpack_h) (rtx, rtx, rtx);
-  rtx (*plus) (rtx, rtx, rtx);
+  enum machine_mode vmode = GET_MODE (lo);
+  unsigned int i, high, nelt = GET_MODE_NUNITS (vmode);
+  struct expand_vec_perm_d d;
+  bool ok;
 
-  wmode = GET_MODE (operands[0]);
-  mode = GET_MODE (operands[1]);
+  d.target = gen_lowpart (vmode, out);
+  d.op0 = (TARGET_BIG_ENDIAN ? hi : lo);
+  d.op1 = (TARGET_BIG_ENDIAN ? lo : hi);
+  d.vmode = vmode;
+  d.nelt = nelt;
+  d.one_operand_p = false;
+  d.testing_p = false;
 
-  switch (mode)
+  high = (highp ? nelt / 2 : 0);
+  for (i = 0; i < nelt / 2; ++i)
     {
-    case V8QImode:
-      unpack_l = gen_unpack1_l;
-      unpack_h = gen_unpack1_h;
-      plus = gen_addv4hi3;
-      break;
-    case V4HImode:
-      unpack_l = gen_unpack2_l;
-      unpack_h = gen_unpack2_h;
-      plus = gen_addv2si3;
-      break;
-    default:
-      gcc_unreachable ();
+      d.perm[i * 2] = i + high;
+      d.perm[i * 2 + 1] = i + high + nelt;
     }
 
-  /* Fill in x with the sign extension of each element in op1.  */
+  ok = ia64_expand_vec_perm_const_1 (&d);
+  gcc_assert (ok);
+}
+
+/* Return a vector of the sign-extension of VEC.  */
+
+static rtx
+ia64_unpack_sign (rtx vec, bool unsignedp)
+{
+  enum machine_mode mode = GET_MODE (vec);
+  rtx zero = CONST0_RTX (mode);
+
   if (unsignedp)
-    x = CONST0_RTX (mode);
+    return zero;
   else
     {
+      rtx sign = gen_reg_rtx (mode);
       bool neg;
 
-      x = gen_reg_rtx (mode);
-
-      neg = ia64_expand_vecint_compare (LT, mode, x, operands[1],
-                                       CONST0_RTX (mode));
+      neg = ia64_expand_vecint_compare (LT, mode, sign, vec, zero);
       gcc_assert (!neg);
+
+      return sign;
     }
+}
+
+/* Emit an integral vector unpack operation.  */
+
+void
+ia64_expand_unpack (rtx operands[3], bool unsignedp, bool highp)
+{
+  rtx sign = ia64_unpack_sign (operands[1], unsignedp);
+  ia64_unpack_assemble (operands[0], operands[1], sign, highp);
+}
+
+/* Emit an integral vector widening sum operations.  */
+
+void
+ia64_expand_widen_sum (rtx operands[3], bool unsignedp)
+{
+  enum machine_mode wmode;
+  rtx l, h, t, sign;
+
+  sign = ia64_unpack_sign (operands[1], unsignedp);
 
+  wmode = GET_MODE (operands[0]);
   l = gen_reg_rtx (wmode);
   h = gen_reg_rtx (wmode);
-  s = gen_reg_rtx (wmode);
 
-  emit_insn (unpack_l (gen_lowpart (mode, l), operands[1], x));
-  emit_insn (unpack_h (gen_lowpart (mode, h), operands[1], x));
-  emit_insn (plus (s, l, operands[2]));
-  emit_insn (plus (operands[0], h, s));
+  ia64_unpack_assemble (l, operands[1], sign, false);
+  ia64_unpack_assemble (h, operands[1], sign, true);
+
+  t = expand_binop (wmode, add_optab, l, operands[2], NULL, 0, OPTAB_DIRECT);
+  t = expand_binop (wmode, add_optab, h, t, operands[0], 0, OPTAB_DIRECT);
+  if (t != operands[0])
+    emit_move_insn (operands[0], t);
 }
 
 /* Emit a signed or unsigned V8QI dot product operation.  */
@@ -1836,44 +2127,31 @@ ia64_expand_widen_sum (rtx operands[3], bool unsignedp)
 void
 ia64_expand_dot_prod_v8qi (rtx operands[4], bool unsignedp)
 {
-  rtx l1, l2, h1, h2, x1, x2, p1, p2, p3, p4, s1, s2, s3;
-
-  /* Fill in x1 and x2 with the sign extension of each element.  */
-  if (unsignedp)
-    x1 = x2 = CONST0_RTX (V8QImode);
-  else
-    {
-      bool neg;
-
-      x1 = gen_reg_rtx (V8QImode);
-      x2 = gen_reg_rtx (V8QImode);
+  rtx op1, op2, sn1, sn2, l1, l2, h1, h2;
+  rtx p1, p2, p3, p4, s1, s2, s3;
 
-      neg = ia64_expand_vecint_compare (LT, V8QImode, x1, operands[1],
-                                       CONST0_RTX (V8QImode));
-      gcc_assert (!neg);
-      neg = ia64_expand_vecint_compare (LT, V8QImode, x2, operands[2],
-                                       CONST0_RTX (V8QImode));
-      gcc_assert (!neg);
-    }
+  op1 = operands[1];
+  op2 = operands[2];
+  sn1 = ia64_unpack_sign (op1, unsignedp);
+  sn2 = ia64_unpack_sign (op2, unsignedp);
 
   l1 = gen_reg_rtx (V4HImode);
   l2 = gen_reg_rtx (V4HImode);
   h1 = gen_reg_rtx (V4HImode);
   h2 = gen_reg_rtx (V4HImode);
-
-  emit_insn (gen_unpack1_l (gen_lowpart (V8QImode, l1), operands[1], x1));
-  emit_insn (gen_unpack1_l (gen_lowpart (V8QImode, l2), operands[2], x2));
-  emit_insn (gen_unpack1_h (gen_lowpart (V8QImode, h1), operands[1], x1));
-  emit_insn (gen_unpack1_h (gen_lowpart (V8QImode, h2), operands[2], x2));
+  ia64_unpack_assemble (l1, op1, sn1, false);
+  ia64_unpack_assemble (l2, op2, sn2, false);
+  ia64_unpack_assemble (h1, op1, sn1, true);
+  ia64_unpack_assemble (h2, op2, sn2, true);
 
   p1 = gen_reg_rtx (V2SImode);
   p2 = gen_reg_rtx (V2SImode);
   p3 = gen_reg_rtx (V2SImode);
   p4 = gen_reg_rtx (V2SImode);
-  emit_insn (gen_pmpy2_r (p1, l1, l2));
-  emit_insn (gen_pmpy2_l (p2, l1, l2));
-  emit_insn (gen_pmpy2_r (p3, h1, h2));
-  emit_insn (gen_pmpy2_l (p4, h1, h2));
+  emit_insn (gen_pmpy2_even (p1, l1, l2));
+  emit_insn (gen_pmpy2_even (p2, h1, h2));
+  emit_insn (gen_pmpy2_odd (p3, l1, l2));
+  emit_insn (gen_pmpy2_odd (p4, h1, h2));
 
   s1 = gen_reg_rtx (V2SImode);
   s2 = gen_reg_rtx (V2SImode);
@@ -1922,6 +2200,10 @@ ia64_expand_call (rtx retval, rtx addr, rtx nextarg ATTRIBUTE_UNUSED,
 
   if (sibcall_p)
     use_reg (&CALL_INSN_FUNCTION_USAGE (insn), b0);
+
+  if (TARGET_ABI_OPEN_VMS)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (insn),
+            gen_rtx_REG (DImode, GR_REG (25)));
 }
 
 static void
@@ -1943,7 +2225,7 @@ get_reg (enum ia64_frame_regs r)
 static bool
 is_emitted (int regno)
 {
-  enum ia64_frame_regs r;
+  unsigned int r;
 
   for (r = reg_fp; r < number_of_ia64_frame_regs; r++)
     if (emitted_frame_related_regs[r] == regno)
@@ -2077,7 +2359,7 @@ ia64_split_call (rtx retval, rtx addr, rtx retaddr, rtx scratch_r,
 
 void
 ia64_expand_atomic_op (enum rtx_code code, rtx mem, rtx val,
-                      rtx old_dst, rtx new_dst)
+                      rtx old_dst, rtx new_dst, enum memmodel model)
 {
   enum machine_mode mode = GET_MODE (mem);
   rtx old_reg, new_reg, cmp_reg, ar_ccv, label;
@@ -2094,12 +2376,31 @@ ia64_expand_atomic_op (enum rtx_code code, rtx mem, rtx val,
       if (!old_dst)
         old_dst = gen_reg_rtx (mode);
 
-      emit_insn (gen_memory_barrier ());
+      switch (model)
+       {
+       case MEMMODEL_ACQ_REL:
+       case MEMMODEL_SEQ_CST:
+         emit_insn (gen_memory_barrier ());
+         /* FALLTHRU */
+       case MEMMODEL_RELAXED:
+       case MEMMODEL_ACQUIRE:
+       case MEMMODEL_CONSUME:
+         if (mode == SImode)
+           icode = CODE_FOR_fetchadd_acq_si;
+         else
+           icode = CODE_FOR_fetchadd_acq_di;
+         break;
+       case MEMMODEL_RELEASE:
+         if (mode == SImode)
+           icode = CODE_FOR_fetchadd_rel_si;
+         else
+           icode = CODE_FOR_fetchadd_rel_di;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
 
-      if (mode == SImode)
-       icode = CODE_FOR_fetchadd_acq_si;
-      else
-       icode = CODE_FOR_fetchadd_acq_di;
       emit_insn (GEN_FCN (icode) (old_dst, mem, val));
 
       if (new_dst)
@@ -2113,8 +2414,12 @@ ia64_expand_atomic_op (enum rtx_code code, rtx mem, rtx val,
     }
 
   /* Because of the volatile mem read, we get an ld.acq, which is the
-     front half of the full barrier.  The end half is the cmpxchg.rel.  */
-  gcc_assert (MEM_VOLATILE_P (mem));
+     front half of the full barrier.  The end half is the cmpxchg.rel.
+     For relaxed and release memory models, we don't need this.  But we
+     also don't bother trying to prevent it either.  */
+  gcc_assert (model == MEMMODEL_RELAXED
+             || model == MEMMODEL_RELEASE
+             || MEM_VOLATILE_P (mem));
 
   old_reg = gen_reg_rtx (DImode);
   cmp_reg = gen_reg_rtx (DImode);
@@ -2153,12 +2458,36 @@ ia64_expand_atomic_op (enum rtx_code code, rtx mem, rtx val,
   if (new_dst)
     emit_move_insn (new_dst, new_reg);
 
-  switch (mode)
+  switch (model)
     {
-    case QImode:  icode = CODE_FOR_cmpxchg_rel_qi;  break;
-    case HImode:  icode = CODE_FOR_cmpxchg_rel_hi;  break;
-    case SImode:  icode = CODE_FOR_cmpxchg_rel_si;  break;
-    case DImode:  icode = CODE_FOR_cmpxchg_rel_di;  break;
+    case MEMMODEL_RELAXED:
+    case MEMMODEL_ACQUIRE:
+    case MEMMODEL_CONSUME:
+      switch (mode)
+       {
+       case QImode: icode = CODE_FOR_cmpxchg_acq_qi;  break;
+       case HImode: icode = CODE_FOR_cmpxchg_acq_hi;  break;
+       case SImode: icode = CODE_FOR_cmpxchg_acq_si;  break;
+       case DImode: icode = CODE_FOR_cmpxchg_acq_di;  break;
+       default:
+         gcc_unreachable ();
+       }
+      break;
+
+    case MEMMODEL_RELEASE:
+    case MEMMODEL_ACQ_REL:
+    case MEMMODEL_SEQ_CST:
+      switch (mode)
+       {
+       case QImode: icode = CODE_FOR_cmpxchg_rel_qi;  break;
+       case HImode: icode = CODE_FOR_cmpxchg_rel_hi;  break;
+       case SImode: icode = CODE_FOR_cmpxchg_rel_si;  break;
+       case DImode: icode = CODE_FOR_cmpxchg_rel_di;  break;
+       default:
+         gcc_unreachable ();
+       }
+      break;
+
     default:
       gcc_unreachable ();
     }
@@ -2173,13 +2502,6 @@ ia64_expand_atomic_op (enum rtx_code code, rtx mem, rtx val,
 static void
 ia64_file_start (void)
 {
-  /* Variable tracking should be run after all optimizations which change order
-     of insns.  It also needs a valid CFG.  This can't be done in
-     ia64_override_options, because flag_var_tracking is finalized after
-     that.  */
-  ia64_flag_var_tracking = flag_var_tracking;
-  flag_var_tracking = 0;
-
   default_file_start ();
   emit_safe_across_calls ();
 }
@@ -2634,6 +2956,14 @@ ia64_compute_frame_size (HOST_WIDE_INT size)
   current_frame_info.initialized = reload_completed;
 }
 
+/* Worker function for TARGET_CAN_ELIMINATE.  */
+
+bool
+ia64_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+  return (to == BR_REG (0) ? current_function_is_leaf : true);
+}
+
 /* Compute the initial difference between the specified pair of registers.  */
 
 HOST_WIDE_INT
@@ -2885,7 +3215,7 @@ do_spill (rtx (*move_fn) (rtx, rtx, rtx), rtx reg, HOST_WIDE_INT cfa_off,
          off = current_frame_info.total_size - cfa_off;
        }
 
-      add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+      add_reg_note (insn, REG_CFA_OFFSET,
                    gen_rtx_SET (VOIDmode,
                                 gen_rtx_MEM (GET_MODE (reg),
                                              plus_constant (base, off)),
@@ -2958,6 +3288,9 @@ ia64_expand_prologue (void)
   ia64_compute_frame_size (get_frame_size ());
   last_scratch_gr_reg = 15;
 
+  if (flag_stack_usage_info)
+    current_function_static_stack_size = current_frame_info.total_size;
+
   if (dump_file) 
     {
       fprintf (dump_file, "ia64 frame related registers "
@@ -3053,7 +3386,14 @@ ia64_expand_prologue (void)
                                   GEN_INT (current_frame_info.n_local_regs),
                                   GEN_INT (current_frame_info.n_output_regs),
                                   GEN_INT (current_frame_info.n_rotate_regs)));
-      RTX_FRAME_RELATED_P (insn) = (current_frame_info.r[reg_save_ar_pfs] != 0);
+      if (current_frame_info.r[reg_save_ar_pfs])
+       {
+         RTX_FRAME_RELATED_P (insn) = 1;
+         add_reg_note (insn, REG_CFA_REGISTER,
+                       gen_rtx_SET (VOIDmode,
+                                    ar_pfs_save_reg,
+                                    gen_rtx_REG (DImode, AR_PFS_REGNUM)));
+       }
     }
 
   /* Set up frame pointer, stack pointer, and spill iterators.  */
@@ -3066,6 +3406,10 @@ ia64_expand_prologue (void)
     {
       insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* Force the unwind info to recognize this as defining a new CFA,
+        rather than some temp register setup.  */
+      add_reg_note (insn, REG_CFA_ADJUST_CFA, NULL_RTX);
     }
 
   if (current_frame_info.total_size != 0)
@@ -3088,13 +3432,12 @@ ia64_expand_prologue (void)
       if (! frame_pointer_needed)
        {
          RTX_FRAME_RELATED_P (insn) = 1;
-         if (GET_CODE (offset) != CONST_INT)
-           add_reg_note (insn, REG_FRAME_RELATED_EXPR,
-                         gen_rtx_SET (VOIDmode,
-                                      stack_pointer_rtx,
-                                      gen_rtx_PLUS (DImode,
-                                                    stack_pointer_rtx,
-                                                    frame_size_rtx)));
+         add_reg_note (insn, REG_CFA_ADJUST_CFA,
+                       gen_rtx_SET (VOIDmode,
+                                    stack_pointer_rtx,
+                                    gen_rtx_PLUS (DImode,
+                                                  stack_pointer_rtx,
+                                                  frame_size_rtx)));
        }
 
       /* ??? At this point we must generate a magic insn that appears to
@@ -3122,7 +3465,11 @@ ia64_expand_prologue (void)
 
       reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM);
       insn = emit_move_insn (ar_unat_save_reg, reg);
-      RTX_FRAME_RELATED_P (insn) = (current_frame_info.r[reg_save_ar_unat] != 0);
+      if (current_frame_info.r[reg_save_ar_unat])
+       {
+         RTX_FRAME_RELATED_P (insn) = 1;
+         add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
+       }
 
       /* Even if we're not going to generate an epilogue, we still
         need to save the register so that EH works.  */
@@ -3161,8 +3508,7 @@ ia64_expand_prologue (void)
          /* ??? Denote pr spill/fill by a DImode move that modifies all
             64 hard registers.  */
          RTX_FRAME_RELATED_P (insn) = 1;
-         add_reg_note (insn, REG_FRAME_RELATED_EXPR,
-                       gen_rtx_SET (VOIDmode, alt_reg, reg));
+         add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
 
          /* Even if we're not going to generate an epilogue, we still
             need to save the register so that EH works.  */
@@ -3208,6 +3554,7 @@ ia64_expand_prologue (void)
          reg_emitted (reg_save_ar_lc);
          insn = emit_move_insn (alt_reg, reg);
          RTX_FRAME_RELATED_P (insn) = 1;
+         add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
 
          /* Even if we're not going to generate an epilogue, we still
             need to save the register so that EH works.  */
@@ -3234,6 +3581,8 @@ ia64_expand_prologue (void)
           reg_emitted (reg_save_b0);
          insn = emit_move_insn (alt_reg, reg);
          RTX_FRAME_RELATED_P (insn) = 1;
+         add_reg_note (insn, REG_CFA_REGISTER,
+                       gen_rtx_SET (VOIDmode, alt_reg, pc_rtx));
 
          /* Even if we're not going to generate an epilogue, we still
             need to save the register so that EH works.  */
@@ -3298,6 +3647,30 @@ ia64_expand_prologue (void)
   finish_spill_pointers ();
 }
 
+/* Output the textual info surrounding the prologue.  */
+
+void
+ia64_start_function (FILE *file, const char *fnname,
+                    tree decl ATTRIBUTE_UNUSED)
+{
+#if VMS_DEBUGGING_INFO
+  if (vms_debug_main
+      && debug_info_level > DINFO_LEVEL_NONE
+      && strncmp (vms_debug_main, fnname, strlen (vms_debug_main)) == 0)
+    {
+      targetm.asm_out.globalize_label (asm_out_file, VMS_DEBUG_MAIN_POINTER);
+      ASM_OUTPUT_DEF (asm_out_file, VMS_DEBUG_MAIN_POINTER, fnname);
+      dwarf2out_vms_debug_main_pointer ();
+      vms_debug_main = 0;
+    }
+#endif
+
+  fputs ("\t.proc ", file);
+  assemble_name (file, fnname);
+  fputc ('\n', file);
+  ASM_OUTPUT_LABEL (file, fnname);
+}
+
 /* Called after register allocation to add any instructions needed for the
    epilogue.  Using an epilogue insn is favored compared to putting all of the
    instructions in output_function_prologue(), since it allows the scheduler
@@ -3501,6 +3874,7 @@ ia64_expand_epilogue (int sibcall_p)
     {
       insn = emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
+      add_reg_note (insn, REG_CFA_ADJUST_CFA, NULL);
     }
   else if (current_frame_info.total_size)
     {
@@ -3520,13 +3894,12 @@ ia64_expand_epilogue (int sibcall_p)
                                    offset));
 
       RTX_FRAME_RELATED_P (insn) = 1;
-      if (GET_CODE (offset) != CONST_INT)
-       add_reg_note (insn, REG_FRAME_RELATED_EXPR,
-                     gen_rtx_SET (VOIDmode,
-                                  stack_pointer_rtx,
-                                  gen_rtx_PLUS (DImode,
-                                                stack_pointer_rtx,
-                                                frame_size_rtx)));
+      add_reg_note (insn, REG_CFA_ADJUST_CFA,
+                   gen_rtx_SET (VOIDmode,
+                                stack_pointer_rtx,
+                                gen_rtx_PLUS (DImode,
+                                              stack_pointer_rtx,
+                                              frame_size_rtx)));
     }
 
   if (cfun->machine->ia64_eh_epilogue_bsp)
@@ -3537,11 +3910,12 @@ ia64_expand_epilogue (int sibcall_p)
   else
     {
       int fp = GR_REG (2);
-      /* We need a throw away register here, r0 and r1 are reserved, so r2 is the
-        first available call clobbered register.  If there was a frame_pointer
-        register, we may have swapped the names of r2 and HARD_FRAME_POINTER_REGNUM,
-        so we have to make sure we're using the string "r2" when emitting
-        the register name for the assembler.  */
+      /* We need a throw away register here, r0 and r1 are reserved,
+        so r2 is the first available call clobbered register.  If
+        there was a frame_pointer register, we may have swapped the
+        names of r2 and HARD_FRAME_POINTER_REGNUM, so we have to make
+        sure we're using the string "r2" when emitting the register
+        name for the assembler.  */
       if (current_frame_info.r[reg_fp] 
           && current_frame_info.r[reg_fp] == GR_REG (2))
        fp = HARD_FRAME_POINTER_REGNUM;
@@ -3556,10 +3930,19 @@ ia64_expand_epilogue (int sibcall_p)
       if (current_frame_info.n_input_regs != 0)
        {
          rtx n_inputs = GEN_INT (current_frame_info.n_input_regs);
+
          insn = emit_insn (gen_alloc (gen_rtx_REG (DImode, fp),
                                const0_rtx, const0_rtx,
                                n_inputs, const0_rtx));
          RTX_FRAME_RELATED_P (insn) = 1;
+
+         /* ??? We need to mark the alloc as frame-related so that it gets
+            passed into ia64_asm_unwind_emit for ia64-specific unwinding.
+            But there's nothing dwarf2 related to be done wrt the register
+            windows.  If we do nothing, dwarf2out will abort on the UNSPEC;
+            the empty parallel means dwarf2out will not see anything.  */
+         add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                       gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (0)));
        }
     }
 }
@@ -3657,7 +4040,7 @@ int
 ia64_hard_regno_rename_ok (int from, int to)
 {
   /* Don't clobber any of the registers we reserved for the prologue.  */
-  enum ia64_frame_regs r;
+  unsigned int r;
 
   for (r = reg_fp; r <= reg_save_ar_lc; r++)
     if (to == current_frame_info.r[r] 
@@ -3715,7 +4098,7 @@ ia64_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
             current_frame_info.n_output_regs,
             current_frame_info.n_rotate_regs);
 
-  if (!flag_unwind_tables && (!flag_exceptions || USING_SJLJ_EXCEPTIONS))
+  if (ia64_except_unwind_info (&global_options) != UI_TARGET)
     return;
 
   /* Emit the .prologue directive.  */
@@ -3773,7 +4156,7 @@ ia64_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 static void
 ia64_output_function_end_prologue (FILE *file)
 {
-  if (!flag_unwind_tables && (!flag_exceptions || USING_SJLJ_EXCEPTIONS))
+  if (ia64_except_unwind_info (&global_options) != UI_TARGET)
     return;
 
   fputs ("\t.body\n", file);
@@ -3833,10 +4216,35 @@ ia64_dbx_register_number (int regno)
     return regno;
 }
 
-void
-ia64_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
+/* Implement TARGET_TRAMPOLINE_INIT.
+
+   The trampoline should set the static chain pointer to value placed
+   into the trampoline and should branch to the specified routine.
+   To make the normal indirect-subroutine calling convention work,
+   the trampoline must look like a function descriptor; the first
+   word being the target address and the second being the target's
+   global pointer.
+
+   We abuse the concept of a global pointer by arranging for it
+   to point to the data we need to load.  The complete trampoline
+   has the following form:
+
+               +-------------------+ \
+       TRAMP:  | __ia64_trampoline | |
+               +-------------------+  > fake function descriptor
+               | TRAMP+16          | |
+               +-------------------+ /
+               | target descriptor |
+               +-------------------+
+               | static link       |
+               +-------------------+
+*/
+
+static void
+ia64_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
 {
-  rtx addr_reg, eight = GEN_INT (8);
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx addr, addr_reg, tramp, eight = GEN_INT (8);
 
   /* The Intel assembler requires that the global __ia64_trampoline symbol
      be declared explicitly */
@@ -3853,30 +4261,45 @@ ia64_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
     }
 
   /* Make sure addresses are Pmode even if we are in ILP32 mode. */
-  addr = convert_memory_address (Pmode, addr);
+  addr = convert_memory_address (Pmode, XEXP (m_tramp, 0));
   fnaddr = convert_memory_address (Pmode, fnaddr);
   static_chain = convert_memory_address (Pmode, static_chain);
 
   /* Load up our iterator.  */
-  addr_reg = gen_reg_rtx (Pmode);
-  emit_move_insn (addr_reg, addr);
+  addr_reg = copy_to_reg (addr);
+  m_tramp = adjust_automodify_address (m_tramp, Pmode, addr_reg, 0);
 
   /* The first two words are the fake descriptor:
      __ia64_trampoline, ADDR+16.  */
-  emit_move_insn (gen_rtx_MEM (Pmode, addr_reg),
-                 gen_rtx_SYMBOL_REF (Pmode, "__ia64_trampoline"));
+  tramp = gen_rtx_SYMBOL_REF (Pmode, "__ia64_trampoline");
+  if (TARGET_ABI_OPEN_VMS)
+    {
+      /* HP decided to break the ELF ABI on VMS (to deal with an ambiguity
+        in the Macro-32 compiler) and changed the semantics of the LTOFF22
+        relocation against function symbols to make it identical to the
+        LTOFF_FPTR22 relocation.  Emit the latter directly to stay within
+        strict ELF and dereference to get the bare code address.  */
+      rtx reg = gen_reg_rtx (Pmode);
+      SYMBOL_REF_FLAGS (tramp) |= SYMBOL_FLAG_FUNCTION;
+      emit_move_insn (reg, tramp);
+      emit_move_insn (reg, gen_rtx_MEM (Pmode, reg));
+      tramp = reg;
+   }
+  emit_move_insn (m_tramp, tramp);
   emit_insn (gen_adddi3 (addr_reg, addr_reg, eight));
+  m_tramp = adjust_automodify_address (m_tramp, VOIDmode, NULL, 8);
 
-  emit_move_insn (gen_rtx_MEM (Pmode, addr_reg),
-                 copy_to_reg (plus_constant (addr, 16)));
+  emit_move_insn (m_tramp, force_reg (Pmode, plus_constant (addr, 16)));
   emit_insn (gen_adddi3 (addr_reg, addr_reg, eight));
+  m_tramp = adjust_automodify_address (m_tramp, VOIDmode, NULL, 8);
 
   /* The third word is the target descriptor.  */
-  emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), fnaddr);
+  emit_move_insn (m_tramp, force_reg (Pmode, fnaddr));
   emit_insn (gen_adddi3 (addr_reg, addr_reg, eight));
+  m_tramp = adjust_automodify_address (m_tramp, VOIDmode, NULL, 8);
 
   /* The fourth word is the static chain.  */
-  emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), static_chain);
+  emit_move_insn (m_tramp, static_chain);
 }
 \f
 /* Do any needed setup for a variadic function.  CUM has not been updated
@@ -3885,14 +4308,14 @@ ia64_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
    We generate the actual spill instructions during prologue generation.  */
 
 static void
-ia64_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ia64_setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
                             tree type, int * pretend_size,
                             int second_time ATTRIBUTE_UNUSED)
 {
-  CUMULATIVE_ARGS next_cum = *cum;
+  CUMULATIVE_ARGS next_cum = *get_cumulative_args (cum);
 
   /* Skip the current argument.  */
-  ia64_function_arg_advance (&next_cum, mode, type, 1);
+  ia64_function_arg_advance (pack_cumulative_args (&next_cum), mode, type, 1);
 
   if (next_cum.words < MAX_ARGUMENT_SLOTS)
     {
@@ -3958,7 +4381,7 @@ hfa_element_mode (const_tree type, bool nested)
     case RECORD_TYPE:
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
-      for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
+      for (t = TYPE_FIELDS (type); t; t = DECL_CHAIN (t))
        {
          if (TREE_CODE (t) != FIELD_DECL)
            continue;
@@ -3993,7 +4416,7 @@ hfa_element_mode (const_tree type, bool nested)
 /* Return the number of words required to hold a quantity of TYPE and MODE
    when passed as an argument.  */
 static int
-ia64_function_arg_words (tree type, enum machine_mode mode)
+ia64_function_arg_words (const_tree type, enum machine_mode mode)
 {
   int words;
 
@@ -4019,9 +4442,11 @@ ia64_function_arg_words (tree type, enum machine_mode mode)
    all as if they had 16 byte alignment.  Such aggregates can occur
    only if gcc extensions are used.  */
 static int
-ia64_function_arg_offset (CUMULATIVE_ARGS *cum, tree type, int words)
+ia64_function_arg_offset (const CUMULATIVE_ARGS *cum,
+                         const_tree type, int words)
 {
-  if ((cum->words & 1) == 0)
+  /* No registers are skipped on VMS.  */
+  if (TARGET_ABI_OPEN_VMS || (cum->words & 1) == 0)
     return 0;
 
   if (type
@@ -4037,15 +4462,35 @@ ia64_function_arg_offset (CUMULATIVE_ARGS *cum, tree type, int words)
 /* ??? 128-bit quad-precision floats are always passed in general
    registers.  */
 
-rtx
-ia64_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
-                  int named, int incoming)
+static rtx
+ia64_function_arg_1 (cumulative_args_t cum_v, enum machine_mode mode,
+                    const_tree type, bool named, bool incoming)
 {
+  const CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+
   int basereg = (incoming ? GR_ARG_FIRST : AR_ARG_FIRST);
   int words = ia64_function_arg_words (type, mode);
   int offset = ia64_function_arg_offset (cum, type, words);
   enum machine_mode hfa_mode = VOIDmode;
 
+  /* For OPEN VMS, emit the instruction setting up the argument register here,
+     when we know this will be together with the other arguments setup related
+     insns.  This is not the conceptually best place to do this, but this is
+     the easiest as we have convenient access to cumulative args info.  */
+
+  if (TARGET_ABI_OPEN_VMS && mode == VOIDmode && type == void_type_node
+      && named == 1)
+    {
+      unsigned HOST_WIDE_INT regval = cum->words;
+      int i;
+
+      for (i = 0; i < 8; i++)
+       regval |= ((int) cum->atypes[i]) << (i * 3 + 8);
+
+      emit_move_insn (gen_rtx_REG (DImode, GR_REG (25)),
+                     GEN_INT (regval));
+    }
+
   /* If all argument slots are used, then it must go on the stack.  */
   if (cum->words + offset >= MAX_ARGUMENT_SLOTS)
     return 0;
@@ -4135,6 +4580,15 @@ ia64_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
        }
       return gen_rtx_PARALLEL (mode, gen_rtvec_v (i, loc));
     }
+  
+  /* On OpenVMS variable argument is either in Rn or Fn.  */
+  else if (TARGET_ABI_OPEN_VMS && named == 0)
+    {
+      if (FLOAT_MODE_P (mode))
+       return gen_rtx_REG (mode, FR_ARG_FIRST + cum->words);
+      else
+       return gen_rtx_REG (mode, basereg + cum->words);
+    }
 
   /* Integral and aggregates go in general registers.  If we have run out of
      FR registers, then FP values must also go in general registers.  This can
@@ -4201,14 +4655,35 @@ ia64_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
     }
 }
 
+/* Implement TARGET_FUNCION_ARG target hook.  */
+
+static rtx
+ia64_function_arg (cumulative_args_t cum, enum machine_mode mode,
+                  const_tree type, bool named)
+{
+  return ia64_function_arg_1 (cum, mode, type, named, false);
+}
+
+/* Implement TARGET_FUNCION_INCOMING_ARG target hook.  */
+
+static rtx
+ia64_function_incoming_arg (cumulative_args_t cum,
+                           enum machine_mode mode,
+                           const_tree type, bool named)
+{
+  return ia64_function_arg_1 (cum, mode, type, named, true);
+}
+
 /* Return number of bytes, at the beginning of the argument, that must be
    put in registers.  0 is the argument is entirely in registers or entirely
    in memory.  */
 
 static int
-ia64_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ia64_arg_partial_bytes (cumulative_args_t cum_v, enum machine_mode mode,
                        tree type, bool named ATTRIBUTE_UNUSED)
 {
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+
   int words = ia64_function_arg_words (type, mode);
   int offset = ia64_function_arg_offset (cum, type, words);
 
@@ -4227,21 +4702,42 @@ ia64_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   return (MAX_ARGUMENT_SLOTS - cum->words - offset) * UNITS_PER_WORD;
 }
 
+/* Return ivms_arg_type based on machine_mode.  */
+
+static enum ivms_arg_type
+ia64_arg_type (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case SFmode:
+      return FS;
+    case DFmode:
+      return FT;
+    default:
+      return I64;
+    }
+}
+
 /* Update CUM to point after this argument.  This is patterned after
    ia64_function_arg.  */
 
-void
-ia64_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                          tree type, int named)
+static void
+ia64_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
+                          const_tree type, bool named)
 {
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
   int words = ia64_function_arg_words (type, mode);
   int offset = ia64_function_arg_offset (cum, type, words);
   enum machine_mode hfa_mode = VOIDmode;
 
   /* If all arg slots are already full, then there is nothing to do.  */
   if (cum->words >= MAX_ARGUMENT_SLOTS)
-    return;
+    {
+      cum->words += words + offset;
+      return;
+    }
 
+  cum->atypes[cum->words] = ia64_arg_type (mode);
   cum->words += words + offset;
 
   /* Check for and handle homogeneous FP aggregates.  */
@@ -4284,6 +4780,13 @@ ia64_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       cum->fp_regs = fp_regs;
     }
 
+  /* On OpenVMS variable argument is either in Rn or Fn.  */
+  else if (TARGET_ABI_OPEN_VMS && named == 0)
+    {
+      cum->int_regs = cum->words;
+      cum->fp_regs = cum->words;
+    }
+
   /* Integral and aggregates go in general registers.  So do TFmode FP values.
      If we have run out of FR registers, then other FP values must also go in
      general registers.  This can happen when we have a SFmode HFA.  */
@@ -4315,10 +4818,9 @@ ia64_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
    boundary.  On ILP32 HPUX, TFmode arguments start on next even boundary
    even though their normal alignment is 8 bytes.  See ia64_function_arg.  */
 
-int
-ia64_function_arg_boundary (enum machine_mode mode, tree type)
+static unsigned int
+ia64_function_arg_boundary (enum machine_mode mode, const_tree type)
 {
-
   if (mode == TFmode && TARGET_HPUX && TARGET_ILP32)
     return PARM_BOUNDARY * 2;
 
@@ -4376,12 +4878,9 @@ ia64_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
   if ((TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == INTEGER_TYPE)
       ? int_size_in_bytes (type) > 8 : TYPE_ALIGN (type) > 8 * BITS_PER_UNIT)
     {
-      tree t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (valist), valist,
-                      size_int (2 * UNITS_PER_WORD - 1));
-      t = fold_convert (sizetype, t);
+      tree t = fold_build_pointer_plus_hwi (valist, 2 * UNITS_PER_WORD - 1);
       t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
-                 size_int (-2 * UNITS_PER_WORD));
-      t = fold_convert (TREE_TYPE (valist), t);
+                 build_int_cst (TREE_TYPE (t), -2 * UNITS_PER_WORD));
       gimplify_assign (unshare_expr (valist), t, pre_p);
     }
 
@@ -4427,12 +4926,20 @@ ia64_return_in_memory (const_tree valtype, const_tree fntype ATTRIBUTE_UNUSED)
 
 /* Return rtx for register that holds the function return value.  */
 
-rtx
-ia64_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
+static rtx
+ia64_function_value (const_tree valtype,
+                    const_tree fn_decl_or_type,
+                    bool outgoing ATTRIBUTE_UNUSED)
 {
   enum machine_mode mode;
   enum machine_mode hfa_mode;
+  int unsignedp;
+  const_tree func = fn_decl_or_type;
 
+  if (fn_decl_or_type
+      && !DECL_P (fn_decl_or_type))
+    func = NULL;
+  
   mode = TYPE_MODE (valtype);
   hfa_mode = hfa_element_mode (valtype, 0);
 
@@ -4502,10 +5009,36 @@ ia64_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
          return gen_rtx_PARALLEL (mode, gen_rtvec_v (i, loc));
        }
 
+      mode = promote_function_mode (valtype, mode, &unsignedp,
+                                    func ? TREE_TYPE (func) : NULL_TREE,
+                                    true);
+
       return gen_rtx_REG (mode, GR_RET_FIRST);
     }
 }
 
+/* Worker function for TARGET_LIBCALL_VALUE.  */
+
+static rtx
+ia64_libcall_value (enum machine_mode mode,
+                   const_rtx fun ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (mode,
+                     (((GET_MODE_CLASS (mode) == MODE_FLOAT
+                        || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+                       && (mode) != TFmode)
+                      ? FR_RET_FIRST : GR_RET_FIRST));
+}
+
+/* Worker function for FUNCTION_VALUE_REGNO_P.  */
+
+static bool
+ia64_function_value_regno_p (const unsigned int regno)
+{
+  return ((regno >= GR_RET_FIRST && regno <= GR_RET_LAST)
+          || (regno >= FR_RET_FIRST && regno <= FR_RET_LAST));
+}
+
 /* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
    We need to emit DTP-relative relocations.  */
 
@@ -4526,7 +5059,7 @@ ia64_output_dwarf_dtprel (FILE *file, int size, rtx x)
 /* ??? Do we need this?  It gets used only for 'a' operands.  We could perhaps
    also call this from ia64_print_operand for memory addresses.  */
 
-void
+static void
 ia64_print_operand_address (FILE * stream ATTRIBUTE_UNUSED,
                            rtx address ATTRIBUTE_UNUSED)
 {
@@ -4557,7 +5090,7 @@ ia64_print_operand_address (FILE * stream ATTRIBUTE_UNUSED,
        Linux kernel.
    v    Print vector constant value as an 8-byte integer value.  */
 
-void
+static void
 ia64_print_operand (FILE * file, rtx x, int code)
 {
   const char *str;
@@ -4844,6 +5377,14 @@ ia64_print_operand (FILE * file, rtx x, int code)
 
   return;
 }
+
+/* Worker function for TARGET_PRINT_OPERAND_PUNCT_VALID_P.  */
+
+static bool
+ia64_print_operand_punct_valid_p (unsigned char code)
+{
+  return (code == '+' || code == ',');
+}
 \f
 /* Compute a (partial) cost for rtx X.  Return true if the complete
    cost has been computed, and false if subexpressions should be
@@ -4851,8 +5392,8 @@ ia64_print_operand (FILE * file, rtx x, int code)
 /* ??? This is incomplete.  */
 
 static bool
-ia64_rtx_costs (rtx x, int code, int outer_code, int *total,
-               bool speed ATTRIBUTE_UNUSED)
+ia64_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
+               int *total, bool speed ATTRIBUTE_UNUSED)
 {
   switch (code)
     {
@@ -4888,13 +5429,18 @@ ia64_rtx_costs (rtx x, int code, int outer_code, int *total,
       *total = COSTS_N_INSNS (3);
       return true;
 
+    case FMA:
+      *total = COSTS_N_INSNS (4);
+      return true;
+
     case MULT:
       /* For multiplies wider than HImode, we have to go to the FPU,
          which normally involves copies.  Plus there's the latency
          of the multiply itself, and the latency of the instructions to
          transfer integer regs to FP regs.  */
-      /* ??? Check for FP mode.  */
-      if (GET_MODE_SIZE (GET_MODE (x)) > 2)
+      if (FLOAT_MODE_P (GET_MODE (x)))
+       *total = COSTS_N_INSNS (4);
+      else if (GET_MODE_SIZE (GET_MODE (x)) > 2)
         *total = COSTS_N_INSNS (10);
       else
        *total = COSTS_N_INSNS (2);
@@ -4902,6 +5448,13 @@ ia64_rtx_costs (rtx x, int code, int outer_code, int *total,
 
     case PLUS:
     case MINUS:
+      if (FLOAT_MODE_P (GET_MODE (x)))
+       {
+         *total = COSTS_N_INSNS (4);
+         return true;
+       }
+      /* FALLTHRU */
+
     case ASHIFT:
     case ASHIFTRT:
     case LSHIFTRT:
@@ -4925,9 +5478,9 @@ ia64_rtx_costs (rtx x, int code, int outer_code, int *total,
 /* Calculate the cost of moving data from a register in class FROM to
    one in class TO, using MODE.  */
 
-int
-ia64_register_move_cost (enum machine_mode mode, enum reg_class from,
-                        enum reg_class to)
+static int
+ia64_register_move_cost (enum machine_mode mode, reg_class_t from,
+                        reg_class_t to)
 {
   /* ADDL_REGS is the same as GR_REGS for movement purposes.  */
   if (to == ADDL_REGS)
@@ -4939,18 +5492,18 @@ ia64_register_move_cost (enum machine_mode mode, enum reg_class from,
      lower number class as the destination.  */
   if (from < to)
     {
-      enum reg_class tmp = to;
+      reg_class_t tmp = to;
       to = from, from = tmp;
     }
 
   /* Moving from FR<->GR in XFmode must be more expensive than 2,
      so that we get secondary memory reloads.  Between FR_REGS,
-     we have to make this at least as expensive as MEMORY_MOVE_COST
+     we have to make this at least as expensive as memory_move_cost
      to avoid spectacularly poor register class preferencing.  */
   if (mode == XFmode || mode == RFmode)
     {
       if (to != GR_REGS || from != GR_REGS)
-        return MEMORY_MOVE_COST (mode, to, 0);
+        return memory_move_cost (mode, to, false);
       else
        return 3;
     }
@@ -4963,20 +5516,20 @@ ia64_register_move_cost (enum machine_mode mode, enum reg_class from,
        return 3;
       /* Moving between PR and anything but GR is impossible.  */
       if (from != GR_REGS)
-       return MEMORY_MOVE_COST (mode, to, 0);
+       return memory_move_cost (mode, to, false);
       break;
 
     case BR_REGS:
       /* Moving between BR and anything but GR is impossible.  */
       if (from != GR_REGS && from != GR_AND_BR_REGS)
-       return MEMORY_MOVE_COST (mode, to, 0);
+       return memory_move_cost (mode, to, false);
       break;
 
     case AR_I_REGS:
     case AR_M_REGS:
       /* Moving between AR and anything but GR is impossible.  */
       if (from != GR_REGS)
-       return MEMORY_MOVE_COST (mode, to, 0);
+       return memory_move_cost (mode, to, false);
       break;
 
     case GR_REGS:
@@ -4994,11 +5547,28 @@ ia64_register_move_cost (enum machine_mode mode, enum reg_class from,
   return 2;
 }
 
-/* Implement PREFERRED_RELOAD_CLASS.  Place additional restrictions on RCLASS
-   to use when copying X into that class.  */
+/* Calculate the cost of moving data of MODE from a register to or from
+   memory.  */
 
-enum reg_class
-ia64_preferred_reload_class (rtx x, enum reg_class rclass)
+static int
+ia64_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+                      reg_class_t rclass,
+                      bool in ATTRIBUTE_UNUSED)
+{
+  if (rclass == GENERAL_REGS
+      || rclass == FR_REGS
+      || rclass == FP_REGS
+      || rclass == GR_AND_FR_REGS)
+    return 4;
+  else
+    return 10;
+}
+
+/* Implement TARGET_PREFERRED_RELOAD_CLASS.  Place additional restrictions
+   on RCLASS to use when copying X into that class.  */
+
+static reg_class_t
+ia64_preferred_reload_class (rtx x, reg_class_t rclass)
 {
   switch (rclass)
     {
@@ -5210,87 +5780,64 @@ fix_range (const char *const_str)
     }
 }
 
-/* Implement TARGET_HANDLE_OPTION.  */
+/* Implement TARGET_OPTION_OVERRIDE.  */
 
-static bool
-ia64_handle_option (size_t code, const char *arg, int value)
+static void
+ia64_option_override (void)
 {
-  static bool warned_itanium1_deprecated;
+  unsigned int i;
+  cl_deferred_option *opt;
+  VEC(cl_deferred_option,heap) *vec
+    = (VEC(cl_deferred_option,heap) *) ia64_deferred_options;
 
-  switch (code)
+  FOR_EACH_VEC_ELT (cl_deferred_option, vec, i, opt)
     {
-    case OPT_mfixed_range_:
-      fix_range (arg);
-      return true;
+      switch (opt->opt_index)
+       {
+       case OPT_mfixed_range_:
+         fix_range (opt->arg);
+         break;
 
-    case OPT_mtls_size_:
-      if (value != 14 && value != 22 && value != 64)
-       error ("bad value %<%s%> for -mtls-size= switch", arg);
-      return true;
+       default:
+         gcc_unreachable ();
+       }
+    }
 
-    case OPT_mtune_:
-      {
-       static struct pta
-         {
-           const char *name;           /* processor name or nickname.  */
-           enum processor_type processor;
-         }
-       const processor_alias_table[] =
-         {
-           {"itanium", PROCESSOR_ITANIUM},
-           {"itanium1", PROCESSOR_ITANIUM},
-           {"merced", PROCESSOR_ITANIUM},
-           {"itanium2", PROCESSOR_ITANIUM2},
-           {"mckinley", PROCESSOR_ITANIUM2},
-         };
-       int const pta_size = ARRAY_SIZE (processor_alias_table);
-       int i;
+  if (TARGET_AUTO_PIC)
+    target_flags |= MASK_CONST_GP;
 
-       for (i = 0; i < pta_size; i++)
-         if (!strcmp (arg, processor_alias_table[i].name))
-           {
-             ia64_tune = processor_alias_table[i].processor;
-             if (ia64_tune == PROCESSOR_ITANIUM
-                 && ! warned_itanium1_deprecated)
-               {
-                 inform (0,
-                         "value %<%s%> for -mtune= switch is deprecated",
-                         arg);
-                 inform (0, "GCC 4.4 is the last release with "
-                         "Itanium1 tuning support");
-                 warned_itanium1_deprecated = true;
-               }
-             break;
-           }
-       if (i == pta_size)
-         error ("bad value %<%s%> for -mtune= switch", arg);
-       return true;
-      }
+  /* Numerous experiment shows that IRA based loop pressure
+     calculation works better for RTL loop invariant motion on targets
+     with enough (>= 32) registers.  It is an expensive optimization.
+     So it is on only for peak performance.  */
+  if (optimize >= 3)
+    flag_ira_loop_pressure = 1;
 
-    default:
-      return true;
-    }
-}
 
-/* Implement OVERRIDE_OPTIONS.  */
+  ia64_section_threshold = (global_options_set.x_g_switch_value
+                           ? g_switch_value
+                           : IA64_DEFAULT_GVALUE);
 
-void
-ia64_override_options (void)
-{
-  if (TARGET_AUTO_PIC)
-    target_flags |= MASK_CONST_GP;
+  init_machine_status = ia64_init_machine_status;
 
-  if (TARGET_INLINE_SQRT == INL_MIN_LAT)
-    {
-      warning (0, "not yet implemented: latency-optimized inline square root");
-      TARGET_INLINE_SQRT = INL_MAX_THR;
-    }
+  if (align_functions <= 0)
+    align_functions = 64;
+  if (align_loops <= 0)
+    align_loops = 32;
+  if (TARGET_ABI_OPEN_VMS)
+    flag_no_common = 1;
+
+  ia64_override_options_after_change();
+}
 
-  ia64_flag_schedule_insns2 = flag_schedule_insns_after_reload;
-  flag_schedule_insns_after_reload = 0;
+/* Implement targetm.override_options_after_change.  */
 
+static void
+ia64_override_options_after_change (void)
+{
   if (optimize >= 3
-      && ! sel_sched_switch_set)
+      && !global_options_set.x_flag_selective_scheduling
+      && !global_options_set.x_flag_selective_scheduling2)
     {
       flag_selective_scheduling2 = 1;
       flag_sel_sched_pipelining = 1;
@@ -5307,15 +5854,6 @@ ia64_override_options (void)
          a transformation.  */
       flag_auto_inc_dec = 0;
     }
-
-  ia64_section_threshold = g_switch_set ? g_switch_value : IA64_DEFAULT_GVALUE;
-
-  init_machine_status = ia64_init_machine_status;
-
-  if (align_functions <= 0)
-    align_functions = 64;
-  if (align_loops <= 0)
-    align_loops = 32;
 }
 
 /* Initialize the record of emitted frame related registers.  */
@@ -5328,7 +5866,7 @@ void ia64_init_expanders (void)
 static struct machine_function *
 ia64_init_machine_status (void)
 {
-  return GGC_CNEW (struct machine_function);
+  return ggc_alloc_cleared_machine_function ();
 }
 \f
 static enum attr_itanium_class ia64_safe_itanium_class (rtx);
@@ -5339,6 +5877,8 @@ ia64_safe_itanium_class (rtx insn)
 {
   if (recog_memoized (insn) >= 0)
     return get_attr_itanium_class (insn);
+  else if (DEBUG_INSN_P (insn))
+    return ITANIUM_CLASS_IGNORE;
   else
     return ITANIUM_CLASS_UNKNOWN;
 }
@@ -5521,15 +6061,14 @@ rws_access_regno (int regno, struct reg_flags flags, int pred)
          break;
 
        case 1:
-         /* The register has been written via a predicate.  If this is
-            not a complementary predicate, then we need a barrier.  */
-         /* ??? This assumes that P and P+1 are always complementary
-            predicates for P even.  */
+         /* The register has been written via a predicate.  Treat
+            it like a unconditional write and do not try to check
+            for complementary pred reg in earlier write.  */
          if (flags.is_and && rws_sum[regno].written_by_and)
            ;
          else if (flags.is_or && rws_sum[regno].written_by_or)
            ;
-         else if ((rws_sum[regno].first_pred ^ 1) != pred)
+         else
            need_barrier = 1;
          if (!in_safe_group_barrier)
            rws_update (regno, flags, pred);
@@ -5590,12 +6129,9 @@ rws_access_regno (int regno, struct reg_flags flags, int pred)
          break;
 
        case 1:
-         /* The register has been written via a predicate.  If this is
-            not a complementary predicate, then we need a barrier.  */
-         /* ??? This assumes that P and P+1 are always complementary
-            predicates for P even.  */
-         if ((rws_sum[regno].first_pred ^ 1) != pred)
-           need_barrier = 1;
+         /* The register has been written via a predicate, assume we
+            need a barrier (don't check for complementary regs).  */
+         need_barrier = 1;
          break;
 
        case 2:
@@ -5838,6 +6374,17 @@ rtx_needs_barrier (rtx x, struct reg_flags flags, int pred)
              break;
 
            case CLOBBER:
+             if (REG_P (XEXP (pat, 0))
+                 && extract_asm_operands (x) != NULL_RTX
+                 && REGNO (XEXP (pat, 0)) != AR_UNAT_REGNUM)
+               {
+                 new_flags.is_write = 1;
+                 need_barrier |= rtx_needs_barrier (XEXP (pat, 0),
+                                                    new_flags, pred);
+                 new_flags = flags;
+               }
+             break;
+
            case RETURN:
              break;
 
@@ -5943,6 +6490,7 @@ rtx_needs_barrier (rtx x, struct reg_flags flags, int pred)
        case UNSPEC_PIC_CALL:
         case UNSPEC_MF:
         case UNSPEC_FETCHADD_ACQ:
+        case UNSPEC_FETCHADD_REL:
        case UNSPEC_BSP_VALUE:
        case UNSPEC_FLUSHRS:
        case UNSPEC_BUNDLE_SELECTOR:
@@ -5986,6 +6534,7 @@ rtx_needs_barrier (rtx x, struct reg_flags flags, int pred)
          break;
 
         case UNSPEC_CMPXCHG_ACQ:
+        case UNSPEC_CMPXCHG_REL:
          need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 1), flags, pred);
          need_barrier |= rtx_needs_barrier (XVECEXP (x, 0, 2), flags, pred);
          break;
@@ -6095,6 +6644,7 @@ group_barrier_needed (rtx insn)
   switch (GET_CODE (insn))
     {
     case NOTE:
+    case DEBUG_INSN:
       break;
 
     case BARRIER:
@@ -6252,7 +6802,7 @@ emit_insn_group_barriers (FILE *dump)
          init_insn_group_barriers ();
          last_label = 0;
        }
-      else if (INSN_P (insn))
+      else if (NONDEBUG_INSN_P (insn))
        {
          insns_since_last_label = 1;
 
@@ -6300,7 +6850,7 @@ emit_all_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED)
 
          init_insn_group_barriers ();
        }
-      else if (INSN_P (insn))
+      else if (NONDEBUG_INSN_P (insn))
        {
          if (recog_memoized (insn) == CODE_FOR_insn_group_barrier)
            init_insn_group_barriers ();
@@ -6384,17 +6934,6 @@ static int stop_before_p = 0;
 
 static int clocks_length;
 
-/* The following array element values are cycles on which the
-   corresponding insn will be issued.  The array is used only for
-   Itanium1.  */
-
-static int *clocks;
-
-/* The following array element values are numbers of cycles should be
-   added to improve insn scheduling for MM_insns for Itanium1.  */
-
-static int *add_cycles;
-
 /* The following variable value is number of data speculations in progress.  */
 static int pending_data_specs = 0;
 
@@ -6768,8 +7307,6 @@ ia64_sched_reorder2 (FILE *dump ATTRIBUTE_UNUSED,
                     int sched_verbose ATTRIBUTE_UNUSED, rtx *ready,
                     int *pn_ready, int clock_var)
 {
-  if (ia64_tune == PROCESSOR_ITANIUM && reload_completed && last_scheduled_insn)
-    clocks [INSN_UID (last_scheduled_insn)] = clock_var;
   return ia64_dfa_sched_reorder (dump, sched_verbose, ready, pn_ready,
                                 clock_var, 1);
 }
@@ -6793,6 +7330,9 @@ ia64_variable_issue (FILE *dump ATTRIBUTE_UNUSED,
        pending_data_specs--;
     }
 
+  if (DEBUG_INSN_P (insn))
+    return 1;
+
   last_scheduled_insn = insn;
   memcpy (prev_cycle_state, curr_state, dfa_state_size);
   if (reload_completed)
@@ -6872,9 +7412,11 @@ static int
 ia64_dfa_new_cycle (FILE *dump, int verbose, rtx insn, int last_clock,
                    int clock, int *sort_p)
 {
-  int setup_clocks_p = FALSE;
-
   gcc_assert (insn && INSN_P (insn));
+
+  if (DEBUG_INSN_P (insn))
+    return 0;
+
   /* When a group barrier is needed for insn, last_scheduled_insn
      should be set.  */
   gcc_assert (!(reload_completed && safe_group_barrier_needed (insn))
@@ -6911,8 +7453,6 @@ ia64_dfa_new_cycle (FILE *dump, int verbose, rtx insn, int last_clock,
            *sort_p = 0;
          return 1;
        }
-      else if (reload_completed)
-       setup_clocks_p = TRUE;
 
       if (last_scheduled_insn)
        {
@@ -6928,40 +7468,6 @@ ia64_dfa_new_cycle (FILE *dump, int verbose, rtx insn, int last_clock,
            }
        }
     }
-  else if (reload_completed)
-    setup_clocks_p = TRUE;
-
-  if (setup_clocks_p && ia64_tune == PROCESSOR_ITANIUM
-      && GET_CODE (PATTERN (insn)) != ASM_INPUT
-      && asm_noperands (PATTERN (insn)) < 0)
-    {
-      enum attr_itanium_class c = ia64_safe_itanium_class (insn);
-
-      if (c != ITANIUM_CLASS_MMMUL && c != ITANIUM_CLASS_MMSHF)
-       {
-         sd_iterator_def sd_it;
-         dep_t dep;
-         int d = -1;
-
-         FOR_EACH_DEP (insn, SD_LIST_BACK, sd_it, dep)
-           if (DEP_TYPE (dep) == REG_DEP_TRUE)
-             {
-               enum attr_itanium_class dep_class;
-               rtx dep_insn = DEP_PRO (dep);
-
-               dep_class = ia64_safe_itanium_class (dep_insn);
-               if ((dep_class == ITANIUM_CLASS_MMMUL
-                    || dep_class == ITANIUM_CLASS_MMSHF)
-                   && last_clock - clocks [INSN_UID (dep_insn)] < 4
-                   && (d < 0
-                       || last_clock - clocks [INSN_UID (dep_insn)] < d))
-                 d = last_clock - clocks [INSN_UID (dep_insn)];
-             }
-         if (d >= 0)
-           add_cycles [INSN_UID (insn)] = 3 - d;
-       }
-    }
-
   return 0;
 }
 
@@ -6973,17 +7479,7 @@ ia64_h_i_d_extended (void)
   if (stops_p != NULL) 
     {
       int new_clocks_length = get_max_uid () * 3 / 2;
-      
       stops_p = (char *) xrecalloc (stops_p, new_clocks_length, clocks_length, 1);
-      
-      if (ia64_tune == PROCESSOR_ITANIUM)
-       {
-         clocks = (int *) xrecalloc (clocks, new_clocks_length, clocks_length,
-                                     sizeof (int));
-         add_cycles = (int *) xrecalloc (add_cycles, new_clocks_length,
-                                         clocks_length, sizeof (int));
-       }
-      
       clocks_length = new_clocks_length;
     }
 }
@@ -8270,7 +8766,7 @@ ia64_add_bundle_selector_before (int template0, rtx insn)
   ia64_emit_insn_before (b, insn);
 #if NR_BUNDLES == 10
   if ((template0 == 4 || template0 == 5)
-      && (flag_unwind_tables || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)))
+      && ia64_except_unwind_info (&global_options) == UI_TARGET)
     {
       int i;
       rtx note = NULL_RTX;
@@ -8340,9 +8836,7 @@ ia64_add_bundle_selector_before (int template0, rtx insn)
    automaton state for each insn in chosen bundle states.
 
    So the algorithm makes two (forward and backward) passes through
-   EBB.  There is an additional forward pass through EBB for Itanium1
-   processor.  This pass inserts more nops to make dependency between
-   a producer insn and MMMUL/MMSHF at least 4 cycles long.  */
+   EBB.  */
 
 static void
 bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
@@ -8441,14 +8935,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
               || (GET_MODE (next_insn) == TImode
                   && INSN_CODE (insn) != CODE_FOR_insn_group_barrier));
          if (type == TYPE_F || type == TYPE_B || type == TYPE_L
-             || type == TYPE_S
-             /* We need to insert 2 nops for cases like M_MII.  To
-                guarantee issuing all insns on the same cycle for
-                Itanium 1, we need to issue 2 nops after the first M
-                insn (MnnMII where n is a nop insn).  */
-             || ((type == TYPE_M || type == TYPE_A)
-                 && ia64_tune == PROCESSOR_ITANIUM
-                 && !bundle_end_p && pos == 1))
+             || type == TYPE_S)
            issue_nops_and_insn (curr_state, 2, insn, bundle_end_p,
                                 only_bundle_end_p);
          issue_nops_and_insn (curr_state, 1, insn, bundle_end_p,
@@ -8484,9 +8971,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
               curr_state->before_nops_num, curr_state->after_nops_num,
               curr_state->accumulated_insns_num, curr_state->branch_deviation,
               curr_state->middle_bundle_stops,
-              (ia64_tune == PROCESSOR_ITANIUM
-               ? ((struct DFA_chip *) curr_state->dfa_state)->oneb_automaton_state
-               : ((struct DFA_chip *) curr_state->dfa_state)->twob_automaton_state),
+              ((struct DFA_chip *) curr_state->dfa_state)->twob_automaton_state,
               INSN_UID (insn));
          }
     }
@@ -8549,9 +9034,7 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
             curr_state->before_nops_num, curr_state->after_nops_num,
             curr_state->accumulated_insns_num, curr_state->branch_deviation,
             curr_state->middle_bundle_stops,
-            (ia64_tune == PROCESSOR_ITANIUM
-             ? ((struct DFA_chip *) curr_state->dfa_state)->oneb_automaton_state
-             : ((struct DFA_chip *) curr_state->dfa_state)->twob_automaton_state),
+            ((struct DFA_chip *) curr_state->dfa_state)->twob_automaton_state,
             INSN_UID (insn));
        }
       /* Find the position in the current bundle window.  The window can
@@ -8650,103 +9133,6 @@ bundling (FILE *dump, int verbose, rtx prev_head_insn, rtx tail)
            }
        }
     }
-  if (ia64_tune == PROCESSOR_ITANIUM)
-    /* Insert additional cycles for MM-insns (MMMUL and MMSHF).
-       Itanium1 has a strange design, if the distance between an insn
-       and dependent MM-insn is less 4 then we have a 6 additional
-       cycles stall.  So we make the distance equal to 4 cycles if it
-       is less.  */
-    for (insn = get_next_important_insn (NEXT_INSN (prev_head_insn), tail);
-        insn != NULL_RTX;
-        insn = next_insn)
-      {
-       gcc_assert (INSN_P (insn)
-                   && ia64_safe_itanium_class (insn) != ITANIUM_CLASS_IGNORE
-                   && GET_CODE (PATTERN (insn)) != USE
-                   && GET_CODE (PATTERN (insn)) != CLOBBER);
-       next_insn = get_next_important_insn (NEXT_INSN (insn), tail);
-       if (INSN_UID (insn) < clocks_length && add_cycles [INSN_UID (insn)])
-         /* We found a MM-insn which needs additional cycles.  */
-         {
-           rtx last;
-           int i, j, n;
-           int pred_stop_p;
-
-           /* Now we are searching for a template of the bundle in
-              which the MM-insn is placed and the position of the
-              insn in the bundle (0, 1, 2).  Also we are searching
-              for that there is a stop before the insn.  */
-           last = prev_active_insn (insn);
-           pred_stop_p = recog_memoized (last) == CODE_FOR_insn_group_barrier;
-           if (pred_stop_p)
-             last = prev_active_insn (last);
-           n = 0;
-           for (;; last = prev_active_insn (last))
-             if (recog_memoized (last) == CODE_FOR_bundle_selector)
-               {
-                 template0 = XINT (XVECEXP (PATTERN (last), 0, 0), 0);
-                 if (template0 == 9)
-                   /* The insn is in MLX bundle.  Change the template
-                      onto MFI because we will add nops before the
-                      insn.  It simplifies subsequent code a lot.  */
-                   PATTERN (last)
-                     = gen_bundle_selector (const2_rtx); /* -> MFI */
-                 break;
-               }
-             else if (recog_memoized (last) != CODE_FOR_insn_group_barrier
-                      && (ia64_safe_itanium_class (last)
-                          != ITANIUM_CLASS_IGNORE))
-               n++;
-           /* Some check of correctness: the stop is not at the
-              bundle start, there are no more 3 insns in the bundle,
-              and the MM-insn is not at the start of bundle with
-              template MLX.  */
-           gcc_assert ((!pred_stop_p || n)
-                       && n <= 2
-                       && (template0 != 9 || !n));
-           /* Put nops after the insn in the bundle.  */
-           for (j = 3 - n; j > 0; j --)
-             ia64_emit_insn_before (gen_nop (), insn);
-           /* It takes into account that we will add more N nops
-              before the insn lately -- please see code below.  */
-           add_cycles [INSN_UID (insn)]--;
-           if (!pred_stop_p || add_cycles [INSN_UID (insn)])
-             ia64_emit_insn_before (gen_insn_group_barrier (GEN_INT (3)),
-                                    insn);
-           if (pred_stop_p)
-             add_cycles [INSN_UID (insn)]--;
-           for (i = add_cycles [INSN_UID (insn)]; i > 0; i--)
-             {
-               /* Insert "MII;" template.  */
-               ia64_emit_insn_before (gen_bundle_selector (const0_rtx),
-                                      insn);
-               ia64_emit_insn_before (gen_nop (), insn);
-               ia64_emit_insn_before (gen_nop (), insn);
-               if (i > 1)
-                 {
-                   /* To decrease code size, we use "MI;I;"
-                      template.  */
-                   ia64_emit_insn_before
-                     (gen_insn_group_barrier (GEN_INT (3)), insn);
-                   i--;
-                 }
-               ia64_emit_insn_before (gen_nop (), insn);
-               ia64_emit_insn_before (gen_insn_group_barrier (GEN_INT (3)),
-                                      insn);
-             }
-           /* Put the MM-insn in the same slot of a bundle with the
-              same template as the original one.  */
-           ia64_add_bundle_selector_before (template0, insn);
-           /* To put the insn in the same slot, add necessary number
-              of nops.  */
-           for (j = n; j > 0; j --)
-             ia64_emit_insn_before (gen_nop (), insn);
-           /* Put the stop if the original bundle had it.  */
-           if (pred_stop_p)
-             ia64_emit_insn_before (gen_insn_group_barrier (GEN_INT (3)),
-                                    insn);
-         }
-      }
 
 #ifdef ENABLE_CHECKING
   {
@@ -8836,7 +9222,6 @@ final_emit_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED)
   rtx insn;
   int need_barrier_p = 0;
   int seen_good_insn = 0;
-  rtx prev_insn = NULL_RTX;
 
   init_insn_group_barriers ();
 
@@ -8859,16 +9244,14 @@ final_emit_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED)
          init_insn_group_barriers ();
          seen_good_insn = 0;
          need_barrier_p = 0;
-         prev_insn = NULL_RTX;
        }
-      else if (INSN_P (insn))
+      else if (NONDEBUG_INSN_P (insn))
        {
          if (recog_memoized (insn) == CODE_FOR_insn_group_barrier)
            {
              init_insn_group_barriers ();
              seen_good_insn = 0;
              need_barrier_p = 0;
-             prev_insn = NULL_RTX;
            }
          else if (need_barrier_p || group_barrier_needed (insn)
                   || (mflag_sched_stop_bits_after_every_cycle
@@ -8915,14 +9298,10 @@ final_emit_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED)
              if (recog_memoized (insn) >= 0
                  && important_for_bundling_p (insn))
                seen_good_insn = 1;
-             prev_insn = NULL_RTX;
            }
          else if (recog_memoized (insn) >= 0
                   && important_for_bundling_p (insn))
-           {
-             prev_insn = insn;
-             seen_good_insn = 1;
-           }
+           seen_good_insn = 1;
          need_barrier_p = (GET_CODE (insn) == CALL_INSN
                            || GET_CODE (PATTERN (insn)) == ASM_INPUT
                            || asm_noperands (PATTERN (insn)) >= 0);
@@ -9129,23 +9508,25 @@ ia64_reorg (void)
   if (optimize == 0)
     split_all_insns ();
 
-  if (optimize && ia64_flag_schedule_insns2
+  if (optimize && flag_schedule_insns_after_reload
       && dbg_cnt (ia64_sched2))
     {
+      basic_block bb;
       timevar_push (TV_SCHED2);
       ia64_final_schedule = 1;
 
+      /* We can't let modulo-sched prevent us from scheduling any bbs,
+        since we need the final schedule to produce bundle information.  */
+      FOR_EACH_BB (bb)
+       bb->flags &= ~BB_DISABLE_SCHEDULE;
+
       initiate_bundle_states ();
       ia64_nop = make_insn_raw (gen_nop ());
       PREV_INSN (ia64_nop) = NEXT_INSN (ia64_nop) = NULL_RTX;
       recog_memoized (ia64_nop);
       clocks_length = get_max_uid () + 1;
       stops_p = XCNEWVEC (char, clocks_length);
-      if (ia64_tune == PROCESSOR_ITANIUM)
-       {
-         clocks = XCNEWVEC (int, clocks_length);
-         add_cycles = XCNEWVEC (int, clocks_length);
-       }
+
       if (ia64_tune == PROCESSOR_ITANIUM2)
        {
          pos_1 = get_cpu_unit_code ("2_1");
@@ -9217,11 +9598,6 @@ ia64_reorg (void)
       /* We cannot reuse this one because it has been corrupted by the
         evil glat.  */
       finish_bundle_states ();
-      if (ia64_tune == PROCESSOR_ITANIUM)
-       {
-         free (add_cycles);
-         free (clocks);
-       }
       free (stops_p);
       stops_p = NULL;
       emit_insn_group_barriers (dump_file);
@@ -9237,7 +9613,7 @@ ia64_reorg (void)
   /* A call must not be the last instruction in a function, so that the
      return address is still within the function, so that unwinding works
      properly.  Note that IA-64 differs from dwarf2 on this point.  */
-  if (flag_unwind_tables || (flag_exceptions && !USING_SJLJ_EXCEPTIONS))
+  if (ia64_except_unwind_info (&global_options) == UI_TARGET)
     {
       rtx insn;
       int saw_stop = 0;
@@ -9245,26 +9621,30 @@ ia64_reorg (void)
       insn = get_last_insn ();
       if (! INSN_P (insn))
         insn = prev_active_insn (insn);
-      /* Skip over insns that expand to nothing.  */
-      while (GET_CODE (insn) == INSN && get_attr_empty (insn) == EMPTY_YES)
-        {
-         if (GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
-             && XINT (PATTERN (insn), 1) == UNSPECV_INSN_GROUP_BARRIER)
-           saw_stop = 1;
-         insn = prev_active_insn (insn);
-       }
-      if (GET_CODE (insn) == CALL_INSN)
+      if (insn)
        {
-         if (! saw_stop)
-           emit_insn (gen_insn_group_barrier (GEN_INT (3)));
-         emit_insn (gen_break_f ());
-         emit_insn (gen_insn_group_barrier (GEN_INT (3)));
+         /* Skip over insns that expand to nothing.  */
+         while (GET_CODE (insn) == INSN
+                && get_attr_empty (insn) == EMPTY_YES)
+           {
+             if (GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
+                 && XINT (PATTERN (insn), 1) == UNSPECV_INSN_GROUP_BARRIER)
+               saw_stop = 1;
+             insn = prev_active_insn (insn);
+           }
+         if (GET_CODE (insn) == CALL_INSN)
+           {
+             if (! saw_stop)
+               emit_insn (gen_insn_group_barrier (GEN_INT (3)));
+             emit_insn (gen_break_f ());
+             emit_insn (gen_insn_group_barrier (GEN_INT (3)));
+           }
        }
     }
 
   emit_predicate_relation_info ();
 
-  if (ia64_flag_var_tracking)
+  if (flag_var_tracking)
     {
       timevar_push (TV_VAR_TRACKING);
       variable_tracking_main ();
@@ -9317,7 +9697,7 @@ ia64_epilogue_uses (int regno)
 int
 ia64_eh_uses (int regno)
 {
-  enum ia64_frame_regs r;
+  unsigned int r;
 
   if (! reload_completed)
     return 0;
@@ -9393,56 +9773,11 @@ static bool need_copy_state;
 # define MAX_ARTIFICIAL_LABEL_BYTES 30
 #endif
 
-/* Emit a debugging label after a call-frame-related insn.  We'd
-   rather output the label right away, but we'd have to output it
-   after, not before, the instruction, and the instruction has not
-   been output yet.  So we emit the label after the insn, delete it to
-   avoid introducing basic blocks, and mark it as preserved, such that
-   it is still output, given that it is referenced in debug info.  */
-
-static const char *
-ia64_emit_deleted_label_after_insn (rtx insn)
-{
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-  rtx lb = gen_label_rtx ();
-  rtx label_insn = emit_label_after (lb, insn);
-
-  LABEL_PRESERVE_P (lb) = 1;
-
-  delete_insn (label_insn);
-
-  ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (label_insn));
-
-  return xstrdup (label);
-}
-
-/* Define the CFA after INSN with the steady-state definition.  */
-
-static void
-ia64_dwarf2out_def_steady_cfa (rtx insn)
-{
-  rtx fp = frame_pointer_needed
-    ? hard_frame_pointer_rtx
-    : stack_pointer_rtx;
-
-  dwarf2out_def_cfa
-    (ia64_emit_deleted_label_after_insn (insn),
-     REGNO (fp),
-     ia64_initial_elimination_offset
-     (REGNO (arg_pointer_rtx), REGNO (fp))
-     + ARG_POINTER_CFA_OFFSET (current_function_decl));
-}
-
-/* The generic dwarf2 frame debug info generator does not define a
-   separate region for the very end of the epilogue, so refrain from
-   doing so in the IA64-specific code as well.  */
-
-#define IA64_CHANGE_CFA_IN_EPILOGUE 0
-
 /* The function emits unwind directives for the start of an epilogue.  */
 
 static void
-process_epilogue (FILE *asm_out_file, rtx insn, bool unwind, bool frame)
+process_epilogue (FILE *asm_out_file, rtx insn ATTRIBUTE_UNUSED,
+                 bool unwind, bool frame ATTRIBUTE_UNUSED)
 {
   /* If this isn't the last block of the function, then we need to label the
      current state, and copy it back in at the start of the next block.  */
@@ -9457,58 +9792,21 @@ process_epilogue (FILE *asm_out_file, rtx insn, bool unwind, bool frame)
 
   if (unwind)
     fprintf (asm_out_file, "\t.restore sp\n");
-  if (IA64_CHANGE_CFA_IN_EPILOGUE && frame)
-    dwarf2out_def_cfa (ia64_emit_deleted_label_after_insn (insn),
-                      STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
 }
 
-/* This function processes a SET pattern looking for specific patterns
-   which result in emitting an assembly directive required for unwinding.  */
+/* This function processes a SET pattern for REG_CFA_ADJUST_CFA.  */
 
-static int
-process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame)
+static void
+process_cfa_adjust_cfa (FILE *asm_out_file, rtx pat, rtx insn,
+                       bool unwind, bool frame)
 {
-  rtx src = SET_SRC (pat);
   rtx dest = SET_DEST (pat);
-  int src_regno, dest_regno;
-
-  /* Look for the ALLOC insn.  */
-  if (GET_CODE (src) == UNSPEC_VOLATILE
-      && XINT (src, 1) == UNSPECV_ALLOC
-      && GET_CODE (dest) == REG)
-    {
-      dest_regno = REGNO (dest);
-
-      /* If this is the final destination for ar.pfs, then this must
-        be the alloc in the prologue.  */
-      if (dest_regno == current_frame_info.r[reg_save_ar_pfs])
-       {
-         if (unwind)
-           fprintf (asm_out_file, "\t.save ar.pfs, r%d\n",
-                    ia64_dbx_register_number (dest_regno));
-       }
-      else
-       {
-         /* This must be an alloc before a sibcall.  We must drop the
-            old frame info.  The easiest way to drop the old frame
-            info is to ensure we had a ".restore sp" directive
-            followed by a new prologue.  If the procedure doesn't
-            have a memory-stack frame, we'll issue a dummy ".restore
-            sp" now.  */
-         if (current_frame_info.total_size == 0 && !frame_pointer_needed)
-           /* if haven't done process_epilogue() yet, do it now */
-           process_epilogue (asm_out_file, insn, unwind, frame);
-         if (unwind)
-           fprintf (asm_out_file, "\t.prologue\n");
-       }
-      return 1;
-    }
+  rtx src = SET_SRC (pat);
 
-  /* Look for SP = ....  */
-  if (GET_CODE (dest) == REG && REGNO (dest) == STACK_POINTER_REGNUM)
+  if (dest == stack_pointer_rtx)
     {
       if (GET_CODE (src) == PLUS)
-        {
+       {
          rtx op0 = XEXP (src, 0);
          rtx op1 = XEXP (src, 1);
          
@@ -9518,253 +9816,338 @@ process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame)
            {
              gcc_assert (!frame_pointer_needed);
              if (unwind)
-               fprintf (asm_out_file, "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n",
+               fprintf (asm_out_file,
+                        "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n",
                         -INTVAL (op1));
-             if (frame)
-               ia64_dwarf2out_def_steady_cfa (insn);
            }
          else
            process_epilogue (asm_out_file, insn, unwind, frame);
        }
       else
        {
-         gcc_assert (GET_CODE (src) == REG
-                     && REGNO (src) == HARD_FRAME_POINTER_REGNUM);
+         gcc_assert (src == hard_frame_pointer_rtx);
          process_epilogue (asm_out_file, insn, unwind, frame);
        }
-
-      return 1;
     }
-
-  /* Register move we need to look at.  */
-  if (GET_CODE (dest) == REG && GET_CODE (src) == REG)
+  else if (dest == hard_frame_pointer_rtx)
     {
-      src_regno = REGNO (src);
-      dest_regno = REGNO (dest);
-
-      switch (src_regno)
-       {
-       case BR_REG (0):
-         /* Saving return address pointer.  */
-         gcc_assert (dest_regno == current_frame_info.r[reg_save_b0]);
-         if (unwind)
-           fprintf (asm_out_file, "\t.save rp, r%d\n",
-                    ia64_dbx_register_number (dest_regno));
-         return 1;
-
-       case PR_REG (0):
-         gcc_assert (dest_regno == current_frame_info.r[reg_save_pr]);
-         if (unwind)
-           fprintf (asm_out_file, "\t.save pr, r%d\n",
-                    ia64_dbx_register_number (dest_regno));
-         return 1;
+      gcc_assert (src == stack_pointer_rtx);
+      gcc_assert (frame_pointer_needed);
 
-       case AR_UNAT_REGNUM:
-         gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_unat]);
-         if (unwind)
-           fprintf (asm_out_file, "\t.save ar.unat, r%d\n",
-                    ia64_dbx_register_number (dest_regno));
-         return 1;
+      if (unwind)
+       fprintf (asm_out_file, "\t.vframe r%d\n",
+                ia64_dbx_register_number (REGNO (dest)));
+    }
+  else
+    gcc_unreachable ();
+}
 
-       case AR_LC_REGNUM:
-         gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_lc]);
-         if (unwind)
-           fprintf (asm_out_file, "\t.save ar.lc, r%d\n",
-                    ia64_dbx_register_number (dest_regno));
-         return 1;
+/* This function processes a SET pattern for REG_CFA_REGISTER.  */
 
-       case STACK_POINTER_REGNUM:
-         gcc_assert (dest_regno == HARD_FRAME_POINTER_REGNUM
-                     && frame_pointer_needed);
-         if (unwind)
-           fprintf (asm_out_file, "\t.vframe r%d\n",
-                    ia64_dbx_register_number (dest_regno));
-         if (frame)
-           ia64_dwarf2out_def_steady_cfa (insn);
-         return 1;
+static void
+process_cfa_register (FILE *asm_out_file, rtx pat, bool unwind)
+{
+  rtx dest = SET_DEST (pat);
+  rtx src = SET_SRC (pat);
+  int dest_regno = REGNO (dest);
+  int src_regno;
 
-       default:
-         /* Everything else should indicate being stored to memory.  */
-         gcc_unreachable ();
-       }
+  if (src == pc_rtx)
+    {
+      /* Saving return address pointer.  */
+      if (unwind)
+       fprintf (asm_out_file, "\t.save rp, r%d\n",
+                ia64_dbx_register_number (dest_regno));
+      return;
     }
 
-  /* Memory store we need to look at.  */
-  if (GET_CODE (dest) == MEM && GET_CODE (src) == REG)
+  src_regno = REGNO (src);
+
+  switch (src_regno)
     {
-      long off;
-      rtx base;
-      const char *saveop;
+    case PR_REG (0):
+      gcc_assert (dest_regno == current_frame_info.r[reg_save_pr]);
+      if (unwind)
+       fprintf (asm_out_file, "\t.save pr, r%d\n",
+                ia64_dbx_register_number (dest_regno));
+      break;
 
-      if (GET_CODE (XEXP (dest, 0)) == REG)
-       {
-         base = XEXP (dest, 0);
-         off = 0;
-       }
-      else
-       {
-         gcc_assert (GET_CODE (XEXP (dest, 0)) == PLUS
-                     && GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT);
-         base = XEXP (XEXP (dest, 0), 0);
-         off = INTVAL (XEXP (XEXP (dest, 0), 1));
-       }
+    case AR_UNAT_REGNUM:
+      gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_unat]);
+      if (unwind)
+       fprintf (asm_out_file, "\t.save ar.unat, r%d\n",
+                ia64_dbx_register_number (dest_regno));
+      break;
 
-      if (base == hard_frame_pointer_rtx)
-       {
-         saveop = ".savepsp";
-         off = - off;
-       }
-      else
-       {
-         gcc_assert (base == stack_pointer_rtx);
-         saveop = ".savesp";
-       }
+    case AR_LC_REGNUM:
+      gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_lc]);
+      if (unwind)
+       fprintf (asm_out_file, "\t.save ar.lc, r%d\n",
+                ia64_dbx_register_number (dest_regno));
+      break;
 
-      src_regno = REGNO (src);
-      switch (src_regno)
-       {
-       case BR_REG (0):
-         gcc_assert (!current_frame_info.r[reg_save_b0]);
-         if (unwind)
-           fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off);
-         return 1;
+    default:
+      /* Everything else should indicate being stored to memory.  */
+      gcc_unreachable ();
+    }
+}
 
-       case PR_REG (0):
-         gcc_assert (!current_frame_info.r[reg_save_pr]);
-         if (unwind)
-           fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off);
-         return 1;
+/* This function processes a SET pattern for REG_CFA_OFFSET.  */
 
-       case AR_LC_REGNUM:
-         gcc_assert (!current_frame_info.r[reg_save_ar_lc]);
-         if (unwind)
-           fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off);
-         return 1;
+static void
+process_cfa_offset (FILE *asm_out_file, rtx pat, bool unwind)
+{
+  rtx dest = SET_DEST (pat);
+  rtx src = SET_SRC (pat);
+  int src_regno = REGNO (src);
+  const char *saveop;
+  HOST_WIDE_INT off;
+  rtx base;
 
-       case AR_PFS_REGNUM:
-         gcc_assert (!current_frame_info.r[reg_save_ar_pfs]);
-         if (unwind)
-           fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off);
-         return 1;
+  gcc_assert (MEM_P (dest));
+  if (GET_CODE (XEXP (dest, 0)) == REG)
+    {
+      base = XEXP (dest, 0);
+      off = 0;
+    }
+  else
+    {
+      gcc_assert (GET_CODE (XEXP (dest, 0)) == PLUS
+                 && GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT);
+      base = XEXP (XEXP (dest, 0), 0);
+      off = INTVAL (XEXP (XEXP (dest, 0), 1));
+    }
 
-       case AR_UNAT_REGNUM:
-         gcc_assert (!current_frame_info.r[reg_save_ar_unat]);
-         if (unwind)
-           fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off);
-         return 1;
+  if (base == hard_frame_pointer_rtx)
+    {
+      saveop = ".savepsp";
+      off = - off;
+    }
+  else
+    {
+      gcc_assert (base == stack_pointer_rtx);
+      saveop = ".savesp";
+    }
 
-       case GR_REG (4):
-       case GR_REG (5):
-       case GR_REG (6):
-       case GR_REG (7):
-         if (unwind)
-           fprintf (asm_out_file, "\t.save.g 0x%x\n",
-                    1 << (src_regno - GR_REG (4)));
-         return 1;
+  src_regno = REGNO (src);
+  switch (src_regno)
+    {
+    case BR_REG (0):
+      gcc_assert (!current_frame_info.r[reg_save_b0]);
+      if (unwind)
+       fprintf (asm_out_file, "\t%s rp, " HOST_WIDE_INT_PRINT_DEC "\n",
+                saveop, off);
+      break;
 
-       case BR_REG (1):
-       case BR_REG (2):
-       case BR_REG (3):
-       case BR_REG (4):
-       case BR_REG (5):
-         if (unwind)
-           fprintf (asm_out_file, "\t.save.b 0x%x\n",
-                    1 << (src_regno - BR_REG (1)));
-         return 1;
+    case PR_REG (0):
+      gcc_assert (!current_frame_info.r[reg_save_pr]);
+      if (unwind)
+       fprintf (asm_out_file, "\t%s pr, " HOST_WIDE_INT_PRINT_DEC "\n",
+                saveop, off);
+      break;
 
-       case FR_REG (2):
-       case FR_REG (3):
-       case FR_REG (4):
-       case FR_REG (5):
-         if (unwind)
-           fprintf (asm_out_file, "\t.save.f 0x%x\n",
-                    1 << (src_regno - FR_REG (2)));
-         return 1;
+    case AR_LC_REGNUM:
+      gcc_assert (!current_frame_info.r[reg_save_ar_lc]);
+      if (unwind)
+       fprintf (asm_out_file, "\t%s ar.lc, " HOST_WIDE_INT_PRINT_DEC "\n",
+                saveop, off);
+      break;
 
-       case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19):
-       case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23):
-       case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27):
-       case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31):
-         if (unwind)
-           fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n",
-                    1 << (src_regno - FR_REG (12)));
-         return 1;
+    case AR_PFS_REGNUM:
+      gcc_assert (!current_frame_info.r[reg_save_ar_pfs]);
+      if (unwind)
+       fprintf (asm_out_file, "\t%s ar.pfs, " HOST_WIDE_INT_PRINT_DEC "\n",
+                saveop, off);
+      break;
 
-       default:
-         return 0;
-       }
-    }
+    case AR_UNAT_REGNUM:
+      gcc_assert (!current_frame_info.r[reg_save_ar_unat]);
+      if (unwind)
+       fprintf (asm_out_file, "\t%s ar.unat, " HOST_WIDE_INT_PRINT_DEC "\n",
+                saveop, off);
+      break;
 
-  return 0;
-}
+    case GR_REG (4):
+    case GR_REG (5):
+    case GR_REG (6):
+    case GR_REG (7):
+      if (unwind)
+       fprintf (asm_out_file, "\t.save.g 0x%x\n",
+                1 << (src_regno - GR_REG (4)));
+      break;
 
+    case BR_REG (1):
+    case BR_REG (2):
+    case BR_REG (3):
+    case BR_REG (4):
+    case BR_REG (5):
+      if (unwind)
+       fprintf (asm_out_file, "\t.save.b 0x%x\n",
+                1 << (src_regno - BR_REG (1)));
+      break;
+
+    case FR_REG (2):
+    case FR_REG (3):
+    case FR_REG (4):
+    case FR_REG (5):
+      if (unwind)
+       fprintf (asm_out_file, "\t.save.f 0x%x\n",
+                1 << (src_regno - FR_REG (2)));
+      break;
+
+    case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19):
+    case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23):
+    case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27):
+    case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31):
+      if (unwind)
+       fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n",
+                1 << (src_regno - FR_REG (12)));
+      break;
+
+    default:
+      /* ??? For some reason we mark other general registers, even those
+        we can't represent in the unwind info.  Ignore them.  */
+      break;
+    }
+}
 
 /* This function looks at a single insn and emits any directives
    required to unwind this insn.  */
-void
-process_for_unwind_directive (FILE *asm_out_file, rtx insn)
+
+static void
+ia64_asm_unwind_emit (FILE *asm_out_file, rtx insn)
 {
-  bool unwind = (flag_unwind_tables
-                || (flag_exceptions && !USING_SJLJ_EXCEPTIONS));
+  bool unwind = ia64_except_unwind_info (&global_options) == UI_TARGET;
   bool frame = dwarf2out_do_frame ();
+  rtx note, pat;
+  bool handled_one;
 
-  if (unwind || frame)
+  if (!unwind && !frame)
+    return;
+
+  if (NOTE_INSN_BASIC_BLOCK_P (insn))
     {
-      rtx pat;
+      last_block = NOTE_BASIC_BLOCK (insn)->next_bb == EXIT_BLOCK_PTR;
 
-      if (NOTE_INSN_BASIC_BLOCK_P (insn))
+      /* Restore unwind state from immediately before the epilogue.  */
+      if (need_copy_state)
        {
-         last_block = NOTE_BASIC_BLOCK (insn)->next_bb == EXIT_BLOCK_PTR;
-
-         /* Restore unwind state from immediately before the epilogue.  */
-         if (need_copy_state)
+         if (unwind)
            {
-             if (unwind)
-               {
-                 fprintf (asm_out_file, "\t.body\n");
-                 fprintf (asm_out_file, "\t.copy_state %d\n",
-                          cfun->machine->state_num);
-               }
-             if (IA64_CHANGE_CFA_IN_EPILOGUE && frame)
-               ia64_dwarf2out_def_steady_cfa (insn);
-             need_copy_state = false;
+             fprintf (asm_out_file, "\t.body\n");
+             fprintf (asm_out_file, "\t.copy_state %d\n",
+                      cfun->machine->state_num);
            }
+         need_copy_state = false;
        }
+    }
 
-      if (GET_CODE (insn) == NOTE || ! RTX_FRAME_RELATED_P (insn))
-       return;
+  if (GET_CODE (insn) == NOTE || ! RTX_FRAME_RELATED_P (insn))
+    return;
 
-      pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
-      if (pat)
-       pat = XEXP (pat, 0);
+  /* Look for the ALLOC insn.  */
+  if (INSN_CODE (insn) == CODE_FOR_alloc)
+    {
+      rtx dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+      int dest_regno = REGNO (dest);
+
+      /* If this is the final destination for ar.pfs, then this must
+        be the alloc in the prologue.  */
+      if (dest_regno == current_frame_info.r[reg_save_ar_pfs])
+       {
+         if (unwind)
+           fprintf (asm_out_file, "\t.save ar.pfs, r%d\n",
+                    ia64_dbx_register_number (dest_regno));
+       }
       else
-       pat = PATTERN (insn);
+       {
+         /* This must be an alloc before a sibcall.  We must drop the
+            old frame info.  The easiest way to drop the old frame
+            info is to ensure we had a ".restore sp" directive
+            followed by a new prologue.  If the procedure doesn't
+            have a memory-stack frame, we'll issue a dummy ".restore
+            sp" now.  */
+         if (current_frame_info.total_size == 0 && !frame_pointer_needed)
+           /* if haven't done process_epilogue() yet, do it now */
+           process_epilogue (asm_out_file, insn, unwind, frame);
+         if (unwind)
+           fprintf (asm_out_file, "\t.prologue\n");
+       }
+      return;
+    }
 
-      switch (GET_CODE (pat))
-        {
-       case SET:
-         process_set (asm_out_file, pat, insn, unwind, frame);
-         break;
+  handled_one = false;
+  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+    switch (REG_NOTE_KIND (note))
+      {
+      case REG_CFA_ADJUST_CFA:
+       pat = XEXP (note, 0);
+       if (pat == NULL)
+         pat = PATTERN (insn);
+       process_cfa_adjust_cfa (asm_out_file, pat, insn, unwind, frame);
+       handled_one = true;
+       break;
 
-       case PARALLEL:
-         {
-           int par_index;
-           int limit = XVECLEN (pat, 0);
-           for (par_index = 0; par_index < limit; par_index++)
-             {
-               rtx x = XVECEXP (pat, 0, par_index);
-               if (GET_CODE (x) == SET)
-                 process_set (asm_out_file, x, insn, unwind, frame);
-             }
-           break;
-         }
+      case REG_CFA_OFFSET:
+       pat = XEXP (note, 0);
+       if (pat == NULL)
+         pat = PATTERN (insn);
+       process_cfa_offset (asm_out_file, pat, unwind);
+       handled_one = true;
+       break;
 
-       default:
-         gcc_unreachable ();
-       }
-    }
+      case REG_CFA_REGISTER:
+       pat = XEXP (note, 0);
+       if (pat == NULL)
+         pat = PATTERN (insn);
+       process_cfa_register (asm_out_file, pat, unwind);
+       handled_one = true;
+       break;
+
+      case REG_FRAME_RELATED_EXPR:
+      case REG_CFA_DEF_CFA:
+      case REG_CFA_EXPRESSION:
+      case REG_CFA_RESTORE:
+      case REG_CFA_SET_VDRAP:
+       /* Not used in the ia64 port.  */
+       gcc_unreachable ();
+
+      default:
+       /* Not a frame-related note.  */
+       break;
+      }
+
+  /* All REG_FRAME_RELATED_P insns, besides ALLOC, are marked with the
+     explicit action to take.  No guessing required.  */
+  gcc_assert (handled_one);
 }
 
+/* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY.  */
+
+static void
+ia64_asm_emit_except_personality (rtx personality)
+{
+  fputs ("\t.personality\t", asm_out_file);
+  output_addr_const (asm_out_file, personality);
+  fputc ('\n', asm_out_file);
+}
+
+/* Implement TARGET_ASM_INITIALIZE_SECTIONS.  */
+
+static void
+ia64_asm_init_sections (void)
+{
+  exception_section = get_unnamed_section (0, output_section_asm_op,
+                                          "\t.handlerdata");
+}
+
+/* Implement TARGET_DEBUG_UNWIND_INFO.  */
+
+static enum unwind_info_type
+ia64_debug_unwind_info (void)
+{
+  return UI_TARGET;
+}
 \f
 enum ia64_builtins
 {
@@ -9773,14 +10156,18 @@ enum ia64_builtins
   IA64_BUILTIN_FABSQ,
   IA64_BUILTIN_FLUSHRS,
   IA64_BUILTIN_INFQ,
-  IA64_BUILTIN_HUGE_VALQ
+  IA64_BUILTIN_HUGE_VALQ,
+  IA64_BUILTIN_max
 };
 
+static GTY(()) tree ia64_builtins[(int) IA64_BUILTIN_max];
+
 void
 ia64_init_builtins (void)
 {
   tree fpreg_type;
   tree float80_type;
+  tree decl;
 
   /* The __fpreg type.  */
   fpreg_type = make_node (REAL_TYPE);
@@ -9797,7 +10184,7 @@ ia64_init_builtins (void)
   /* The __float128 type.  */
   if (!TARGET_HPUX)
     {
-      tree ftype, decl;
+      tree ftype;
       tree float128_type = make_node (REAL_TYPE);
 
       TYPE_PRECISION (float128_type) = 128;
@@ -9805,14 +10192,16 @@ ia64_init_builtins (void)
       (*lang_hooks.types.register_builtin_type) (float128_type, "__float128");
 
       /* TFmode support builtins.  */
-      ftype = build_function_type (float128_type, void_list_node);
-      add_builtin_function ("__builtin_infq", ftype,
-                           IA64_BUILTIN_INFQ, BUILT_IN_MD,
-                           NULL, NULL_TREE);
+      ftype = build_function_type_list (float128_type, NULL_TREE);
+      decl = add_builtin_function ("__builtin_infq", ftype,
+                                  IA64_BUILTIN_INFQ, BUILT_IN_MD,
+                                  NULL, NULL_TREE);
+      ia64_builtins[IA64_BUILTIN_INFQ] = decl;
 
-      add_builtin_function ("__builtin_huge_valq", ftype,
-                           IA64_BUILTIN_HUGE_VALQ, BUILT_IN_MD,
-                           NULL, NULL_TREE);
+      decl = add_builtin_function ("__builtin_huge_valq", ftype,
+                                  IA64_BUILTIN_HUGE_VALQ, BUILT_IN_MD,
+                                  NULL, NULL_TREE);
+      ia64_builtins[IA64_BUILTIN_HUGE_VALQ] = decl;
 
       ftype = build_function_type_list (float128_type,
                                        float128_type,
@@ -9821,6 +10210,7 @@ ia64_init_builtins (void)
                                   IA64_BUILTIN_FABSQ, BUILT_IN_MD,
                                   "__fabstf2", NULL_TREE);
       TREE_READONLY (decl) = 1;
+      ia64_builtins[IA64_BUILTIN_FABSQ] = decl;
 
       ftype = build_function_type_list (float128_type,
                                        float128_type,
@@ -9830,37 +10220,42 @@ ia64_init_builtins (void)
                                   IA64_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
                                   "__copysigntf3", NULL_TREE);
       TREE_READONLY (decl) = 1;
+      ia64_builtins[IA64_BUILTIN_COPYSIGNQ] = decl;
     }
   else
     /* Under HPUX, this is a synonym for "long double".  */
     (*lang_hooks.types.register_builtin_type) (long_double_type_node,
                                               "__float128");
 
+  /* Fwrite on VMS is non-standard.  */
+#if TARGET_ABI_OPEN_VMS
+  vms_patch_builtins ();
+#endif
+
 #define def_builtin(name, type, code)                                  \
   add_builtin_function ((name), (type), (code), BUILT_IN_MD,   \
                       NULL, NULL_TREE)
 
-  def_builtin ("__builtin_ia64_bsp",
-              build_function_type (ptr_type_node, void_list_node),
-              IA64_BUILTIN_BSP);
+  decl = def_builtin ("__builtin_ia64_bsp",
+                     build_function_type_list (ptr_type_node, NULL_TREE),
+                     IA64_BUILTIN_BSP);
+  ia64_builtins[IA64_BUILTIN_BSP] = decl;
 
-  def_builtin ("__builtin_ia64_flushrs",
-              build_function_type (void_type_node, void_list_node),
-              IA64_BUILTIN_FLUSHRS);
+  decl = def_builtin ("__builtin_ia64_flushrs",
+                     build_function_type_list (void_type_node, NULL_TREE),
+                     IA64_BUILTIN_FLUSHRS);
+  ia64_builtins[IA64_BUILTIN_FLUSHRS] = decl;
 
 #undef def_builtin
 
   if (TARGET_HPUX)
     {
-      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");
-      if (built_in_decls [BUILT_IN_FINITEL])
-       set_user_assembler_name (built_in_decls [BUILT_IN_FINITEL],
-         "_Isfinitef128");
+      if ((decl = builtin_decl_explicit (BUILT_IN_FINITE)) != NULL_TREE)
+       set_user_assembler_name (decl, "_Isfinite");
+      if ((decl = builtin_decl_explicit (BUILT_IN_FINITEF)) != NULL_TREE)
+       set_user_assembler_name (decl, "_Isfinitef");
+      if ((decl = builtin_decl_explicit (BUILT_IN_FINITEL)) != NULL_TREE)
+       set_user_assembler_name (decl, "_Isfinitef128");
     }
 }
 
@@ -9890,16 +10285,17 @@ ia64_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
     case IA64_BUILTIN_INFQ:
     case IA64_BUILTIN_HUGE_VALQ:
       {
+        enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
        REAL_VALUE_TYPE inf;
        rtx tmp;
 
        real_inf (&inf);
-       tmp = CONST_DOUBLE_FROM_REAL_VALUE (inf, mode);
+       tmp = CONST_DOUBLE_FROM_REAL_VALUE (inf, target_mode);
 
-       tmp = validize_mem (force_const_mem (mode, tmp));
+       tmp = validize_mem (force_const_mem (target_mode, tmp));
 
        if (target == 0)
-         target = gen_reg_rtx (mode);
+         target = gen_reg_rtx (target_mode);
 
        emit_move_insn (target, tmp);
        return target;
@@ -9916,6 +10312,17 @@ ia64_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   return NULL_RTX;
 }
 
+/* Return the ia64 builtin for CODE.  */
+
+static tree
+ia64_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
+{
+  if (code >= IA64_BUILTIN_max)
+    return error_mark_node;
+
+  return ia64_builtins[code];
+}
+
 /* For the HP-UX IA64 aggregate parameters are passed stored in the
    most significant bits of the stack slot.  */
 
@@ -10050,6 +10457,11 @@ ia64_vms_init_libfuncs (void)
   set_optab_libfunc (smod_optab, DImode, "OTS$REM_L");
   set_optab_libfunc (umod_optab, SImode, "OTS$REM_UI");
   set_optab_libfunc (umod_optab, DImode, "OTS$REM_UL");
+  abort_libfunc = init_one_libfunc ("decc$abort");
+  memcmp_libfunc = init_one_libfunc ("decc$memcmp");
+#ifdef MEM_LIBFUNCS_INIT
+  MEM_LIBFUNCS_INIT;
+#endif
 }
 
 /* Rename the TFmode libfuncs available from soft-fp in glibc using
@@ -10080,6 +10492,12 @@ static void
 ia64_soft_fp_init_libfuncs (void)
 {
 }
+
+static bool
+ia64_vms_valid_pointer_mode (enum machine_mode mode)
+{
+  return (mode == SImode || mode == DImode);
+}
 \f
 /* For HPUX, it is illegal to have relocations in shared segments.  */
 
@@ -10129,6 +10547,12 @@ ia64_section_type_flags (tree decl, const char *name, int reloc)
       || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
     flags = SECTION_SMALL;
 
+#if TARGET_ABI_OPEN_VMS
+  if (decl && DECL_ATTRIBUTES (decl)
+      && lookup_attribute ("common_object", DECL_ATTRIBUTES (decl)))
+    flags |= SECTION_VMS_OVERLAY;
+#endif
+
   flags |= default_section_type_flags (decl, name, reloc);
   return flags;
 }
@@ -10294,7 +10718,6 @@ ia64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
   final_start_function (insn, file, 1);
   final (insn, file, 1);
   final_end_function ();
-  free_after_compilation (cfun);
 
   reload_completed = 0;
   epilogue_completed = 0;
@@ -10306,7 +10729,8 @@ static rtx
 ia64_struct_value_rtx (tree fntype,
                       int incoming ATTRIBUTE_UNUSED)
 {
-  if (fntype && ia64_struct_retval_addr_is_first_parm_p (fntype))
+  if (TARGET_ABI_OPEN_VMS ||
+      (fntype && ia64_struct_retval_addr_is_first_parm_p (fntype)))
     return NULL_RTX;
   return gen_rtx_REG (Pmode, GR_REG (8));
 }
@@ -10442,7 +10866,7 @@ ia64_profile_hook (int labelno)
       char buf[30];
       const char *label_name;
       ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
-      label_name = (*targetm.strip_name_encoding) (ggc_strdup (buf));
+      label_name = ggc_strdup ((*targetm.strip_name_encoding) (buf));
       label = gen_rtx_SYMBOL_REF (Pmode, label_name);
       SYMBOL_REF_FLAGS (label) = SYMBOL_FLAG_LOCAL;
     }
@@ -10520,21 +10944,6 @@ ia64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1, const_tree ty
   return NULL;
 }
 
-/* Implement overriding of the optimization options.  */
-void
-ia64_optimization_options (int level ATTRIBUTE_UNUSED,
-                           int size ATTRIBUTE_UNUSED)
-{
-  /* Let the scheduler form additional regions.  */
-  set_param_value ("max-sched-extend-regions-iters", 2);
-
-  /* Set the default values for cache-related parameters.  */
-  set_param_value ("simultaneous-prefetches", 6);
-  set_param_value ("l1-cache-line-size", 32);
-
-  set_param_value("sched-mem-true-dep-cost", 4);
-}
-
 /* HP-UX version_id attribute.
    For object foo, if the version_id is set to 1234 put out an alias
    of '.alias foo "foo{1234}"  We can't use "foo{1234}" in anything
@@ -10571,4 +10980,609 @@ ia64_c_mode_for_suffix (char suffix)
   return VOIDmode;
 }
 
+static GTY(()) rtx ia64_dconst_0_5_rtx;
+
+rtx
+ia64_dconst_0_5 (void)
+{
+  if (! ia64_dconst_0_5_rtx)
+    {
+      REAL_VALUE_TYPE rv;
+      real_from_string (&rv, "0.5");
+      ia64_dconst_0_5_rtx = const_double_from_real_value (rv, DFmode);
+    }
+  return ia64_dconst_0_5_rtx;
+}
+
+static GTY(()) rtx ia64_dconst_0_375_rtx;
+
+rtx
+ia64_dconst_0_375 (void)
+{
+  if (! ia64_dconst_0_375_rtx)
+    {
+      REAL_VALUE_TYPE rv;
+      real_from_string (&rv, "0.375");
+      ia64_dconst_0_375_rtx = const_double_from_real_value (rv, DFmode);
+    }
+  return ia64_dconst_0_375_rtx;
+}
+
+static enum machine_mode
+ia64_get_reg_raw_mode (int regno)
+{
+  if (FR_REGNO_P (regno))
+    return XFmode;
+  return default_get_reg_raw_mode(regno);
+}
+
+/* Always default to .text section until HP-UX linker is fixed.  */
+
+ATTRIBUTE_UNUSED static section *
+ia64_hpux_function_section (tree decl ATTRIBUTE_UNUSED,
+                           enum node_frequency freq ATTRIBUTE_UNUSED,
+                           bool startup ATTRIBUTE_UNUSED,
+                           bool exit ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+\f
+/* Construct (set target (vec_select op0 (parallel perm))) and
+   return true if that's a valid instruction in the active ISA.  */
+
+static bool
+expand_vselect (rtx target, rtx op0, const unsigned char *perm, unsigned nelt)
+{
+  rtx rperm[MAX_VECT_LEN], x;
+  unsigned i;
+
+  for (i = 0; i < nelt; ++i)
+    rperm[i] = GEN_INT (perm[i]);
+
+  x = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelt, rperm));
+  x = gen_rtx_VEC_SELECT (GET_MODE (target), op0, x);
+  x = gen_rtx_SET (VOIDmode, target, x);
+
+  x = emit_insn (x);
+  if (recog_memoized (x) < 0)
+    {
+      remove_insn (x);
+      return false;
+    }
+  return true;
+}
+
+/* Similar, but generate a vec_concat from op0 and op1 as well.  */
+
+static bool
+expand_vselect_vconcat (rtx target, rtx op0, rtx op1,
+                       const unsigned char *perm, unsigned nelt)
+{
+  enum machine_mode v2mode;
+  rtx x;
+
+  v2mode = GET_MODE_2XWIDER_MODE (GET_MODE (op0));
+  x = gen_rtx_VEC_CONCAT (v2mode, op0, op1);
+  return expand_vselect (target, x, perm, nelt);
+}
+
+/* Try to expand a no-op permutation.  */
+
+static bool
+expand_vec_perm_identity (struct expand_vec_perm_d *d)
+{
+  unsigned i, nelt = d->nelt;
+
+  for (i = 0; i < nelt; ++i)
+    if (d->perm[i] != i)
+      return false;
+
+  if (!d->testing_p)
+    emit_move_insn (d->target, d->op0);
+
+  return true;
+}
+
+/* Try to expand D via a shrp instruction.  */
+
+static bool
+expand_vec_perm_shrp (struct expand_vec_perm_d *d)
+{
+  unsigned i, nelt = d->nelt, shift, mask;
+  rtx tmp, hi, lo;
+
+  /* ??? Don't force V2SFmode into the integer registers.  */
+  if (d->vmode == V2SFmode)
+    return false;
+
+  mask = (d->one_operand_p ? nelt - 1 : 2 * nelt - 1);
+
+  shift = d->perm[0];
+  if (BYTES_BIG_ENDIAN && shift > nelt)
+    return false;
+
+  for (i = 1; i < nelt; ++i)
+    if (d->perm[i] != ((shift + i) & mask))
+      return false;
+
+  if (d->testing_p)
+    return true;
+
+  hi = shift < nelt ? d->op1 : d->op0;
+  lo = shift < nelt ? d->op0 : d->op1;
+
+  shift %= nelt;
+
+  shift *= GET_MODE_UNIT_SIZE (d->vmode) * BITS_PER_UNIT;
+
+  /* We've eliminated the shift 0 case via expand_vec_perm_identity.  */
+  gcc_assert (IN_RANGE (shift, 1, 63));
+
+  /* Recall that big-endian elements are numbered starting at the top of
+     the register.  Ideally we'd have a shift-left-pair.  But since we
+     don't, convert to a shift the other direction.  */
+  if (BYTES_BIG_ENDIAN)
+    shift = 64 - shift;
+
+  tmp = gen_reg_rtx (DImode);
+  hi = gen_lowpart (DImode, hi);
+  lo = gen_lowpart (DImode, lo);
+  emit_insn (gen_shrp (tmp, hi, lo, GEN_INT (shift)));
+
+  emit_move_insn (d->target, gen_lowpart (d->vmode, tmp));
+  return true;
+}
+
+/* Try to instantiate D in a single instruction.  */
+
+static bool
+expand_vec_perm_1 (struct expand_vec_perm_d *d)
+{     
+  unsigned i, nelt = d->nelt;
+  unsigned char perm2[MAX_VECT_LEN];
+
+  /* Try single-operand selections.  */
+  if (d->one_operand_p)
+    {
+      if (expand_vec_perm_identity (d))
+       return true;
+      if (expand_vselect (d->target, d->op0, d->perm, nelt))
+       return true;
+    }
+
+  /* Try two operand selections.  */
+  if (expand_vselect_vconcat (d->target, d->op0, d->op1, d->perm, nelt))
+    return true;
+
+  /* Recognize interleave style patterns with reversed operands.  */
+  if (!d->one_operand_p)
+    {
+      for (i = 0; i < nelt; ++i)
+       {
+         unsigned e = d->perm[i];
+         if (e >= nelt)
+           e -= nelt;
+         else
+           e += nelt;
+         perm2[i] = e;
+       }
+
+      if (expand_vselect_vconcat (d->target, d->op1, d->op0, perm2, nelt))
+       return true;
+    }
+
+  if (expand_vec_perm_shrp (d))
+    return true;
+
+  /* ??? Look for deposit-like permutations where most of the result 
+     comes from one vector unchanged and the rest comes from a 
+     sequential hunk of the other vector.  */
+
+  return false;
+}
+
+/* Pattern match broadcast permutations.  */
+
+static bool
+expand_vec_perm_broadcast (struct expand_vec_perm_d *d)
+{
+  unsigned i, elt, nelt = d->nelt;
+  unsigned char perm2[2];
+  rtx temp;
+  bool ok;
+
+  if (!d->one_operand_p)
+    return false;
+
+  elt = d->perm[0];
+  for (i = 1; i < nelt; ++i)
+    if (d->perm[i] != elt)
+      return false;
+
+  switch (d->vmode)
+    {
+    case V2SImode:
+    case V2SFmode:
+      /* Implementable by interleave.  */
+      perm2[0] = elt;
+      perm2[1] = elt + 2;
+      ok = expand_vselect_vconcat (d->target, d->op0, d->op0, perm2, 2);
+      gcc_assert (ok);
+      break;
+
+    case V8QImode:
+      /* Implementable by extract + broadcast.  */
+      if (BYTES_BIG_ENDIAN)
+       elt = 7 - elt;
+      elt *= BITS_PER_UNIT;
+      temp = gen_reg_rtx (DImode);
+      emit_insn (gen_extzv (temp, gen_lowpart (DImode, d->op0),
+                           GEN_INT (8), GEN_INT (elt)));
+      emit_insn (gen_mux1_brcst_qi (d->target, gen_lowpart (QImode, temp)));
+      break;
+
+    case V4HImode:
+      /* Should have been matched directly by vec_select.  */
+    default:
+      gcc_unreachable ();
+    }
+
+  return true;
+}
+
+/* A subroutine of ia64_expand_vec_perm_const_1.  Try to simplify a
+   two vector permutation into a single vector permutation by using
+   an interleave operation to merge the vectors.  */
+
+static bool
+expand_vec_perm_interleave_2 (struct expand_vec_perm_d *d)
+{
+  struct expand_vec_perm_d dremap, dfinal;
+  unsigned char remap[2 * MAX_VECT_LEN];
+  unsigned contents, i, nelt, nelt2;
+  unsigned h0, h1, h2, h3;
+  rtx seq;
+  bool ok;
+
+  if (d->one_operand_p)
+    return false;
+
+  nelt = d->nelt;
+  nelt2 = nelt / 2;
+
+  /* Examine from whence the elements come.  */
+  contents = 0;
+  for (i = 0; i < nelt; ++i)
+    contents |= 1u << d->perm[i];
+
+  memset (remap, 0xff, sizeof (remap));
+  dremap = *d;
+
+  h0 = (1u << nelt2) - 1;
+  h1 = h0 << nelt2;
+  h2 = h0 << nelt;
+  h3 = h0 << (nelt + nelt2);
+  
+  if ((contents & (h0 | h2)) == contents)      /* punpck even halves */
+    {
+      for (i = 0; i < nelt; ++i)
+       {
+         unsigned which = i / 2 + (i & 1 ? nelt : 0);
+         remap[which] = i;
+         dremap.perm[i] = which;
+       }
+    }
+  else if ((contents & (h1 | h3)) == contents) /* punpck odd halves */
+    {
+      for (i = 0; i < nelt; ++i)
+       {
+         unsigned which = i / 2 + nelt2 + (i & 1 ? nelt : 0);
+         remap[which] = i;
+         dremap.perm[i] = which;
+       }
+    }
+  else if ((contents & 0x5555) == contents)    /* mix even elements */
+    {
+      for (i = 0; i < nelt; ++i)
+       {
+         unsigned which = (i & ~1) + (i & 1 ? nelt : 0);
+         remap[which] = i;
+         dremap.perm[i] = which;
+       }
+    }
+  else if ((contents & 0xaaaa) == contents)    /* mix odd elements */
+    {
+      for (i = 0; i < nelt; ++i)
+       {
+         unsigned which = (i | 1) + (i & 1 ? nelt : 0);
+         remap[which] = i;
+         dremap.perm[i] = which;
+       }
+    }
+  else if (floor_log2 (contents) - ctz_hwi (contents) < (int)nelt) /* shrp */
+    {
+      unsigned shift = ctz_hwi (contents);
+      for (i = 0; i < nelt; ++i)
+       {
+         unsigned which = (i + shift) & (2 * nelt - 1);
+         remap[which] = i;
+         dremap.perm[i] = which;
+       }
+    }
+  else
+    return false;
+
+  /* Use the remapping array set up above to move the elements from their
+     swizzled locations into their final destinations.  */
+  dfinal = *d;
+  for (i = 0; i < nelt; ++i)
+    {
+      unsigned e = remap[d->perm[i]];
+      gcc_assert (e < nelt);
+      dfinal.perm[i] = e;
+    }
+  dfinal.op0 = gen_reg_rtx (dfinal.vmode);
+  dfinal.op1 = dfinal.op0;
+  dfinal.one_operand_p = true;
+  dremap.target = dfinal.op0;
+
+  /* Test if the final remap can be done with a single insn.  For V4HImode
+     this *will* succeed.  For V8QImode or V2SImode it may not.  */
+  start_sequence ();
+  ok = expand_vec_perm_1 (&dfinal);
+  seq = get_insns ();
+  end_sequence ();
+  if (!ok)
+    return false;
+  if (d->testing_p)
+    return true;
+
+  ok = expand_vec_perm_1 (&dremap);
+  gcc_assert (ok);
+
+  emit_insn (seq);
+  return true;
+}
+
+/* A subroutine of ia64_expand_vec_perm_const_1.  Emit a full V4HImode
+   constant permutation via two mux2 and a merge.  */
+
+static bool
+expand_vec_perm_v4hi_5 (struct expand_vec_perm_d *d)
+{
+  unsigned char perm2[4];
+  rtx rmask[4];
+  unsigned i;
+  rtx t0, t1, mask, x;
+  bool ok;
+
+  if (d->vmode != V4HImode || d->one_operand_p)
+    return false;
+  if (d->testing_p)
+    return true;
+
+  for (i = 0; i < 4; ++i)
+    {
+      perm2[i] = d->perm[i] & 3;
+      rmask[i] = (d->perm[i] & 4 ? const0_rtx : constm1_rtx);
+    }
+  mask = gen_rtx_CONST_VECTOR (V4HImode, gen_rtvec_v (4, rmask));
+  mask = force_reg (V4HImode, mask);
+
+  t0 = gen_reg_rtx (V4HImode);
+  t1 = gen_reg_rtx (V4HImode);
+
+  ok = expand_vselect (t0, d->op0, perm2, 4);
+  gcc_assert (ok);
+  ok = expand_vselect (t1, d->op1, perm2, 4);
+  gcc_assert (ok);
+
+  x = gen_rtx_AND (V4HImode, mask, t0);
+  emit_insn (gen_rtx_SET (VOIDmode, t0, x));
+
+  x = gen_rtx_NOT (V4HImode, mask);
+  x = gen_rtx_AND (V4HImode, x, t1);
+  emit_insn (gen_rtx_SET (VOIDmode, t1, x));
+
+  x = gen_rtx_IOR (V4HImode, t0, t1);
+  emit_insn (gen_rtx_SET (VOIDmode, d->target, x));
+
+  return true;
+}
+
+/* The guts of ia64_expand_vec_perm_const, also used by the ok hook.
+   With all of the interface bits taken care of, perform the expansion
+   in D and return true on success.  */
+
+static bool
+ia64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
+{
+  if (expand_vec_perm_1 (d))
+    return true;
+  if (expand_vec_perm_broadcast (d))
+    return true;
+  if (expand_vec_perm_interleave_2 (d))
+    return true;
+  if (expand_vec_perm_v4hi_5 (d))
+    return true;
+  return false;
+}
+
+bool
+ia64_expand_vec_perm_const (rtx operands[4])
+{
+  struct expand_vec_perm_d d;
+  unsigned char perm[MAX_VECT_LEN];
+  int i, nelt, which;
+  rtx sel;
+
+  d.target = operands[0];
+  d.op0 = operands[1];
+  d.op1 = operands[2];
+  sel = operands[3];
+
+  d.vmode = GET_MODE (d.target);
+  gcc_assert (VECTOR_MODE_P (d.vmode));
+  d.nelt = nelt = GET_MODE_NUNITS (d.vmode);
+  d.testing_p = false;
+
+  gcc_assert (GET_CODE (sel) == CONST_VECTOR);
+  gcc_assert (XVECLEN (sel, 0) == nelt);
+  gcc_checking_assert (sizeof (d.perm) == sizeof (perm));
+
+  for (i = which = 0; i < nelt; ++i)
+    {
+      rtx e = XVECEXP (sel, 0, i);
+      int ei = INTVAL (e) & (2 * nelt - 1);
+
+      which |= (ei < nelt ? 1 : 2);
+      d.perm[i] = ei;
+      perm[i] = ei;
+    }
+
+  switch (which)
+    {
+    default:
+      gcc_unreachable();
+
+    case 3:
+      if (!rtx_equal_p (d.op0, d.op1))
+       {
+         d.one_operand_p = false;
+         break;
+       }
+
+      /* The elements of PERM do not suggest that only the first operand
+        is used, but both operands are identical.  Allow easier matching
+        of the permutation by folding the permutation into the single
+        input vector.  */
+      for (i = 0; i < nelt; ++i)
+       if (d.perm[i] >= nelt)
+         d.perm[i] -= nelt;
+      /* FALLTHRU */
+
+    case 1:
+      d.op1 = d.op0;
+      d.one_operand_p = true;
+      break;
+
+    case 2:
+      for (i = 0; i < nelt; ++i)
+        d.perm[i] -= nelt;
+      d.op0 = d.op1;
+      d.one_operand_p = true;
+      break;
+    }
+
+  if (ia64_expand_vec_perm_const_1 (&d))
+    return true;
+
+  /* If the mask says both arguments are needed, but they are the same,
+     the above tried to expand with one_operand_p true.  If that didn't
+     work, retry with one_operand_p false, as that's what we used in _ok.  */
+  if (which == 3 && d.one_operand_p)
+    {
+      memcpy (d.perm, perm, sizeof (perm));
+      d.one_operand_p = false;
+      return ia64_expand_vec_perm_const_1 (&d);
+    }
+
+  return false;
+}
+
+/* Implement targetm.vectorize.vec_perm_const_ok.  */
+
+static bool
+ia64_vectorize_vec_perm_const_ok (enum machine_mode vmode,
+                                 const unsigned char *sel)
+{
+  struct expand_vec_perm_d d;
+  unsigned int i, nelt, which;
+  bool ret;
+
+  d.vmode = vmode;
+  d.nelt = nelt = GET_MODE_NUNITS (d.vmode);
+  d.testing_p = true;
+
+  /* Extract the values from the vector CST into the permutation
+     array in D.  */
+  memcpy (d.perm, sel, nelt);
+  for (i = which = 0; i < nelt; ++i)
+    {
+      unsigned char e = d.perm[i];
+      gcc_assert (e < 2 * nelt);
+      which |= (e < nelt ? 1 : 2);
+    }
+
+  /* For all elements from second vector, fold the elements to first.  */
+  if (which == 2)
+    for (i = 0; i < nelt; ++i)
+      d.perm[i] -= nelt;
+
+  /* Check whether the mask can be applied to the vector type.  */
+  d.one_operand_p = (which != 3);
+
+  /* Otherwise we have to go through the motions and see if we can
+     figure out how to generate the requested permutation.  */
+  d.target = gen_raw_REG (d.vmode, LAST_VIRTUAL_REGISTER + 1);
+  d.op1 = d.op0 = gen_raw_REG (d.vmode, LAST_VIRTUAL_REGISTER + 2);
+  if (!d.one_operand_p)
+    d.op1 = gen_raw_REG (d.vmode, LAST_VIRTUAL_REGISTER + 3);
+
+  start_sequence ();
+  ret = ia64_expand_vec_perm_const_1 (&d);
+  end_sequence ();
+
+  return ret;
+}
+
+void
+ia64_expand_vec_setv2sf (rtx operands[3])
+{
+  struct expand_vec_perm_d d;
+  unsigned int which;
+  bool ok;
+  
+  d.target = operands[0];
+  d.op0 = operands[0];
+  d.op1 = gen_reg_rtx (V2SFmode);
+  d.vmode = V2SFmode;
+  d.nelt = 2;
+  d.one_operand_p = false;
+  d.testing_p = false;
+
+  which = INTVAL (operands[2]);
+  gcc_assert (which <= 1);
+  d.perm[0] = 1 - which;
+  d.perm[1] = which + 2;
+
+  emit_insn (gen_fpack (d.op1, operands[1], CONST0_RTX (SFmode)));
+
+  ok = ia64_expand_vec_perm_const_1 (&d);
+  gcc_assert (ok);
+}
+
+void
+ia64_expand_vec_perm_even_odd (rtx target, rtx op0, rtx op1, int odd)
+{
+  struct expand_vec_perm_d d;
+  enum machine_mode vmode = GET_MODE (target);
+  unsigned int i, nelt = GET_MODE_NUNITS (vmode);
+  bool ok;
+
+  d.target = target;
+  d.op0 = op0;
+  d.op1 = op1;
+  d.vmode = vmode;
+  d.nelt = nelt;
+  d.one_operand_p = false;
+  d.testing_p = false;
+
+  for (i = 0; i < nelt; ++i)
+    d.perm[i] = i * 2 + odd;
+
+  ok = ia64_expand_vec_perm_const_1 (&d);
+  gcc_assert (ok);
+}
+
 #include "gt-ia64.h"