* config/tc-ia64.c (has_suffix_p): New.
[binutils-gdb.git] / gas / config / tc-ia64.c
index 0a3dcc63e2667d1b850de6951f15ea45b4a5ad33..fa51977c2d76b5c36bf79dae41304dfe69ca39c9 100644 (file)
@@ -43,6 +43,7 @@
  */
 
 #include "as.h"
+#include "safe-ctype.h"
 #include "dwarf2dbg.h"
 #include "subsegs.h"
 
 
 enum special_section
   {
+    /* IA-64 ABI section pseudo-ops.  */
     SPECIAL_SECTION_BSS = 0,
     SPECIAL_SECTION_SBSS,
     SPECIAL_SECTION_SDATA,
     SPECIAL_SECTION_RODATA,
     SPECIAL_SECTION_COMMENT,
     SPECIAL_SECTION_UNWIND,
-    SPECIAL_SECTION_UNWIND_INFO
+    SPECIAL_SECTION_UNWIND_INFO,
+    /* HPUX specific section pseudo-ops.  */
+    SPECIAL_SECTION_INIT_ARRAY,
+    SPECIAL_SECTION_FINI_ARRAY,
   };
 
 enum reloc_func
@@ -81,6 +86,7 @@ enum reloc_func
     FUNC_SEG_RELATIVE,
     FUNC_LTV_RELATIVE,
     FUNC_LT_FPTR_RELATIVE,
+    FUNC_IPLT_RELOC,
   };
 
 enum reg_symbol
@@ -279,6 +285,9 @@ static struct
       int g_reg_set_conditionally[128];
     } last_groups[3];
     int group_idx;
+
+    int pointer_size;       /* size in bytes of a pointer */
+    int pointer_size_shift; /* shift size of a pointer for alignment */
   }
 md;
 
@@ -476,6 +485,7 @@ pseudo_func[] =
     { "segrel",        PSEUDO_FUNC_RELOC, { 0 } },
     { "ltv",   PSEUDO_FUNC_RELOC, { 0 } },
     { "", 0, { 0 } },  /* placeholder for FUNC_LT_FPTR_RELATIVE */
+    { "iplt",  PSEUDO_FUNC_RELOC, { 0 } },
 
     /* mbtype4 constants:  */
     { "alt",   PSEUDO_FUNC_CONST, { 0xa } },
@@ -523,7 +533,8 @@ static const bfd_vma nop[IA64_NUM_UNITS] =
 static char special_section_name[][20] =
   {
     {".bss"}, {".sbss"}, {".sdata"}, {".rodata"}, {".comment"},
-    {".IA_64.unwind"}, {".IA_64.unwind_info"}
+    {".IA_64.unwind"}, {".IA_64.unwind_info"},
+    {".init_array"}, {".fini_array"}
   };
 
 static char *special_linkonce_name[] =
@@ -708,6 +719,7 @@ static enum operand_match_result operand_match PARAMS ((const struct ia64_opcode
                                                        expressionS *e));
 static int parse_operand PARAMS ((expressionS *e));
 static struct ia64_opcode * parse_operands PARAMS ((struct ia64_opcode *));
+static int errata_nop_necessary_p PARAMS ((struct slot *, enum ia64_unit));
 static void build_insn PARAMS ((struct slot *, bfd_vma *));
 static void emit_one_bundle PARAMS ((void));
 static void fix_insn PARAMS ((fixS *, const struct ia64_operand *, valueT));
@@ -721,6 +733,7 @@ static void add_qp_imply PARAMS((int p1, int p2));
 static void clear_qp_branch_flag PARAMS((valueT mask));
 static void clear_qp_mutex PARAMS((valueT mask));
 static void clear_qp_implies PARAMS((valueT p1_mask, valueT p2_mask));
+static int has_suffix_p PARAMS((const char *, const char *));
 static void clear_register_values PARAMS ((void));
 static void print_dependency PARAMS ((const char *action, int depind));
 static void instruction_serialization PARAMS ((void));
@@ -856,8 +869,8 @@ static int generate_unwind_image PARAMS ((const char *));
    stack, so this must be a macro... */
 #define make_unw_section_name(special, text_name, result)                 \
   {                                                                       \
-    char *_prefix = special_section_name[special];                        \
-    char *_suffix = text_name;                                            \
+    const char *_prefix = special_section_name[special];                  \
+    const char *_suffix = text_name;                                      \
     size_t _prefix_len, _suffix_len;                                      \
     char *_result;                                                        \
     if (strncmp (text_name, ".gnu.linkonce.t.",                                   \
@@ -868,8 +881,8 @@ static int generate_unwind_image PARAMS ((const char *));
       }                                                                           \
     _prefix_len = strlen (_prefix), _suffix_len = strlen (_suffix);       \
     _result = alloca (_prefix_len + _suffix_len + 1);                     \
-    memcpy(_result, _prefix, _prefix_len);                                \
-    memcpy(_result + _prefix_len, _suffix, _suffix_len);                  \
+    memcpy (_result, _prefix, _prefix_len);                               \
+    memcpy (_result + _prefix_len, _suffix, _suffix_len);                 \
     _result[_prefix_len + _suffix_len] = '\0';                            \
     result = _result;                                                     \
   }                                                                       \
@@ -906,6 +919,20 @@ set_section (name)
   input_line_pointer = saved_input_line_pointer;
 }
 
+/* Map 's' to SHF_IA_64_SHORT.  */
+
+int
+ia64_elf_section_letter (letter, ptr_msg)
+     int letter;
+     char **ptr_msg;
+{
+  if (letter == 's')
+    return SHF_IA_64_SHORT;
+
+  *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S in string");
+  return 0;
+}
+
 /* Map SHF_IA_64_SHORT to SEC_SMALL_DATA.  */
 
 flagword
@@ -2757,6 +2784,37 @@ fixup_unw_records (list)
     }
 }
 
+/* Helper routine for output_unw_records.  Emits the header for the unwind
+   info.  */
+
+static int
+setup_unwind_header (int size, unsigned char **mem)
+{
+  int x, extra = 0;
+
+  /* pad to pointer-size boundry.  */
+  x = size % md.pointer_size;
+  if (x != 0)
+    extra = md.pointer_size - x;
+
+  /* Add 8 for the header + a pointer for the 
+     personality offset.  */
+  *mem = xmalloc (size + extra + 8 + md.pointer_size);
+
+  /* Clear the padding area and personality.  */
+  memset (*mem + 8 + size, 0 , extra + md.pointer_size);
+  /* Initialize the header area.  */
+
+  md_number_to_chars (*mem, (((bfd_vma) 1 << 48)     /* version */
+                            | (unwind.personality_routine
+                               ? ((bfd_vma) 3 << 32) /* U & E handler flags */
+                               : 0)
+                            | ((size + extra) / md.pointer_size)), /* length */
+                     8);
+
+  return extra;
+}
+
 /* Generate an unwind image from a record list.  Returns the number of
    bytes in the resulting image. The memory image itselof is returned
    in the 'ptr' parameter.  */
@@ -2765,7 +2823,7 @@ output_unw_records (list, ptr)
      unw_rec_list *list;
      void **ptr;
 {
-  int size, x, extra = 0;
+  int size, extra;
   unsigned char *mem;
 
   *ptr = NULL;
@@ -2774,35 +2832,17 @@ output_unw_records (list, ptr)
   fixup_unw_records (list);
   size = calc_record_size (list);
 
-  /* pad to 8 byte boundry.  */
-  x = size % 8;
-  if (x != 0)
-    extra = 8 - x;
-
   if (size > 0 || unwind.force_unwind_entry)
     {
       unwind.force_unwind_entry = 0;
-
-      /* Add 8 for the header + 8 more bytes for the personality offset.  */
-      mem = xmalloc (size + extra + 16);
+      extra = setup_unwind_header (size, &mem);
 
       vbyte_mem_ptr = mem + 8;
-      /* Clear the padding area and personality.  */
-      memset (mem + 8 + size, 0 , extra + 8);
-      /* Initialize the header area.  */
-      md_number_to_chars (mem,
-                         (((bfd_vma) 1 << 48)     /* version */
-                          | (unwind.personality_routine
-                             ? ((bfd_vma) 3 << 32) /* U & E handler flags */
-                             : 0)
-                          | ((size + extra) / 8)),  /* length (dwords) */
-                         8);
-
       process_unw_records (list, output_vbyte_mem);
 
       *ptr = mem;
 
-      size += extra + 16;
+      size += extra + 8 + md.pointer_size;
     }
   return size;
 }
@@ -3171,9 +3211,9 @@ generate_unwind_image (text_name)
 
   /* Generate the unwind record.  */
   size = output_unw_records (unwind.list, (void **) &unw_rec);
-  if (size % 8 != 0)
-    as_bad ("Unwind record is not a multiple of 8 bytes.");
-
+  if (size % md.pointer_size != 0)
+    as_bad ("Unwind record is not a multiple of %d bytes.", md.pointer_size);
+                      
   /* If there are unwind records, switch sections, and output the info.  */
   if (size != 0)
     {
@@ -3186,9 +3226,10 @@ generate_unwind_image (text_name)
       bfd_set_section_flags (stdoutput, now_seg,
                             SEC_LOAD | SEC_ALLOC | SEC_READONLY);
 
-      /* Make sure the section has 8 byte alignment.  */
-      frag_align (3, 0, 0);
-      record_alignment (now_seg, 3);
+      /* Make sure the section has 4 byte alignment for ILP32 and
+        8 byte alignment for LP64.  */
+      frag_align (md.pointer_size_shift, 0, 0);
+      record_alignment (now_seg, md.pointer_size_shift);
 
       /* Set expression which points to start of unwind descriptor area.  */
       unwind.info = expr_build_dot ();
@@ -3819,6 +3860,8 @@ dot_endp (dummy)
   segT saved_seg;
   subsegT saved_subseg;
   const char *sec_name, *text_name;
+  char *name, *p, c;
+  symbolS *sym;
 
   if (unwind.saved_text_seg)
     {
@@ -3875,9 +3918,6 @@ dot_endp (dummy)
   if (strcmp (text_name, ".text") == 0)
     text_name = "";
 
-  expression (&e);
-  demand_empty_rest_of_line ();
-
   insn_group_break (1, 0, 0);
 
   /* If there wasn't a .handlerdata, we haven't generated an image yet.  */
@@ -3894,11 +3934,14 @@ dot_endp (dummy)
       bfd_set_section_flags (stdoutput, now_seg,
                             SEC_LOAD | SEC_ALLOC | SEC_READONLY);
 
-      /* Make sure the section has 8 byte alignment.  */
-      record_alignment (now_seg, 3);
+      /* Make sure that section has 4 byte alignment for ILP32 and
+         8 byte alignment for LP64.  */
+      record_alignment (now_seg, md.pointer_size_shift);
 
-      ptr = frag_more (24);
-      where = frag_now_fix () - 24;
+      /* Need space for 3 pointers for procedure start, procedure end,
+        and unwind info.  */
+      ptr = frag_more (3 * md.pointer_size);
+      where = frag_now_fix () - (3 * md.pointer_size);
       bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
 
       /* Issue the values of  a) Proc Begin, b) Proc End, c) Unwind Record. */
@@ -3930,6 +3973,50 @@ dot_endp (dummy)
 
     }
   subseg_set (saved_seg, saved_subseg);
+
+  /* Parse names of main and alternate entry points and set symbol sizes.  */
+  while (1)
+    {
+      SKIP_WHITESPACE ();
+      name = input_line_pointer;
+      c = get_symbol_end ();
+      p = input_line_pointer;
+      sym = symbol_find (name);
+      if (sym && unwind.proc_start
+         && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
+         && 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 == frag_now && SEG_NORMAL (now_seg))
+               S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
+             else
+               {
+                 symbol_get_obj (sym)->size =
+                   (expressionS *) xmalloc (sizeof (expressionS));
+                 symbol_get_obj (sym)->size->X_op = O_subtract;
+                 symbol_get_obj (sym)->size->X_add_symbol
+                   = symbol_new (FAKE_LABEL_NAME, now_seg,
+                                 frag_now_fix (), frag_now);
+                 symbol_get_obj (sym)->size->X_op_symbol = sym;
+                 symbol_get_obj (sym)->size->X_add_number = 0;
+               }
+           }
+       }
+      *p = c;
+      SKIP_WHITESPACE ();
+      if (*input_line_pointer != ',')
+       break;
+      ++input_line_pointer;
+    }
+  demand_empty_rest_of_line ();
   unwind.proc_start = unwind.proc_end = unwind.info = 0;
 }
 
@@ -4430,7 +4517,7 @@ dot_pred_rel (type)
       valueT bit = 1;
       int regno;
 
-      if (toupper (*input_line_pointer) != 'P'
+      if (TOUPPER (*input_line_pointer) != 'P'
          || (regno = atoi (++input_line_pointer)) < 0
          || regno > 63)
        {
@@ -4438,7 +4525,7 @@ dot_pred_rel (type)
          ignore_rest_of_line ();
          return;
        }
-      while (isdigit (*input_line_pointer))
+      while (ISDIGIT (*input_line_pointer))
        ++input_line_pointer;
       if (p1 == -1)
        p1 = regno;
@@ -4455,7 +4542,7 @@ dot_pred_rel (type)
          valueT stop = 1;
          ++input_line_pointer;
 
-         if (toupper (*input_line_pointer) != 'P'
+         if (TOUPPER (*input_line_pointer) != 'P'
              || (regno = atoi (++input_line_pointer)) < 0
              || regno > 63)
            {
@@ -4463,7 +4550,7 @@ dot_pred_rel (type)
              ignore_rest_of_line ();
              return;
            }
-         while (isdigit (*input_line_pointer))
+         while (ISDIGIT (*input_line_pointer))
            ++input_line_pointer;
          stop <<= regno;
          if (bit >= stop)
@@ -4606,6 +4693,8 @@ const pseudo_typeS md_pseudo_table[] =
     { "comment", dot_special_section, SPECIAL_SECTION_COMMENT },
     { "ia_64.unwind", dot_special_section, SPECIAL_SECTION_UNWIND },
     { "ia_64.unwind_info", dot_special_section, SPECIAL_SECTION_UNWIND_INFO },
+    { "init_array", dot_special_section, SPECIAL_SECTION_INIT_ARRAY },
+    { "fini_array", dot_special_section, SPECIAL_SECTION_FINI_ARRAY },
     { "proc", dot_proc, 0 },
     { "body", dot_body, 0 },
     { "prologue", dot_prologue, 0 },
@@ -4701,6 +4790,15 @@ const pseudo_typeS md_pseudo_table[] =
     { "explicit", dot_dv_mode, 'e' },
     { "default", dot_dv_mode, 'd' },
 
+    /* ??? These are needed to make gas/testsuite/gas/elf/ehopt.s work.
+       IA-64 aligns data allocation pseudo-ops by default, so we have to
+       tell it that these ones are supposed to be unaligned.  Long term,
+       should rewrite so that only IA-64 specific data allocation pseudo-ops
+       are aligned by default.  */
+    {"2byte", stmt_cons_ua, 2},
+    {"4byte", stmt_cons_ua, 4},
+    {"8byte", stmt_cons_ua, 8},
+
     { NULL, 0, 0 }
   };
 
@@ -4717,6 +4815,7 @@ pseudo_opcode[] =
     { "data2", cons, 2 },
     { "data4", cons, 4 },
     { "data8", cons, 8 },
+    { "data16", cons, 16 },
     { "real4", stmt_float_cons, 'f' },
     { "real8", stmt_float_cons, 'd' },
     { "real10", stmt_float_cons, 'x' },
@@ -4727,6 +4826,7 @@ pseudo_opcode[] =
     { "data2.ua", stmt_cons_ua, 2 },
     { "data4.ua", stmt_cons_ua, 4 },
     { "data8.ua", stmt_cons_ua, 8 },
+    { "data16.ua", stmt_cons_ua, 16 },
     { "real4.ua", float_cons, 'f' },
     { "real8.ua", float_cons, 'd' },
     { "real10.ua", float_cons, 'x' },
@@ -6212,6 +6312,13 @@ IA-64 options:\n\
        stream);
 }
 
+void
+ia64_after_parse_args ()
+{
+  if (debug_type == DEBUG_STABS)
+    as_fatal (_("--gstabs is not supported for ia64"));
+}
+
 /* Return true if TYPE fits in TEMPL at SLOT.  */
 
 static int
@@ -6302,6 +6409,10 @@ md_begin ()
     symbol_new (".<ltoff.fptr>", undefined_section, FUNC_LT_FPTR_RELATIVE,
                &zero_address_frag);
 
+  pseudo_func[FUNC_IPLT_RELOC].u.sym =
+    symbol_new (".<iplt>", undefined_section, FUNC_IPLT_RELOC,
+               &zero_address_frag);
+
   /* 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
@@ -6474,6 +6585,19 @@ md_begin ()
   if (! ok)
      as_warn (_("Could not set architecture and machine"));
 
+  /* Set the pointer size and pointer shift size depending on md.flags */
+
+  if (md.flags & EF_IA_64_ABI64)
+    {
+      md.pointer_size = 8;         /* pointers are 8 bytes */
+      md.pointer_size_shift = 3;   /* alignment is 8 bytes = 2^2 */
+    }
+  else
+    {
+      md.pointer_size = 4;         /* pointers are 4 bytes */
+      md.pointer_size_shift = 2;   /* alignment is 4 bytes = 2^2 */
+    }
+
   md.mem_offset.hint = 0;
   md.path = 0;
   md.maxpaths = 0;
@@ -6665,10 +6789,10 @@ ia64_unrecognized_line (ch)
            c = get_symbol_end ();
          }
        else if (LOCAL_LABELS_FB
-                && isdigit ((unsigned char) *input_line_pointer))
+                && ISDIGIT (*input_line_pointer))
          {
            temp = 0;
-           while (isdigit ((unsigned char) *input_line_pointer))
+           while (ISDIGIT (*input_line_pointer))
              temp = (temp * 10) + *input_line_pointer++ - '0';
            fb_label_instance_inc (temp);
            s = fb_label_name (temp, 0);
@@ -6841,7 +6965,7 @@ ia64_parse_name (name, e)
   switch (name[0])
     {
     case 'i':
-      if (name[1] == 'n' && isdigit (name[2]))
+      if (name[1] == 'n' && ISDIGIT (name[2]))
        {
          dr = &md.in;
          name += 2;
@@ -6849,7 +6973,7 @@ ia64_parse_name (name, e)
       break;
 
     case 'l':
-      if (name[1] == 'o' && name[2] == 'c' && isdigit (name[3]))
+      if (name[1] == 'o' && name[2] == 'c' && ISDIGIT (name[3]))
        {
          dr = &md.loc;
          name += 3;
@@ -6857,7 +6981,7 @@ ia64_parse_name (name, e)
       break;
 
     case 'o':
-      if (name[1] == 'u' && name[2] == 't' && isdigit (name[3]))
+      if (name[1] == 'u' && name[2] == 't' && ISDIGIT (name[3]))
        {
          dr = &md.out;
          name += 3;
@@ -6914,19 +7038,29 @@ ia64_canonicalize_symbol_name (name)
   return name;
 }
 
-/* Return true if idesc is a conditional branch instruction.  */
+/* Return true if idesc is a conditional branch instruction.  This excludes
+   the modulo scheduled branches, and br.ia.  Mod-sched branches are excluded
+   because they always read/write resources regardless of the value of the
+   qualifying predicate.  br.ia must always use p0, and hence is always
+   taken.  Thus this function returns true for branches which can fall
+   through, and which use no resources if they do fall through.  */
 
 static int
 is_conditional_branch (idesc)
      struct ia64_opcode *idesc;
 {
   /* br is a conditional branch.  Everything that starts with br. except
-     br.ia is a conditional branch.  Everything that starts with brl is a
-     conditional branch.  */
+     br.ia, br.c{loop,top,exit}, and br.w{top,exit} is a conditional branch.
+     Everything that starts with brl is a conditional branch.  */
   return (idesc->name[0] == 'b' && idesc->name[1] == 'r'
          && (idesc->name[2] == '\0'
-             || (idesc->name[2] == '.' && idesc->name[3] != 'i')
-             || idesc->name[2] == 'l'));
+             || (idesc->name[2] == '.' && idesc->name[3] != 'i'
+                 && idesc->name[3] != 'c' && idesc->name[3] != 'w')
+             || idesc->name[2] == 'l'
+             /* br.cond, br.call, br.clr  */
+             || (idesc->name[2] == '.' && idesc->name[3] == 'c'
+                 && (idesc->name[4] == 'a' || idesc->name[4] == 'o'
+                     || (idesc->name[4] == 'l' && idesc->name[5] == 'r')))));
 }
 
 /* Return whether the given opcode is a taken branch.  If there's any doubt,
@@ -7660,8 +7794,8 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
            {
              int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
              int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
-             int or_andcm = strstr(idesc->name, "or.andcm") != NULL;
-             int and_orcm = strstr(idesc->name, "and.orcm") != NULL;
+             int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
+             int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
 
              if ((idesc->operands[0] == IA64_OPND_P1
                   || idesc->operands[0] == IA64_OPND_P2)
@@ -7782,8 +7916,8 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
            {
              int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
              int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
-             int or_andcm = strstr(idesc->name, "or.andcm") != NULL;
-             int and_orcm = strstr(idesc->name, "and.orcm") != NULL;
+             int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
+             int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
 
              if ((idesc->operands[0] == IA64_OPND_P1
                   || idesc->operands[0] == IA64_OPND_P2)
@@ -8245,8 +8379,8 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
            {
               int p1 = CURR_SLOT.opnd[0].X_add_number - REG_P;
               int p2 = CURR_SLOT.opnd[1].X_add_number - REG_P;
-             int or_andcm = strstr(idesc->name, "or.andcm") != NULL;
-             int and_orcm = strstr(idesc->name, "and.orcm") != NULL;
+             int or_andcm = strstr (idesc->name, "or.andcm") != NULL;
+             int and_orcm = strstr (idesc->name, "and.orcm") != NULL;
 
              if (p1 == 63
                  && (idesc->operands[0] == IA64_OPND_P1
@@ -8497,6 +8631,19 @@ add_qp_mutex (mask)
   qp_mutexes[qp_mutexeslen++].prmask = mask;
 }
 
+static int
+has_suffix_p (name, suffix)
+      const char *name;
+      const char *suffix;
+{
+  size_t namelen = strlen (name);
+  size_t sufflen = strlen (suffix);
+
+  if (namelen <= sufflen)
+    return 0;
+  return strcmp (name + namelen - sufflen, suffix) == 0;
+}
+
 static void
 clear_register_values ()
 {
@@ -8614,21 +8761,19 @@ note_register_values (idesc)
        }
       /* In general, clear mutexes and implies which include P1 or P2,
         with the following exceptions.  */
-      else if (strstr (idesc->name, ".or.andcm") != NULL)
+      else if (has_suffix_p (idesc->name, ".or.andcm")
+              || has_suffix_p (idesc->name, ".and.orcm"))
        {
          add_qp_mutex (p1mask | p2mask);
          clear_qp_implies (p2mask, p1mask);
        }
-      else if (strstr (idesc->name, ".and.orcm") != NULL)
-       {
-         add_qp_mutex (p1mask | p2mask);
-         clear_qp_implies (p1mask, p2mask);
-       }
-      else if (strstr (idesc->name, ".and") != NULL)
+      else if (has_suffix_p (idesc->name, ".andcm")
+              || has_suffix_p (idesc->name, ".and"))
        {
          clear_qp_implies (0, p1mask | p2mask);
        }
-      else if (strstr (idesc->name, ".or") != NULL)
+      else if (has_suffix_p (idesc->name, ".orcm")
+              || has_suffix_p (idesc->name, ".or"))
        {
          clear_qp_mutex (p1mask | p2mask);
          clear_qp_implies (p1mask | p2mask, 0);
@@ -8636,7 +8781,7 @@ note_register_values (idesc)
       else
        {
          clear_qp_implies (p1mask | p2mask, p1mask | p2mask);
-         if (strstr (idesc->name, ".unc") != NULL)
+         if (has_suffix_p (idesc->name, ".unc"))
            {
              add_qp_mutex (p1mask | p2mask);
              if (CURR_SLOT.qp_regno != 0)
@@ -9724,6 +9869,21 @@ ia64_cons_fix_new (f, where, nbytes, exp)
        code = BFD_RELOC_IA64_DIR64LSB;
       break;
 
+    case 16:
+      if (exp->X_op == O_pseudo_fixup
+         && exp->X_op_symbol
+         && S_GET_VALUE (exp->X_op_symbol) == FUNC_IPLT_RELOC)
+       {
+         if (target_big_endian)
+           code = BFD_RELOC_IA64_IPLTMSB;
+         else
+           code = BFD_RELOC_IA64_IPLTLSB;
+
+         exp->X_op = O_symbol;
+         break;
+       }
+      /* FALLTHRU */
+
     default:
       as_bad ("Unsupported fixup size %d", nbytes);
       ignore_rest_of_line ();
@@ -9735,10 +9895,11 @@ ia64_cons_fix_new (f, where, nbytes, exp)
       exp->X_op = O_symbol;
       code = ia64_gen_real_reloc_type (exp->X_op_symbol, code);
     }
+
   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_fix().  */
+     relocs available).  See md_apply_fix3().  */
   fix->tc_fix_data.bigendian = target_big_endian;
 }
 
@@ -9862,6 +10023,7 @@ ia64_gen_real_reloc_type (sym, r_type)
          break;
        }
       break;
+
     default:
       abort ();
     }
@@ -9960,14 +10122,15 @@ fix_insn (fix, odesc, value)
 
    If fixp->fx_addsy is non-NULL, we'll have to generate a reloc entry
    (if possible).  */
-int
-md_apply_fix3 (fix, valuep, seg)
+
+void
+md_apply_fix3 (fix, valP, seg)
      fixS *fix;
-     valueT *valuep;
+     valueT * valP;
      segT seg ATTRIBUTE_UNUSED;
 {
   char *fixpos;
-  valueT value = *valuep;
+  valueT value = * valP;
   int adjust = 0;
 
   fixpos = fix->fx_frag->fr_literal + fix->fx_where;
@@ -10010,7 +10173,7 @@ md_apply_fix3 (fix, valuep, seg)
                        "%s must have a constant value",
                        elf64_ia64_operands[fix->tc_fix_data.opnd].desc);
          fix->fx_done = 1;
-         return 1;
+         return;
        }
 
       /* ??? This is a hack copied from tc-i386.c to make PCREL relocs
@@ -10025,15 +10188,12 @@ md_apply_fix3 (fix, valuep, seg)
       else
        number_to_chars_littleendian (fixpos, value, fix->fx_size);
       fix->fx_done = 1;
-      return 1;
     }
   else
     {
       fix_insn (fix, elf64_ia64_operands + fix->tc_fix_data.opnd, value);
       fix->fx_done = 1;
-      return 1;
     }
-  return 1;
 }
 
 /* Generate the BFD reloc to be stuck in the object file from the