Warning and partial fix for gcc -freorder-blocks-and-partition related problem.
[deliverable/binutils-gdb.git] / gas / config / tc-ia64.c
index ae445de1beb505cba04cda3f07e757f0d362e14f..cab32cd04737fae2c947838f7d98f7fd680641ae 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
-   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
@@ -17,8 +17,8 @@
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 /*
   TODO:
 
 #include "elf/ia64.h"
 
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
 #define NELEMS(a)      ((int) (sizeof (a)/sizeof ((a)[0])))
+
+/* Some systems define MIN in, e.g., param.h.  */
+#undef MIN
 #define MIN(a,b)       ((a) < (b) ? (a) : (b))
 
 #define NUM_SLOTS      4
@@ -225,6 +232,21 @@ static struct
        that are predicatable.  */
     expressionS qp;
 
+    /* Optimize for which CPU.  */
+    enum
+      {
+       itanium1,
+       itanium2
+      } tune;
+
+    /* What to do when hint.b is used.  */
+    enum
+      {
+       hint_b_error,
+       hint_b_warning,
+       hint_b_ok
+      } hint_b;
+
     unsigned int
       manual_bundling : 1,
       debug_dv: 1,
@@ -309,6 +331,21 @@ static struct
   }
 md;
 
+/* These are not const, because they are modified to MMI for non-itanium1
+   targets below.  */
+/* MFI bundle of nops.  */
+static unsigned char le_nop[16] =
+{
+  0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00
+};
+/* MFI bundle of nops with stop-bit.  */
+static unsigned char le_nop_stop[16] =
+{
+  0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00
+};
+
 /* application registers:  */
 
 #define AR_K0          0
@@ -627,7 +664,17 @@ static struct gr {
   unsigned known:1;
   int path;
   valueT value;
-} gr_values[128] = {{ 1, 0, 0 }};
+} gr_values[128] = {
+  {
+    1,
+#ifdef INT_MAX
+    INT_MAX,
+#else
+    (((1 << (8 * sizeof(gr_values->path) - 2)) - 1) << 1) + 1,
+#endif
+    0
+  }
+};
 
 /* Remember the alignment frag.  */
 static fragS *align_frag;
@@ -648,8 +695,6 @@ typedef struct unw_rec_list {
   unwind_record r;
   unsigned long slot_number;
   fragS *slot_frag;
-  unsigned long next_slot_number;
-  fragS *next_slot_frag;
   struct unw_rec_list *next;
 } unw_rec_list;
 
@@ -664,6 +709,12 @@ typedef struct label_prologue_count
   unsigned int prologue_count;
 } label_prologue_count;
 
+typedef struct proc_pending
+{
+  symbolS *sym;
+  struct proc_pending *next;
+} proc_pending;
+
 static struct
 {
   /* Maintain a list of unwind entries for the current function.  */
@@ -675,7 +726,7 @@ static struct
   unw_rec_list *current_entry;
 
   /* These are used to create the unwind table entry for this function.  */
-  symbolS *proc_start;
+  proc_pending proc_pending;
   symbolS *info;               /* pointer to unwind info */
   symbolS *personality_routine;
   segT saved_text_seg;
@@ -743,7 +794,7 @@ static void dot_byteorder PARAMS ((int));
 static void dot_psr PARAMS ((int));
 static void dot_alias PARAMS ((int));
 static void dot_ln PARAMS ((int));
-static char *parse_section_name PARAMS ((void));
+static void cross_section PARAMS ((int ref, void (*cons) PARAMS((int)), int ua));
 static void dot_xdata PARAMS ((int));
 static void stmt_float_cons PARAMS ((int));
 static void stmt_cons_ua PARAMS ((int));
@@ -1130,7 +1181,7 @@ ia64_cons_align (nbytes)
 }
 
 /* Output COUNT bytes to a memory location.  */
-static unsigned char *vbyte_mem_ptr = NULL;
+static char *vbyte_mem_ptr = NULL;
 
 void
 output_vbyte_mem (count, ptr, comment)
@@ -1307,7 +1358,7 @@ output_P4_format (f, imask, imask_size)
      unsigned long imask_size;
 {
   imask[0] = UNW_P4;
-  (*f) (imask_size, imask, NULL);
+  (*f) (imask_size, (char *) imask, NULL);
 }
 
 static void
@@ -1703,8 +1754,6 @@ alloc_record (unw_record_type t)
   ptr->next = NULL;
   ptr->slot_number = SLOT_NUM_NOT_SET;
   ptr->r.type = t;
-  ptr->next_slot_number = 0;
-  ptr->next_slot_frag = 0;
   return ptr;
 }
 
@@ -2659,6 +2708,26 @@ slot_index (slot_addr, slot_frag, first_addr, first_frag, before_relax)
       /* Move to the beginning of the next frag.  */
       first_frag = first_frag->fr_next;
       first_addr = (unsigned long) &first_frag->fr_literal;
+
+      /* This can happen if there is section switching in the middle of a
+        function, causing the frag chain for the function to be broken.  */
+      if (first_frag == NULL)
+       {
+         /* We get six warnings for one problem, because of the loop in
+            fixup_unw_records, and because fixup_unw_records is called 3
+            times: once before creating the variant frag, once to estimate
+            its size, and once to relax it.  This is unreasonable, so we use
+            a static var to make sure we only emit the warning once.  */
+         static int warned = 0;
+
+         if (!warned)
+           {
+             as_warn ("Corrupted unwind info due to unsupported section switching");
+             warned = 1;
+           }
+
+         return index;
+       }
     }
 
   /* Add in the used part of the last frag.  */
@@ -3027,17 +3096,20 @@ static void
 dot_radix (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
-  int radix;
+  char *radix;
+  int ch;
 
   SKIP_WHITESPACE ();
-  radix = *input_line_pointer++;
 
-  if (radix != 'C' && !is_end_of_line[(unsigned char) radix])
-    {
-      as_bad ("Radix `%c' unsupported", *input_line_pointer);
-      ignore_rest_of_line ();
-      return;
-    }
+  if (is_it_end_of_statement ())
+    return;
+  radix = input_line_pointer;
+  ch = get_symbol_end ();
+  ia64_canonicalize_symbol_name (radix);
+  if (strcasecmp (radix, "C"))
+    as_bad ("Radix `%s' unsupported or invalid", radix);
+  *input_line_pointer = ch;
+  demand_empty_rest_of_line ();
 }
 
 /* Helper function for .loc directives.  If the assembler is not generating
@@ -3085,7 +3157,7 @@ unwind_diagnostic (const char * region, const char *directive)
 static int
 in_procedure (const char *directive)
 {
-  if (unwind.proc_start
+  if (unwind.proc_pending.sym
       && (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
     return 1;
   return unwind_diagnostic ("procedure", directive);
@@ -3416,7 +3488,7 @@ static char *special_linkonce_name[] =
   };
 
 static void
-start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
+start_unwind_section (const segT text_seg, int sec_index)
 {
   /*
     Use a slightly ugly scheme to derive the unwind section names from
@@ -3478,8 +3550,6 @@ start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
       prefix = special_linkonce_name [sec_index - SPECIAL_SECTION_UNWIND];
       suffix += sizeof (".gnu.linkonce.t.") - 1;
     }
-  else if (linkonce_empty)
-    return;
 
   prefix_len = strlen (prefix);
   suffix_len = strlen (suffix);
@@ -3490,7 +3560,8 @@ start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
   sec_name [sec_name_len] = '\0';
 
   /* Handle COMDAT group.  */
-  if (suffix == text_name && (text_seg->flags & SEC_LINK_ONCE) != 0)
+  if ((text_seg->flags & SEC_LINK_ONCE) != 0
+      && (elf_section_flags (text_seg) & SHF_GROUP) != 0)
     {
       char *section;
       size_t len, group_name_len;
@@ -3567,7 +3638,7 @@ generate_unwind_image (const segT text_seg)
       expressionS exp;
       bfd_reloc_code_real_type reloc;
 
-      start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 0);
+      start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO);
 
       /* Make sure the section has 4 byte alignment for ILP32 and
         8 byte alignment for LP64.  */
@@ -3608,8 +3679,6 @@ generate_unwind_image (const segT text_seg)
          unwind.personality_routine = 0;
        }
     }
-  else
-    start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 1);
 
   free_saved_prologue_counts ();
   unwind.list = unwind.tail = unwind.current_entry = NULL;
@@ -3895,7 +3964,8 @@ static void
 dot_spillreg (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
-  int sep, ab, xy, reg, treg;
+  int sep;
+  unsigned int ab, xy, reg, treg;
   expressionS e1, e2;
 
   if (!in_procedure ("spillreg"))
@@ -3930,7 +4000,8 @@ dot_spillmem (psprel)
      int psprel;
 {
   expressionS e1, e2;
-  int sep, ab, reg;
+  int sep;
+  unsigned int ab, reg;
 
   if (!in_procedure ("spillmem"))
     return;
@@ -3968,7 +4039,8 @@ static void
 dot_spillreg_p (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
-  int sep, ab, xy, reg, treg;
+  int sep;
+  unsigned int ab, xy, reg, treg;
   expressionS e1, e2, e3;
   unsigned int qp;
 
@@ -4019,7 +4091,8 @@ dot_spillmem_p (psprel)
      int psprel;
 {
   expressionS e1, e2, e3;
-  int sep, ab, reg;
+  int sep;
+  unsigned int ab, reg;
   unsigned int qp;
 
   if (!in_procedure ("spillmem.p"))
@@ -4221,8 +4294,22 @@ dot_proc (dummy)
 {
   char *name, *p, c;
   symbolS *sym;
+  proc_pending *pending, *last_pending;
+
+  if (unwind.proc_pending.sym)
+    {
+      (md.unwind_check == unwind_check_warning
+       ? as_warn
+       : as_bad) ("Missing .endp after previous .proc");
+      while (unwind.proc_pending.next)
+       {
+         pending = unwind.proc_pending.next;
+         unwind.proc_pending.next = pending->next;
+         free (pending);
+       }
+    }
+  last_pending = NULL;
 
-  unwind.proc_start = 0;
   /* Parse names of main and alternate entry points and mark them as
      function symbols:  */
   while (1)
@@ -4238,9 +4325,16 @@ dot_proc (dummy)
          sym = symbol_find_or_make (name);
          if (S_IS_DEFINED (sym))
            as_bad ("`%s' was already defined", name);
-         else if (unwind.proc_start == 0)
+         else if (!last_pending)
+           {
+             unwind.proc_pending.sym = sym;
+             last_pending = &unwind.proc_pending;
+           }
+         else
            {
-             unwind.proc_start = sym;
+             pending = xmalloc (sizeof (*pending));
+             pending->sym = sym;
+             last_pending = last_pending->next = pending;
            }
          symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
        }
@@ -4250,8 +4344,12 @@ dot_proc (dummy)
        break;
       ++input_line_pointer;
     }
-  if (unwind.proc_start == 0)
-    unwind.proc_start = expr_build_dot ();
+  if (!last_pending)
+    {
+      unwind.proc_pending.sym = expr_build_dot ();
+      last_pending = &unwind.proc_pending;
+    }
+  last_pending->next = NULL;
   demand_empty_rest_of_line ();
   ia64_do_align (16);
 
@@ -4339,13 +4437,11 @@ dot_endp (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
-  unsigned char *ptr;
   int bytes_per_address;
   long where;
   segT saved_seg;
   subsegT saved_subseg;
-  char *name, *default_name, *p, c;
-  symbolS *sym;
+  proc_pending *pending;
   int unwind_check = md.unwind_check;
 
   md.unwind_check = unwind_check_error;
@@ -4378,7 +4474,7 @@ dot_endp (dummy)
       subseg_set (md.last_text_seg, 0);
       proc_end = expr_build_dot ();
 
-      start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
+      start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND);
 
       /* Make sure that section has 4 byte alignment for ILP32 and
          8 byte alignment for LP64.  */
@@ -4386,7 +4482,7 @@ dot_endp (dummy)
 
       /* Need space for 3 pointers for procedure start, procedure end,
         and unwind info.  */
-      ptr = frag_more (3 * md.pointer_size);
+      memset (frag_more (3 * md.pointer_size), 0, 3 * md.pointer_size);
       where = frag_now_fix () - (3 * md.pointer_size);
       bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
 
@@ -4394,7 +4490,13 @@ dot_endp (dummy)
       e.X_op = O_pseudo_fixup;
       e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
       e.X_add_number = 0;
-      e.X_add_symbol = unwind.proc_start;
+      if (!S_IS_LOCAL (unwind.proc_pending.sym)
+         && S_IS_DEFINED (unwind.proc_pending.sym))
+       e.X_add_symbol = symbol_temp_new (S_GET_SEGMENT (unwind.proc_pending.sym),
+                                         S_GET_VALUE (unwind.proc_pending.sym),
+                                         symbol_get_frag (unwind.proc_pending.sym));
+      else
+       e.X_add_symbol = unwind.proc_pending.sym;
       ia64_cons_fix_new (frag_now, where, bytes_per_address, &e);
 
       e.X_op = O_pseudo_fixup;
@@ -4413,72 +4515,25 @@ dot_endp (dummy)
          ia64_cons_fix_new (frag_now, where + (bytes_per_address * 2),
                             bytes_per_address, &e);
        }
-      else
-       md_number_to_chars (ptr + (bytes_per_address * 2), 0,
-                           bytes_per_address);
-
     }
-  else
-    start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 1);
-
   subseg_set (saved_seg, saved_subseg);
 
-  if (unwind.proc_start)
-    default_name = (char *) S_GET_NAME (unwind.proc_start);
-  else
-    default_name = NULL;
-
-  /* Parse names of main and alternate entry points and set symbol sizes.  */
-  while (1)
+  /* Set symbol sizes.  */
+  pending = &unwind.proc_pending;
+  if (S_GET_NAME (pending->sym))
     {
-      SKIP_WHITESPACE ();
-      name = input_line_pointer;
-      c = get_symbol_end ();
-      p = input_line_pointer;
-      if (!*name)
-       {
-         if (md.unwind_check == unwind_check_warning)
-           {
-             if (default_name)
-               {
-                 as_warn ("Empty argument of .endp. Use the default name `%s'",
-                          default_name);
-                 name = default_name;
-               }
-             else
-               as_warn ("Empty argument of .endp");
-           }
-         else
-           as_bad ("Empty argument of .endp");
-       }
-      if (*name)
+      do
        {
-         sym = symbol_find (name);
-         if (!sym
-             && md.unwind_check == unwind_check_warning
-             && default_name
-             && default_name != name)
-           {
-             /* We have a bad name. Try the default one if needed.  */
-             as_warn ("`%s' was not defined within procedure. Use the default name `%s'",
-                      name, default_name);
-             name = default_name;
-             sym = symbol_find (name);
-           }
-         if (!sym || !S_IS_DEFINED (sym))
-           as_bad ("`%s' was not defined within procedure", name);
-         else if (unwind.proc_start
-             && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
-             && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size == NULL)
+         symbolS *sym = pending->sym;
+
+         if (!S_IS_DEFINED (sym))
+           as_bad ("`%s' was not defined within procedure", S_GET_NAME (sym));
+         else if (S_GET_SIZE (sym) == 0
+                  && symbol_get_obj (sym)->size == NULL)
            {
-             fragS *fr = symbol_get_frag (unwind.proc_start);
              fragS *frag = symbol_get_frag (sym);
 
-             /* Check whether the function label is at or beyond last
-                .proc directive.  */
-             while (fr && fr != frag)
-               fr = fr->fr_next;
-             if (fr)
+             if (frag)
                {
                  if (frag == frag_now && SEG_NORMAL (now_seg))
                    S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
@@ -4495,6 +4550,36 @@ dot_endp (dummy)
                    }
                }
            }
+       } while ((pending = pending->next) != NULL);
+    }
+
+  /* Parse names of main and alternate entry points.  */
+  while (1)
+    {
+      char *name, *p, c;
+
+      SKIP_WHITESPACE ();
+      name = input_line_pointer;
+      c = get_symbol_end ();
+      p = input_line_pointer;
+      if (!*name)
+       (md.unwind_check == unwind_check_warning
+        ? as_warn
+        : as_bad) ("Empty argument of .endp");
+      else
+       {
+         symbolS *sym = symbol_find (name);
+
+         for (pending = &unwind.proc_pending; pending; pending = pending->next)
+           {
+             if (sym == pending->sym)
+               {
+                 pending->sym = NULL;
+                 break;
+               }
+           }
+         if (!sym || !pending)
+           as_warn ("`%s' was not specified with previous .proc", name);
        }
       *p = c;
       SKIP_WHITESPACE ();
@@ -4503,7 +4588,21 @@ dot_endp (dummy)
       ++input_line_pointer;
     }
   demand_empty_rest_of_line ();
-  unwind.proc_start = unwind.info = 0;
+
+  /* Deliberately only checking for the main entry point here; the
+     language spec even says all arguments to .endp are ignored.  */
+  if (unwind.proc_pending.sym
+      && S_GET_NAME (unwind.proc_pending.sym)
+      && strcmp (S_GET_NAME (unwind.proc_pending.sym), FAKE_LABEL_NAME))
+    as_warn ("`%s' should be an operand to this .endp",
+            S_GET_NAME (unwind.proc_pending.sym));
+  while (unwind.proc_pending.next)
+    {
+      pending = unwind.proc_pending.next;
+      unwind.proc_pending.next = pending->next;
+      free (pending);
+    }
+  unwind.proc_pending.sym = unwind.info = NULL;
 }
 
 static void
@@ -4731,58 +4830,75 @@ dot_ln (dummy)
   demand_empty_rest_of_line ();
 }
 
-static char *
-parse_section_name ()
+static void
+cross_section (ref, cons, ua)
+     int ref;
+     void (*cons) PARAMS((int));
+     int ua;
 {
-  char *name;
-  int len;
+  char *start, *end;
+  int saved_auto_align;
+  unsigned int section_count;
 
   SKIP_WHITESPACE ();
-  if (*input_line_pointer == '"')
+  start = input_line_pointer;
+  if (*start == '"')
+    {
+      int len;
+      char *name;
+
       name = demand_copy_C_string (&len);
+      obstack_free(&notes, name);
+      if (!name)
+       {
+         ignore_rest_of_line ();
+         return;
+       }
+    }
   else
     {
-      char *start = input_line_pointer;
       char c = get_symbol_end ();
 
       if (input_line_pointer == start)
        {
          as_bad ("Missing section name");
          ignore_rest_of_line ();
-         return 0;
+         return;
        }
-      name = obstack_copy (&notes, start, input_line_pointer - start + 1);
       *input_line_pointer = c;
     }
-  if (!name)
-    {
-      ignore_rest_of_line ();
-      return 0;
-    }
+  end = input_line_pointer;
   SKIP_WHITESPACE ();
   if (*input_line_pointer != ',')
     {
       as_bad ("Comma expected after section name");
       ignore_rest_of_line ();
-      return 0;
+      return;
     }
-  ++input_line_pointer;                /* skip comma */
-  return name;
+  *end = '\0';
+  end = input_line_pointer + 1;                /* skip comma */
+  input_line_pointer = start;
+  md.keep_pending_output = 1;
+  section_count = bfd_count_sections(stdoutput);
+  obj_elf_section (0);
+  if (section_count != bfd_count_sections(stdoutput))
+    as_warn ("Creating sections with .xdataN/.xrealN/.xstringZ is deprecated.");
+  input_line_pointer = end;
+  saved_auto_align = md.auto_align;
+  if (ua)
+    md.auto_align = 0;
+  (*cons) (ref);
+  if (ua)
+    md.auto_align = saved_auto_align;
+  obj_elf_previous (0);
+  md.keep_pending_output = 0;
 }
 
 static void
 dot_xdata (size)
      int size;
 {
-  char *name = parse_section_name ();
-  if (!name)
-    return;
-
-  md.keep_pending_output = 1;
-  set_section (name);
-  cons (size);
-  obj_elf_previous (0);
-  md.keep_pending_output = 0;
+  cross_section (size, cons, 0);
 }
 
 /* Why doesn't float_cons() call md_cons_align() the way cons() does?  */
@@ -4828,66 +4944,28 @@ static void
 dot_xfloat_cons (kind)
      int kind;
 {
-  char *name = parse_section_name ();
-  if (!name)
-    return;
-
-  md.keep_pending_output = 1;
-  set_section (name);
-  stmt_float_cons (kind);
-  obj_elf_previous (0);
-  md.keep_pending_output = 0;
+  cross_section (kind, stmt_float_cons, 0);
 }
 
 static void
 dot_xstringer (zero)
      int zero;
 {
-  char *name = parse_section_name ();
-  if (!name)
-    return;
-
-  md.keep_pending_output = 1;
-  set_section (name);
-  stringer (zero);
-  obj_elf_previous (0);
-  md.keep_pending_output = 0;
+  cross_section (zero, stringer, 0);
 }
 
 static void
 dot_xdata_ua (size)
      int size;
 {
-  int saved_auto_align = md.auto_align;
-  char *name = parse_section_name ();
-  if (!name)
-    return;
-
-  md.keep_pending_output = 1;
-  set_section (name);
-  md.auto_align = 0;
-  cons (size);
-  md.auto_align = saved_auto_align;
-  obj_elf_previous (0);
-  md.keep_pending_output = 0;
+  cross_section (size, cons, 1);
 }
 
 static void
 dot_xfloat_cons_ua (kind)
      int kind;
 {
-  int saved_auto_align = md.auto_align;
-  char *name = parse_section_name ();
-  if (!name)
-    return;
-
-  md.keep_pending_output = 1;
-  set_section (name);
-  md.auto_align = 0;
-  stmt_float_cons (kind);
-  md.auto_align = saved_auto_align;
-  obj_elf_previous (0);
-  md.keep_pending_output = 0;
+  cross_section (kind, float_cons, 1);
 }
 
 /* .reg.val <regname>,value */
@@ -4913,7 +4991,7 @@ dot_reg_val (dummy)
     {
       valueT value = get_absolute_expression ();
       int regno = reg.X_add_number;
-      if (regno < REG_GR || regno > REG_GR + 128)
+      if (regno <= REG_GR || regno > REG_GR + 127)
        as_warn (_("Register value annotation ignored"));
       else
        {
@@ -5937,7 +6015,7 @@ operand_match (idesc, index, e)
        case O_symbol:
          fix = CURR_SLOT.fixup + CURR_SLOT.num_fixups;
          /* There are no external relocs for TAG13/TAG13b fields, so we
-            create a dummy reloc.  This will not live past md_apply_fix3.  */
+            create a dummy reloc.  This will not live past md_apply_fix.  */
          fix->code = BFD_RELOC_UNUSED;
          fix->code = ia64_gen_real_reloc_type (e->X_op_symbol, fix->code);
          fix->opnd = idesc->operands[index];
@@ -6012,6 +6090,8 @@ parse_operands (idesc)
 {
   int i = 0, highest_unmatched_operand, num_operands = 0, num_outputs = 0;
   int error_pos, out_of_range_pos, curr_out_of_range_pos, sep = 0;
+  int reg1, reg2;
+  char reg_class;
   enum ia64_opnd expected_operand = IA64_OPND_NIL;
   enum operand_match_result result;
   char mnemonic[129];
@@ -6193,6 +6273,127 @@ parse_operands (idesc)
        as_bad ("Operand mismatch");
       return 0;
     }
+
+  /* Check that the instruction doesn't use
+     - r0, f0, or f1 as output operands
+     - the same predicate twice as output operands
+     - r0 as address of a base update load or store
+     - the same GR as output and address of a base update load
+     - two even- or two odd-numbered FRs as output operands of a floating
+       point parallel load.
+     At most two (conflicting) output (or output-like) operands can exist,
+     (floating point parallel loads have three outputs, but the base register,
+     if updated, cannot conflict with the actual outputs).  */
+  reg2 = reg1 = -1;
+  for (i = 0; i < num_operands; ++i)
+    {
+      int regno = 0;
+
+      reg_class = 0;
+      switch (idesc->operands[i])
+       {
+       case IA64_OPND_R1:
+       case IA64_OPND_R2:
+       case IA64_OPND_R3:
+         if (i < num_outputs)
+           {
+             if (CURR_SLOT.opnd[i].X_add_number == REG_GR)
+               reg_class = 'r';
+             else if (reg1 < 0)
+               reg1 = CURR_SLOT.opnd[i].X_add_number;
+             else if (reg2 < 0)
+               reg2 = CURR_SLOT.opnd[i].X_add_number;
+           }
+         break;
+       case IA64_OPND_P1:
+       case IA64_OPND_P2:
+         if (i < num_outputs)
+           {
+             if (reg1 < 0)
+               reg1 = CURR_SLOT.opnd[i].X_add_number;
+             else if (reg2 < 0)
+               reg2 = CURR_SLOT.opnd[i].X_add_number;
+           }
+         break;
+       case IA64_OPND_F1:
+       case IA64_OPND_F2:
+       case IA64_OPND_F3:
+       case IA64_OPND_F4:
+         if (i < num_outputs)
+           {
+             if (CURR_SLOT.opnd[i].X_add_number >= REG_FR
+                 && CURR_SLOT.opnd[i].X_add_number <= REG_FR + 1)
+               {
+                 reg_class = 'f';
+                 regno = CURR_SLOT.opnd[i].X_add_number - REG_FR;
+               }
+             else if (reg1 < 0)
+               reg1 = CURR_SLOT.opnd[i].X_add_number;
+             else if (reg2 < 0)
+               reg2 = CURR_SLOT.opnd[i].X_add_number;
+           }
+         break;
+       case IA64_OPND_MR3:
+         if (idesc->flags & IA64_OPCODE_POSTINC)
+           {
+             if (CURR_SLOT.opnd[i].X_add_number == REG_GR)
+               reg_class = 'm';
+             else if (reg1 < 0)
+               reg1 = CURR_SLOT.opnd[i].X_add_number;
+             else if (reg2 < 0)
+               reg2 = CURR_SLOT.opnd[i].X_add_number;
+           }
+         break;
+       default:
+         break;
+       }
+      switch (reg_class)
+       {
+       case 0:
+         break;
+       default:
+         as_warn ("Invalid use of `%c%d' as output operand", reg_class, regno);
+         break;
+       case 'm':
+         as_warn ("Invalid use of `r%d' as base update address operand", regno);
+         break;
+       }
+    }
+  if (reg1 == reg2)
+    {
+      if (reg1 >= REG_GR && reg1 <= REG_GR + 127)
+       {
+         reg1 -= REG_GR;
+         reg_class = 'r';
+       }
+      else if (reg1 >= REG_P && reg1 <= REG_P + 63)
+       {
+         reg1 -= REG_P;
+         reg_class = 'p';
+       }
+      else if (reg1 >= REG_FR && reg1 <= REG_FR + 127)
+       {
+         reg1 -= REG_FR;
+         reg_class = 'f';
+       }
+      else
+       reg_class = 0;
+      if (reg_class)
+       as_warn ("Invalid duplicate use of `%c%d'", reg_class, reg1);
+    }
+  else if (((reg1 >= REG_FR && reg1 <= REG_FR + 31
+            && reg2 >= REG_FR && reg2 <= REG_FR + 31)
+           || (reg1 >= REG_FR + 32 && reg1 <= REG_FR + 127
+            && reg2 >= REG_FR + 32 && reg2 <= REG_FR + 127))
+          && ! ((reg1 ^ reg2) & 1))
+    as_warn ("Invalid simultaneous use of `f%d' and `f%d'",
+            reg1 - REG_FR, reg2 - REG_FR);
+  else if ((reg1 >= REG_FR && reg1 <= REG_FR + 31
+           && reg2 >= REG_FR + 32 && reg2 <= REG_FR + 127)
+          || (reg1 >= REG_FR + 32 && reg1 <= REG_FR + 127
+           && reg2 >= REG_FR && reg2 <= REG_FR + 31))
+    as_warn ("Dangerous simultaneous use of `f%d' and `f%d'",
+            reg1 - REG_FR, reg2 - REG_FR);
   return idesc;
 }
 
@@ -6203,7 +6404,8 @@ build_insn (slot, insnp)
 {
   const struct ia64_operand *odesc, *o2desc;
   struct ia64_opcode *idesc = slot->idesc;
-  bfd_signed_vma insn, val;
+  bfd_vma insn;
+  bfd_signed_vma val;
   const char *err;
   int i;
 
@@ -6330,8 +6532,7 @@ emit_one_bundle ()
   bfd_vma insn[3] = { -1, -1, -1 };
   struct ia64_opcode *idesc;
   int end_of_insn_group = 0, user_template = -1;
-  int n, i, j, first, curr;
-  unw_rec_list *ptr, *last_ptr, *end_ptr;
+  int n, i, j, first, curr, last_slot;
   bfd_vma t0 = 0, t1 = 0;
   struct label_fix *lfix;
   struct insn_fix *ifix;
@@ -6382,10 +6583,13 @@ emit_one_bundle ()
   curr = first;
   idesc = md.slot[curr].idesc;
   end_of_insn_group = 0;
+  last_slot = -1;
   for (i = 0; i < 3 && md.num_slots_in_use > 0; ++i)
     {
       /* If we have unwind records, we may need to update some now.  */
-      ptr = md.slot[curr].unwind_record;
+      unw_rec_list *ptr = md.slot[curr].unwind_record;
+      unw_rec_list *end_ptr = NULL;
+
       if (ptr)
        {
          /* Find the last prologue/body record in the list for the current
@@ -6395,9 +6599,11 @@ emit_one_bundle ()
             issued.  This matters because there may have been nops emitted
             meanwhile.  Any non-prologue non-body record followed by a
             prologue/body record must also refer to the current point.  */
-         last_ptr = NULL;
-         end_ptr = md.slot[(curr + 1) % NUM_SLOTS].unwind_record;
-         for (; ptr != end_ptr; ptr = ptr->next)
+         unw_rec_list *last_ptr;
+
+         for (j = 1; end_ptr == NULL && j < md.num_slots_in_use; ++j)
+           end_ptr = md.slot[(curr + j) % NUM_SLOTS].unwind_record;
+         for (last_ptr = NULL; ptr != end_ptr; ptr = ptr->next)
            if (ptr->r.type == prologue || ptr->r.type == prologue_gr
                || ptr->r.type == body)
              last_ptr = ptr;
@@ -6427,6 +6633,11 @@ emit_one_bundle ()
          break; /* Need to start a new bundle.  */
        }
 
+      /* If this instruction specifies a template, then it must be the first
+        instruction of a bundle.  */
+      if (curr != first && md.slot[curr].user_template >= 0)
+       break;
+
       if (idesc->flags & IA64_OPCODE_SLOT2)
        {
          if (manual_bundling && !manual_bundling_off)
@@ -6568,9 +6779,34 @@ emit_one_bundle ()
          enum ia64_opnd opnd1, opnd2;
 
          if ((strcmp (idesc->name, "nop") == 0)
-             || (strcmp (idesc->name, "hint") == 0)
              || (strcmp (idesc->name, "break") == 0))
            insn_unit = required_unit;
+         else if (strcmp (idesc->name, "hint") == 0)
+           {
+             insn_unit = required_unit;
+             if (required_unit == IA64_UNIT_B)
+               {
+                 switch (md.hint_b)
+                   {
+                   case hint_b_ok:
+                     break;
+                   case hint_b_warning:
+                     as_warn ("hint in B unit may be treated as nop");
+                     break;
+                   case hint_b_error:
+                     /* When manual bundling is off and there is no
+                        user template, we choose a different unit so
+                        that hint won't go into the current slot. We
+                        will fill the current bundle with nops and
+                        try to put hint into the next bundle.  */
+                     if (!manual_bundling && user_template < 0)
+                       insn_unit = IA64_UNIT_I;
+                     else
+                       as_bad ("hint in B unit can't be used");
+                     break;
+                   }
+               }
+           }
          else if (strcmp (idesc->name, "chk.s") == 0
              || strcmp (idesc->name, "mov") == 0)
            {
@@ -6617,27 +6853,7 @@ emit_one_bundle ()
        }
 
       if (insn_unit != required_unit)
-       {
-         if (required_unit == IA64_UNIT_L
-             && insn_unit == IA64_UNIT_I
-             && !(idesc->flags & IA64_OPCODE_X_IN_MLX))
-           {
-             /* we got ourselves an MLX template but the current
-                instruction isn't an X-unit, or an I-unit instruction
-                that can go into the X slot of an MLX template.  Duh.  */
-             if (md.num_slots_in_use >= NUM_SLOTS)
-               {
-                 as_bad_where (md.slot[curr].src_file,
-                               md.slot[curr].src_line,
-                               "`%s' can't go in X slot of "
-                               "MLX template", idesc->name);
-                 /* drop this insn so we don't livelock:  */
-                 --md.num_slots_in_use;
-               }
-             break;
-           }
-         continue;             /* try next slot */
-       }
+       continue;               /* Try next slot.  */
 
       if (debug_type == DEBUG_DWARF2 || md.slot[curr].loc_directive_seen)
        {
@@ -6655,7 +6871,6 @@ emit_one_bundle ()
          /* Set slot numbers for all remaining unwind records belonging to the
             current insn.  There can not be any prologue/body unwind records
             here.  */
-         end_ptr = md.slot[(curr + 1) % NUM_SLOTS].unwind_record;
          for (; ptr != end_ptr; ptr = ptr->next)
            {
              ptr->slot_number = (unsigned long) f + i;
@@ -6671,6 +6886,7 @@ emit_one_bundle ()
          ++i;
        }
       --md.num_slots_in_use;
+      last_slot = i;
 
       /* now is a good time to fix up the labels for this insn:  */
       for (lfix = md.slot[curr].label_fixups; lfix; lfix = lfix->next)
@@ -6715,10 +6931,35 @@ emit_one_bundle ()
     {
       if (md.num_slots_in_use > 0)
        {
-         as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
-                       "`%s' does not fit into %s template",
-                       idesc->name, ia64_templ_desc[template].name);
-         --md.num_slots_in_use;
+         if (last_slot >= 2)
+           as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+                         "`%s' does not fit into bundle", idesc->name);
+         else if (last_slot < 0)
+           {
+             as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+                           "`%s' does not fit into %s template",
+                           idesc->name, ia64_templ_desc[template].name);
+             /* Drop first insn so we don't livelock.  */
+             --md.num_slots_in_use;
+             know (curr == first);
+             ia64_free_opcode (md.slot[curr].idesc);
+             memset (md.slot + curr, 0, sizeof (md.slot[curr]));
+             md.slot[curr].user_template = -1;
+           }
+         else
+           {
+             const char *where;
+
+             if (template == 2)
+               where = "X slot";
+             else if (last_slot == 0)
+               where = "slots 2 or 3";
+             else
+               where = "slot 3";
+             as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+                           "`%s' can't go in %s of %s template",
+                           idesc->name, where, ia64_templ_desc[template].name);
+           }
        }
       else
        as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
@@ -6731,12 +6972,6 @@ emit_one_bundle ()
 
   number_to_chars_littleendian (f + 0, t0, 8);
   number_to_chars_littleendian (f + 8, t1, 8);
-
-  if (unwind.list)
-    {
-      unwind.list->next_slot_number = (unsigned long) f + 16;
-      unwind.list->next_slot_frag = frag_now;
-    }
 }
 
 int
@@ -6779,6 +7014,28 @@ md_parse_option (c, arg)
          else
            return 0;
        }
+      else if (strncmp (arg, "hint.b=", 7) == 0)
+       {
+         arg += 7;
+         if (strcmp (arg, "ok") == 0)
+           md.hint_b = hint_b_ok;
+         else if (strcmp (arg, "warning") == 0)
+           md.hint_b = hint_b_warning;
+         else if (strcmp (arg, "error") == 0)
+           md.hint_b = hint_b_error;
+         else
+           return 0;
+       }
+      else if (strncmp (arg, "tune=", 5) == 0)
+       {
+         arg += 5;
+         if (strcmp (arg, "itanium1") == 0)
+           md.tune = itanium1;
+         else if (strcmp (arg, "itanium2") == 0)
+           md.tune = itanium2;
+         else
+           return 0;
+       }
       else
        return 0;
       break;
@@ -6891,8 +7148,12 @@ IA-64 options:\n\
                          EF_IA_64_NOFUNCDESC_CONS_GP)\n\
   -milp32|-milp64|-mlp64|-mp64 select data model (default -mlp64)\n\
   -mle | -mbe            select little- or big-endian byte order (default -mle)\n\
+  -mtune=[itanium1|itanium2]\n\
+                         tune for a specific CPU (default -mtune=itanium2)\n\
   -munwind-check=[warning|error]\n\
                          unwind directive check (default -munwind-check=warning)\n\
+  -mhint.b=[ok|warning|error]\n\
+                         hint.b check (default -mhint.b=error)\n\
   -x | -xexplicit        turn on dependency violation checking\n\
   -xauto                 automagically remove dependency violations (default)\n\
   -xnone                 turn off dependency violation checking\n\
@@ -6936,17 +7197,37 @@ match (int templ, int type, int slot)
   return result;
 }
 
-/* Add a bit of extra goodness if a nop of type F or B would fit
-   in TEMPL at SLOT.  */
+/* For Itanium 1, add a bit of extra goodness if a nop of type F or B would fit
+   in TEMPL at SLOT.  For Itanium 2, add a bit of extra goodness if a nop of
+   type M or I would fit in TEMPL at SLOT.  */
 
 static inline int
 extra_goodness (int templ, int slot)
 {
-  if (slot == 1 && match (templ, IA64_TYPE_F, slot))
-    return 2;
-  if (slot == 2 && match (templ, IA64_TYPE_B, slot))
-    return 1;
-  return 0;
+  switch (md.tune)
+    {
+    case itanium1:
+      if (slot == 1 && match (templ, IA64_TYPE_F, slot))
+       return 2;
+      else if (slot == 2 && match (templ, IA64_TYPE_B, slot))
+       return 1;
+      else
+       return 0;
+      break;
+    case itanium2:
+      if (match (templ, IA64_TYPE_M, slot)
+         || match (templ, IA64_TYPE_I, slot))
+       /* Favor M- and I-unit NOPs.  We definitely want to avoid
+          F-unit and B-unit may cause split-issue or less-than-optimal
+          branch-prediction.  */
+       return 2;
+      else
+       return 0;
+      break;
+    default:
+      abort ();
+      return 0;
+    }
 }
 
 /* This function is called once, at assembler startup time.  It sets
@@ -7041,11 +7322,17 @@ md_begin ()
     symbol_new (".<iplt>", undefined_section, FUNC_IPLT_RELOC,
                &zero_address_frag);
 
+ if (md.tune != itanium1)
+   {
+     /* Convert MFI NOPs bundles into MMI NOPs bundles.  */
+     le_nop[0] = 0x8;
+     le_nop_stop[0] = 0x9;
+   }
+
   /* Compute the table of best templates.  We compute goodness as a
-     base 4 value, in which each match counts for 3, each F counts
-     for 2, each B counts for 1.  This should maximize the number of
-     F and B nops in the chosen bundles, which is good because these
-     pipelines are least likely to be overcommitted.  */
+     base 4 value, in which each match counts for 3.  Match-failures
+     result in NOPs and we use extra_goodness() to pick the execution
+     units that are best suited for issuing the NOP.  */
   for (i = 0; i < IA64_NUM_TYPES; ++i)
     for (j = 0; j < IA64_NUM_TYPES; ++j)
       for (k = 0; k < IA64_NUM_TYPES; ++k)
@@ -7058,7 +7345,7 @@ md_begin ()
                {
                  if (match (t, j, 1))
                    {
-                     if (match (t, k, 2))
+                     if ((t == 2 && j == IA64_TYPE_X) || match (t, k, 2))
                        goodness = 3 + 3 + 3;
                      else
                        goodness = 3 + 3 + extra_goodness (t, 2);
@@ -7074,7 +7361,7 @@ md_begin ()
                }
              else if (match (t, i, 1))
                {
-                 if (match (t, j, 2))
+                 if ((t == 2 && i == IA64_TYPE_X) || match (t, j, 2))
                    goodness = 3 + 3;
                  else
                    goodness = 3 + extra_goodness (t, 2);
@@ -7090,6 +7377,21 @@ md_begin ()
            }
        }
 
+#ifdef DEBUG_TEMPLATES
+  /* For debugging changes to the best_template calculations.  We don't care
+     about combinations with invalid instructions, so start the loops at 1.  */
+  for (i = 0; i < IA64_NUM_TYPES; ++i)
+    for (j = 0; j < IA64_NUM_TYPES; ++j)
+      for (k = 0; k < IA64_NUM_TYPES; ++k)
+       {
+         char type_letter[IA64_NUM_TYPES] = { 'n', 'a', 'i', 'm', 'b', 'f',
+                                              'x', 'd' };
+         fprintf (stderr, "%c%c%c %s\n", type_letter[i], type_letter[j],
+                  type_letter[k],
+                  ia64_templ_desc[best_template[i][j][k]].name);
+       }
+#endif
+
   for (i = 0; i < NUM_SLOTS; ++i)
     md.slot[i].user_template = -1;
 
@@ -7245,6 +7547,8 @@ ia64_init (argc, argv)
   md.detect_dv = 1;
   /* FIXME: We should change it to unwind_check_error someday.  */
   md.unwind_check = unwind_check_warning;
+  md.hint_b = hint_b_error;
+  md.tune = itanium2;
 }
 
 /* Return a string for the target object file format.  */
@@ -7598,7 +7902,6 @@ ia64_parse_name (name, e, nextcharP)
 {
   struct const_desc *cdesc;
   struct dynreg *dr = 0;
-  unsigned int regnum;
   unsigned int idx;
   struct symbol *sym;
   char *end;
@@ -7704,13 +8007,14 @@ ia64_parse_name (name, e, nextcharP)
     }
 
   /* check for inN, locN, or outN:  */
+  idx = 0;
   switch (name[0])
     {
     case 'i':
       if (name[1] == 'n' && ISDIGIT (name[2]))
        {
          dr = &md.in;
-         name += 2;
+         idx = 2;
        }
       break;
 
@@ -7718,7 +8022,7 @@ ia64_parse_name (name, e, nextcharP)
       if (name[1] == 'o' && name[2] == 'c' && ISDIGIT (name[3]))
        {
          dr = &md.loc;
-         name += 3;
+         idx = 3;
        }
       break;
 
@@ -7726,7 +8030,7 @@ ia64_parse_name (name, e, nextcharP)
       if (name[1] == 'u' && name[2] == 't' && ISDIGIT (name[3]))
        {
          dr = &md.out;
-         name += 3;
+         idx = 3;
        }
       break;
 
@@ -7734,13 +8038,16 @@ ia64_parse_name (name, e, nextcharP)
       break;
     }
 
-  if (dr)
+  /* Ignore register numbers with leading zeroes, except zero itself.  */
+  if (dr && (name[idx] != '0' || name[idx + 1] == '\0'))
     {
+      unsigned long regnum;
+
       /* The name is inN, locN, or outN; parse the register number.  */
-      regnum = strtoul (name, &end, 10);
-      if (end > name && *end == '\0')
+      regnum = strtoul (name + idx, &end, 10);
+      if (end > name + idx && *end == '\0' && regnum < 96)
        {
-         if ((unsigned) regnum >= dr->num_regs)
+         if (regnum >= dr->num_regs)
            {
              if (!dr->num_regs)
                as_bad ("No current frame");
@@ -7785,8 +8092,6 @@ ia64_canonicalize_symbol_name (name)
     {
       if (full > 0)
        as_bad ("Standalone `#' is illegal");
-      else
-       as_bad ("Zero-length symbol is illegal");
     }
   else if (len < full - 1)
     as_warn ("Redundant `#' suffix operators");
@@ -7936,9 +8241,15 @@ specify_resource (dep, idesc, type, specs, note, path)
   tmpl.qp_regno = CURR_SLOT.qp_regno;
   tmpl.link_to_qp_branch = 1;
   tmpl.mem_offset.hint = 0;
+  tmpl.mem_offset.offset = 0;
+  tmpl.mem_offset.base = 0;
   tmpl.specific = 1;
-  tmpl.index = 0;
+  tmpl.index = -1;
   tmpl.cmp_type = CMP_NONE;
+  tmpl.depind = 0;
+  tmpl.file = NULL;
+  tmpl.line = 0;
+  tmpl.path = 0;
 
 #define UNHANDLED \
 as_warn (_("Unhandled dependency %s for %s (%s), note %d"), \
@@ -9180,8 +9491,7 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
              if (idesc->operands[0] == IA64_OPND_AR3
                  && CURR_SLOT.opnd[0].X_add_number - REG_AR == AR_BSPSTORE)
                {
-                 specs[count] = tmpl;
-                 specs[count++].index = 0; /* IA64_RSE_BSPLOAD/RNATBITINDEX */
+                 specs[count++] = tmpl;
                }
            }
          else
@@ -9635,6 +9945,7 @@ note_register_values (idesc)
   else if (idesc->operands[0] == IA64_OPND_R1
           && (idesc->operands[1] == IA64_OPND_IMM22
               || idesc->operands[1] == IA64_OPND_IMMU64)
+          && CURR_SLOT.opnd[1].X_op == O_constant
           && (strcmp (idesc->name, "mov") == 0
               || strcmp (idesc->name, "movl") == 0))
     {
@@ -9652,6 +9963,30 @@ note_register_values (idesc)
            }
        }
     }
+  /* Look for dep.z imm insns.  */
+  else if (idesc->operands[0] == IA64_OPND_R1
+          && idesc->operands[1] == IA64_OPND_IMM8
+          && strcmp (idesc->name, "dep.z") == 0)
+    {
+      int regno = CURR_SLOT.opnd[0].X_add_number - REG_GR;
+      if (regno > 0 && regno < NELEMS (gr_values))
+       {
+         valueT value = CURR_SLOT.opnd[1].X_add_number;
+
+         if (CURR_SLOT.opnd[3].X_add_number < 64)
+           value &= ((valueT)1 << CURR_SLOT.opnd[3].X_add_number) - 1;
+         value <<= CURR_SLOT.opnd[2].X_add_number;
+         gr_values[regno].known = 1;
+         gr_values[regno].value = value;
+         gr_values[regno].path = md.path;
+         if (md.debug_dv)
+           {
+             fprintf (stderr, "  Know gr%d = ", regno);
+             fprintf_vma (stderr, gr_values[regno].value);
+             fputs ("\n", stderr);
+           }
+       }
+    }
   else
     {
       clear_qp_mutex (qp_changemask);
@@ -9872,7 +10207,7 @@ print_dependency (action, depind)
       fprintf (stderr, "  %s %s '%s'",
               action, dv_mode[(regdeps[depind].dependency)->mode],
               (regdeps[depind].dependency)->name);
-      if (regdeps[depind].specific && regdeps[depind].index != 0)
+      if (regdeps[depind].specific && regdeps[depind].index >= 0)
        fprintf (stderr, " (%d)", regdeps[depind].index);
       if (regdeps[depind].mem_offset.hint)
        {
@@ -9939,6 +10274,7 @@ remove_marked_resource (rs)
          struct slot oldslot = CURR_SLOT;
          /* Manually jam a srlz.i insn into the stream */
          memset (&CURR_SLOT, 0, sizeof (CURR_SLOT));
+         CURR_SLOT.user_template = -1;
          CURR_SLOT.idesc = ia64_find_opcode ("srlz.i");
          instruction_serialization ();
          md.curr_slot = (md.curr_slot + 1) % NUM_SLOTS;
@@ -9960,6 +10296,7 @@ remove_marked_resource (rs)
        struct slot oldslot = CURR_SLOT;
        /* Manually jam a srlz.d insn into the stream */
        memset (&CURR_SLOT, 0, sizeof (CURR_SLOT));
+       CURR_SLOT.user_template = -1;
        CURR_SLOT.idesc = ia64_find_opcode ("srlz.d");
        data_serialization ();
        md.curr_slot = (md.curr_slot + 1) % NUM_SLOTS;
@@ -10070,7 +10407,7 @@ check_dependencies (idesc)
              if (path != 0)
                sprintf (pathmsg, " when entry is at label '%s'",
                         md.entry_labels[path - 1]);
-             if (rs->specific && rs->index != 0)
+             if (matchtype == 1 && rs->index >= 0)
                sprintf (indexmsg, ", specific resource number is %d",
                         rs->index);
              sprintf (msg, "Use of '%s' %s %s dependency '%s' (%s)%s%s",
@@ -10431,11 +10768,25 @@ md_assemble (str)
          else if (ar_is_only_in_memory_unit (CURR_SLOT.opnd[rop].X_add_number))
            unit = 'm';
          if (unit != 'a' && unit != idesc->name [4])
-           as_bad ("AR %d cannot be accessed by %c-unit",
+           as_bad ("AR %d can only be accessed by %c-unit",
                    (int) (CURR_SLOT.opnd[rop].X_add_number - REG_AR),
                    TOUPPER (unit));
        }
     }
+  else if (strcmp (idesc->name, "hint.b") == 0)
+    {
+      switch (md.hint_b)
+       {
+       case hint_b_ok:
+         break;
+       case hint_b_warning:
+         as_warn ("hint.b may be treated as nop");
+         break;
+       case hint_b_error:
+         as_bad ("hint.b shouldn't be used");
+         break;
+       }
+    }
 
   qp_regno = 0;
   if (md.qp.X_op == O_register)
@@ -10487,7 +10838,7 @@ md_assemble (str)
       CURR_SLOT.unwind_record = unwind.current_entry;
       unwind.current_entry = NULL;
     }
-  if (unwind.proc_start && S_IS_DEFINED (unwind.proc_start))
+  if (unwind.proc_pending.sym && S_IS_DEFINED (unwind.proc_pending.sym))
     unwind.insn = 1;
 
   /* Check for dependency violations.  */
@@ -10563,7 +10914,7 @@ ia64_fix_adjustable (fix)
      fixS *fix;
 {
   /* Prevent all adjustments to global symbols */
-  if (S_IS_EXTERN (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy))
+  if (S_IS_EXTERNAL (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy))
     return 0;
 
   switch (fix->fx_r_type)
@@ -10724,7 +11075,7 @@ ia64_cons_fix_new (f, where, nbytes, exp)
   fix = fix_new_exp (f, where, nbytes, exp, 0, code);
   /* We need to store the byte order in effect in case we're going
      to fix an 8 or 16 bit relocation (for which there no real
-     relocs available).  See md_apply_fix3().  */
+     relocs available).  See md_apply_fix().  */
   fix->tc_fix_data.bigendian = target_big_endian;
 }
 
@@ -10738,6 +11089,7 @@ ia64_gen_real_reloc_type (sym, r_type)
      bfd_reloc_code_real_type r_type;
 {
   bfd_reloc_code_real_type new = 0;
+  const char *type = NULL, *suffix = "";
 
   if (sym == NULL)
     {
@@ -10754,7 +11106,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_FPTR32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_FPTR64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_FPTR64LSB; break;
-       default:                        break;
+       default:                        type = "FPTR"; break;
        }
       break;
 
@@ -10767,7 +11119,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_GPREL32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_GPREL64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_GPREL64LSB; break;
-       default:                        break;
+       default:                        type = "GPREL"; break;
        }
       break;
 
@@ -10776,7 +11128,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        {
        case BFD_RELOC_IA64_IMM22:      new = BFD_RELOC_IA64_LTOFF22; break;
        case BFD_RELOC_IA64_IMM64:      new = BFD_RELOC_IA64_LTOFF64I; break;
-       default:                        break;
+       default:                        type = "LTOFF"; break;
        }
       break;
 
@@ -10784,7 +11136,7 @@ ia64_gen_real_reloc_type (sym, r_type)
       switch (r_type)
        {
        case BFD_RELOC_IA64_IMM22:      new = BFD_RELOC_IA64_LTOFF22X; break;
-       default:                        break;
+       default:                        type = "LTOFF"; suffix = "X"; break;
        }
       break;
 
@@ -10797,7 +11149,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_PCREL32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_PCREL64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_PCREL64LSB; break;
-       default:                        break;
+       default:                        type = "PCREL"; break;
        }
       break;
 
@@ -10808,7 +11160,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM64:      new = BFD_RELOC_IA64_PLTOFF64I; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_PLTOFF64MSB;break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_PLTOFF64LSB;break;
-       default:                        break;
+       default:                        type = "PLTOFF"; break;
        }
       break;
 
@@ -10819,7 +11171,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_SECREL32LSB;break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_SECREL64MSB;break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_SECREL64LSB;break;
-       default:                        break;
+       default:                        type = "SECREL"; break;
        }
       break;
 
@@ -10830,7 +11182,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_SEGREL32LSB;break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_SEGREL64MSB;break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_SEGREL64LSB;break;
-       default:                        break;
+       default:                        type = "SEGREL"; break;
        }
       break;
 
@@ -10841,7 +11193,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_DIR32LSB:   new = BFD_RELOC_IA64_LTV32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_LTV64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_LTV64LSB; break;
-       default:                        break;
+       default:                        type = "LTV"; break;
        }
       break;
 
@@ -10852,22 +11204,28 @@ ia64_gen_real_reloc_type (sym, r_type)
          new = BFD_RELOC_IA64_LTOFF_FPTR22; break;
        case BFD_RELOC_IA64_IMM64:
          new = BFD_RELOC_IA64_LTOFF_FPTR64I; break;
+       case BFD_RELOC_IA64_DIR32MSB:
+         new = BFD_RELOC_IA64_LTOFF_FPTR32MSB; break;
+       case BFD_RELOC_IA64_DIR32LSB:
+         new = BFD_RELOC_IA64_LTOFF_FPTR32LSB; break;
+       case BFD_RELOC_IA64_DIR64MSB:
+         new = BFD_RELOC_IA64_LTOFF_FPTR64MSB; break;
+       case BFD_RELOC_IA64_DIR64LSB:
+         new = BFD_RELOC_IA64_LTOFF_FPTR64LSB; break;
        default:
-         break;
+         type = "LTOFF_FPTR"; break;
        }
       break;
 
     case FUNC_TP_RELATIVE:
       switch (r_type)
        {
-       case BFD_RELOC_IA64_IMM14:
-         new = BFD_RELOC_IA64_TPREL14; break;
-       case BFD_RELOC_IA64_IMM22:
-         new = BFD_RELOC_IA64_TPREL22; break;
-       case BFD_RELOC_IA64_IMM64:
-         new = BFD_RELOC_IA64_TPREL64I; break;
-       default:
-         break;
+       case BFD_RELOC_IA64_IMM14:      new = BFD_RELOC_IA64_TPREL14; break;
+       case BFD_RELOC_IA64_IMM22:      new = BFD_RELOC_IA64_TPREL22; break;
+       case BFD_RELOC_IA64_IMM64:      new = BFD_RELOC_IA64_TPREL64I; break;
+       case BFD_RELOC_IA64_DIR64MSB:   new = BFD_RELOC_IA64_TPREL64MSB; break;
+       case BFD_RELOC_IA64_DIR64LSB:   new = BFD_RELOC_IA64_TPREL64LSB; break;
+       default:                        type = "TPREL"; break;
        }
       break;
 
@@ -10877,7 +11235,19 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM22:
          new = BFD_RELOC_IA64_LTOFF_TPREL22; break;
        default:
-         break;
+         type = "LTOFF_TPREL"; break;
+       }
+      break;
+
+    case FUNC_DTP_MODULE:
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_DIR64MSB:
+         new = BFD_RELOC_IA64_DTPMOD64MSB; break;
+       case BFD_RELOC_IA64_DIR64LSB:
+         new = BFD_RELOC_IA64_DTPMOD64LSB; break;
+       default:
+         type = "DTPMOD"; break;
        }
       break;
 
@@ -10887,13 +11257,17 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM22:
          new = BFD_RELOC_IA64_LTOFF_DTPMOD22; break;
        default:
-         break;
+         type = "LTOFF_DTPMOD"; break;
        }
       break;
 
     case FUNC_DTP_RELATIVE:
       switch (r_type)
        {
+       case BFD_RELOC_IA64_DIR32MSB:
+         new = BFD_RELOC_IA64_DTPREL32MSB; break;
+       case BFD_RELOC_IA64_DIR32LSB:
+         new = BFD_RELOC_IA64_DTPREL32LSB; break;
        case BFD_RELOC_IA64_DIR64MSB:
          new = BFD_RELOC_IA64_DTPREL64MSB; break;
        case BFD_RELOC_IA64_DIR64LSB:
@@ -10905,7 +11279,7 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM64:
          new = BFD_RELOC_IA64_DTPREL64I; break;
        default:
-         break;
+         type = "DTPREL"; break;
        }
       break;
 
@@ -10915,22 +11289,49 @@ ia64_gen_real_reloc_type (sym, r_type)
        case BFD_RELOC_IA64_IMM22:
          new = BFD_RELOC_IA64_LTOFF_DTPREL22; break;
        default:
-         break;
+         type = "LTOFF_DTPREL"; break;
        }
       break;
 
     case FUNC_IPLT_RELOC:
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_IPLTMSB:    return r_type;
+       case BFD_RELOC_IA64_IPLTLSB:    return r_type;
+       default:                        type = "IPLT"; break;
+       }
       break;
 
     default:
       abort ();
     }
 
-  /* Hmmmm.  Should this ever occur?  */
   if (new)
     return new;
   else
-    return r_type;
+    {
+      int width;
+
+      if (!type)
+       abort ();
+      switch (r_type)
+       {
+       case BFD_RELOC_IA64_DIR32MSB: width = 32; suffix = "MSB"; break;
+       case BFD_RELOC_IA64_DIR32LSB: width = 32; suffix = "LSB"; break;
+       case BFD_RELOC_IA64_DIR64MSB: width = 64; suffix = "MSB"; break;
+       case BFD_RELOC_IA64_DIR64LSB: width = 64; suffix = "LSB"; break;
+       case BFD_RELOC_UNUSED:        width = 13; break;
+       case BFD_RELOC_IA64_IMM14:    width = 14; break;
+       case BFD_RELOC_IA64_IMM22:    width = 22; break;
+       case BFD_RELOC_IA64_IMM64:    width = 64; suffix = "I"; break;
+       default:                      abort ();
+       }
+
+      /* This should be an error, but since previously there wasn't any
+        diagnostic here, dont't make it fail because of this for now.  */
+      as_warn ("Cannot express %s%d%s relocation", type, width, suffix);
+      return r_type;
+    }
 }
 
 /* Here is where generate the appropriate reloc for pseudo relocation
@@ -11021,7 +11422,7 @@ fix_insn (fix, odesc, value)
    (if possible).  */
 
 void
-md_apply_fix3 (fix, valP, seg)
+md_apply_fix (fix, valP, seg)
      fixS *fix;
      valueT *valP;
      segT seg ATTRIBUTE_UNUSED;
@@ -11033,27 +11434,24 @@ md_apply_fix3 (fix, valP, seg)
 
   if (fix->fx_pcrel)
     {
-      switch (fix->fx_r_type)
-       {
-       case BFD_RELOC_IA64_DIR32MSB:
-         fix->fx_r_type = BFD_RELOC_IA64_PCREL32MSB;
-         break;
-
-       case BFD_RELOC_IA64_DIR32LSB:
-         fix->fx_r_type = BFD_RELOC_IA64_PCREL32LSB;
-         break;
-
-       case BFD_RELOC_IA64_DIR64MSB:
-         fix->fx_r_type = BFD_RELOC_IA64_PCREL64MSB;
-         break;
-
-       case BFD_RELOC_IA64_DIR64LSB:
-         fix->fx_r_type = BFD_RELOC_IA64_PCREL64LSB;
-         break;
-
-       default:
-         break;
-       }
+    switch (fix->fx_r_type)
+      {
+      case BFD_RELOC_IA64_PCREL21B: break;
+      case BFD_RELOC_IA64_PCREL21BI: break;
+      case BFD_RELOC_IA64_PCREL21F: break;
+      case BFD_RELOC_IA64_PCREL21M: break;
+      case BFD_RELOC_IA64_PCREL60B: break;
+      case BFD_RELOC_IA64_PCREL22: break;
+      case BFD_RELOC_IA64_PCREL64I: break;
+      case BFD_RELOC_IA64_PCREL32MSB: break;
+      case BFD_RELOC_IA64_PCREL32LSB: break;
+      case BFD_RELOC_IA64_PCREL64MSB: break;
+      case BFD_RELOC_IA64_PCREL64LSB: break;
+      default:
+       fix->fx_r_type = ia64_gen_real_reloc_type (pseudo_func[FUNC_PC_RELATIVE].u.sym,
+                                              fix->fx_r_type);
+       break;
+      }
     }
   if (fix->fx_addsy)
     {
@@ -11208,14 +11606,6 @@ void
 ia64_handle_align (fragp)
      fragS *fragp;
 {
-  /* Use mfi bundle of nops with no stop bits.  */
-  static const unsigned char le_nop[]
-    = { 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-       0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
-  static const unsigned char le_nop_stop[]
-    = { 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-       0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
-
   int bytes;
   char *p;
   const unsigned char *nop;
This page took 0.04519 seconds and 4 git commands to generate.