* as.h (rs_align_test): New.
[deliverable/binutils-gdb.git] / gas / config / tc-ia64.c
index c582e50964f3fecb67fd241c6d836674dbb53a25..b0ff7ed4fc4618a3a60ae6abce7b004853763724 100644 (file)
@@ -156,7 +156,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 /* ia64-specific option processing:  */
 
-const char *md_shortopts = "M:N:x::";
+const char *md_shortopts = "m:N:x::";
 
 struct option md_longopts[] =
   {
@@ -252,6 +252,25 @@ static struct
                                       the current DV-checking block.  */
     int maxpaths;                   /* size currently allocated for
                                       entry_labels */
+    /* Support for hardware errata workarounds.  */
+
+    /* Record data about the last three insn groups.  */
+    struct group
+    {
+      /* B-step workaround.
+        For each predicate register, this is set if the corresponding insn
+        group conditionally sets this register with one of the affected
+        instructions.  */
+      int p_reg_set[64];
+      /* B-step workaround.
+        For each general register, this is set if the corresponding insn
+        a) is conditional one one of the predicate registers for which
+           P_REG_SET is 1 in the corresponding entry of the previous group,
+        b) sets this general register with one of the affected
+           instructions.  */
+      int g_reg_set_conditionally[128];
+    } last_groups[3];
+    int group_idx;
   }
 md;
 
@@ -440,15 +459,15 @@ static struct
 pseudo_func[] =
   {
     /* reloc pseudo functions (these must come first!):  */
-    { "fptr",  PSEUDO_FUNC_RELOC },
-    { "gprel", PSEUDO_FUNC_RELOC },
-    { "ltoff", PSEUDO_FUNC_RELOC },
-    { "pcrel", PSEUDO_FUNC_RELOC },
-    { "pltoff",        PSEUDO_FUNC_RELOC },
-    { "secrel",        PSEUDO_FUNC_RELOC },
-    { "segrel",        PSEUDO_FUNC_RELOC },
-    { "ltv",   PSEUDO_FUNC_RELOC },
-    { 0, },            /* placeholder for FUNC_LT_FPTR_RELATIVE */
+    { "fptr",  PSEUDO_FUNC_RELOC, { 0 } },
+    { "gprel", PSEUDO_FUNC_RELOC, { 0 } },
+    { "ltoff", PSEUDO_FUNC_RELOC, { 0 } },
+    { "pcrel", PSEUDO_FUNC_RELOC, { 0 } },
+    { "pltoff",        PSEUDO_FUNC_RELOC, { 0 } },
+    { "secrel",        PSEUDO_FUNC_RELOC, { 0 } },
+    { "segrel",        PSEUDO_FUNC_RELOC, { 0 } },
+    { "ltv",   PSEUDO_FUNC_RELOC, { 0 } },
+    { "", 0, { 0 } },  /* placeholder for FUNC_LT_FPTR_RELATIVE */
 
     /* mbtype4 constants:  */
     { "alt",   PSEUDO_FUNC_CONST, { 0xa } },
@@ -520,7 +539,7 @@ static struct rsrc {
   int data_srlz;                    /* current data serialization state */
   int qp_regno;                     /* qualifying predicate for this usage */
   char *file;                       /* what file marked this dependency */
-  int line;                         /* what line marked this dependency */
+  unsigned int line;                /* what line marked this dependency */
   struct mem_offset mem_offset;     /* optional memory offset hint */
   enum { CMP_NONE, CMP_OR, CMP_AND } cmp_type; /* OR or AND compare? */
   int path;                         /* corresponding code entry index */
@@ -557,22 +576,33 @@ static struct gr {
   unsigned known:1;
   int path;
   valueT value;
-} gr_values[128] = {{ 1, 0 }};
+} gr_values[128] = {{ 1, 0, 0 }};
 
 /* These are the routines required to output the various types of
    unwind records.  */
 
+/* A slot_number is a frag address plus the slot index (0-2).  We use the
+   frag address here so that if there is a section switch in the middle of
+   a function, then instructions emitted to a different section are not
+   counted.  Since there may be more than one frag for a function, this
+   means we also need to keep track of which frag this address belongs to
+   so we can compute inter-frag distances.  This also nicely solves the
+   problem with nops emitted for align directives, which can't easily be
+   counted, but can easily be derived from frag sizes.  */
+
 typedef struct unw_rec_list {
   unwind_record r;
   unsigned long slot_number;
+  fragS *slot_frag;
   struct unw_rec_list *next;
 } unw_rec_list;
 
-#define SLOT_NUM_NOT_SET        -1
+#define SLOT_NUM_NOT_SET        (unsigned)-1
 
 static struct
 {
   unsigned long next_slot_number;
+  fragS *next_slot_frag;
 
   /* Maintain a list of unwind entries for the current function.  */
   unw_rec_list *list;
@@ -793,7 +823,8 @@ static void process_unw_records PARAMS ((unw_rec_list *, vbyte_func));
 static int calc_record_size PARAMS ((unw_rec_list *));
 static void set_imask PARAMS ((unw_rec_list *, unsigned long, unsigned long, unsigned int));
 static int count_bits PARAMS ((unsigned long));
-static unsigned long slot_index PARAMS ((unsigned long, unsigned long));
+static unsigned long slot_index PARAMS ((unsigned long, fragS *,
+                                        unsigned long, fragS *));
 static void fixup_unw_records PARAMS ((unw_rec_list *));
 static int output_unw_records PARAMS ((unw_rec_list *, void **));
 static int convert_expr_to_ab_reg PARAMS ((expressionS *, unsigned int *, unsigned int *));
@@ -836,7 +867,7 @@ set_section (name)
 flagword
 ia64_elf_section_flags (flags, attr, type)
      flagword flags;
-     int attr, type;
+     int attr, type ATTRIBUTE_UNUSED;
 {
   if (attr & SHF_IA_64_SHORT)
     flags |= SEC_SMALL_DATA;
@@ -942,7 +973,7 @@ void
 output_vbyte_mem (count, ptr, comment)
      int count;
      char *ptr;
-     char *comment;
+     char *comment ATTRIBUTE_UNUSED;
 {
   int x;
   if (vbyte_mem_ptr == NULL)
@@ -959,8 +990,8 @@ static int vbyte_count = 0;
 void
 count_output (count, ptr, comment)
      int count;
-     char *ptr;
-     char *comment;
+     char *ptr ATTRIBUTE_UNUSED;
+     char *comment ATTRIBUTE_UNUSED;
 {
   vbyte_count += count;
 }
@@ -2406,11 +2437,45 @@ count_bits (unsigned long mask)
   return n;
 }
 
+/* Return the number of instruction slots from FIRST_ADDR to SLOT_ADDR.
+   SLOT_FRAG is the frag containing SLOT_ADDR, and FIRST_FRAG is the frag
+   containing FIRST_ADDR.  */
+
 unsigned long
-slot_index (unsigned long slot_addr, unsigned long first_addr)
+slot_index (slot_addr, slot_frag, first_addr, first_frag)
+     unsigned long slot_addr;
+     fragS *slot_frag;
+     unsigned long first_addr;
+     fragS *first_frag;
 {
-  return (3 * ((slot_addr >> 4) - (first_addr >> 4))
-         + ((slot_addr & 0x3) - (first_addr & 0x3)));
+  unsigned long index = 0;
+
+  /* First time we are called, the initial address and frag are invalid.  */
+  if (first_addr == 0)
+    return 0;
+
+  /* If the two addresses are in different frags, then we need to add in
+     the remaining size of this frag, and then the entire size of intermediate
+     frags.  */
+  while (slot_frag != first_frag)
+    {
+      unsigned long start_addr = (unsigned long) &first_frag->fr_literal;
+
+      /* Add in the full size of the frag converted to instruction slots.  */
+      index += 3 * (first_frag->fr_fix >> 4);
+      /* Subtract away the initial part before first_addr.  */
+      index -= (3 * ((first_addr >> 4) - (start_addr >> 4))
+               + ((first_addr & 0x3) - (start_addr & 0x3)));
+
+      /* Move to the beginning of the next frag.  */
+      first_frag = first_frag->fr_next;
+      first_addr = (unsigned long) &first_frag->fr_literal;
+    }
+
+  /* Add in the used part of the last frag.  */
+  index += (3 * ((slot_addr >> 4) - (first_addr >> 4))
+           + ((slot_addr & 0x3) - (first_addr & 0x3)));
+  return index;
 }
 
 /* Given a complete record list, process any records which have
@@ -2424,12 +2489,14 @@ fixup_unw_records (list)
 {
   unw_rec_list *ptr, *region = 0;
   unsigned long first_addr = 0, rlen = 0, t;
+  fragS *first_frag = 0;
 
   for (ptr = list; ptr; ptr = ptr->next)
     {
       if (ptr->slot_number == SLOT_NUM_NOT_SET)
        as_bad (" Insn slot not set in unwind record.");
-      t = slot_index (ptr->slot_number, first_addr);
+      t = slot_index (ptr->slot_number, ptr->slot_frag,
+                     first_addr, first_frag);
       switch (ptr->r.type)
        {
        case prologue:
@@ -2439,17 +2506,21 @@ fixup_unw_records (list)
            unw_rec_list *last;
            int size, dir_len = 0;
            unsigned long last_addr;
+           fragS *last_frag;
 
            first_addr = ptr->slot_number;
+           first_frag = ptr->slot_frag;
            ptr->slot_number = 0;
            /* Find either the next body/prologue start, or the end of
               the list, and determine the size of the region.  */
            last_addr = unwind.next_slot_number;
+           last_frag = unwind.next_slot_frag;
            for (last = ptr->next; last != NULL; last = last->next)
              if (last->r.type == prologue || last->r.type == prologue_gr
                  || last->r.type == body)
                {
                  last_addr = last->slot_number;
+                 last_frag = last->slot_frag;
                  break;
                }
              else if (!last->next)
@@ -2460,6 +2531,7 @@ fixup_unw_records (list)
                  if (ptr->r.type != body)
                    {
                      last_addr = last->slot_number;
+                     last_frag = last->slot_frag;
                      switch (last->r.type)
                        {
                        case frgr_mem:
@@ -2484,7 +2556,8 @@ fixup_unw_records (list)
                    }
                  break;
                }
-           size = slot_index (last_addr, first_addr) + dir_len;
+           size = (slot_index (last_addr, last_frag, first_addr, first_frag)
+                   + dir_len);
            rlen = ptr->r.record.r.rlen = size;
            region = ptr;
            break;
@@ -2630,18 +2703,18 @@ convert_expr_to_ab_reg (e, ab, regp)
     return 0;
 
   reg = e->X_add_number;
-  if (reg >= REG_GR + 4 && reg <= REG_GR + 7)
+  if (reg >= (REG_GR + 4) && reg <= (REG_GR + 7))
     {
       *ab = 0;
       *regp = reg - REG_GR;
     }
-  else if ((reg >= REG_FR + 2 && reg <= REG_FR + 5)
-          || (reg >= REG_FR + 16 && reg <= REG_FR + 31))
+  else if ((reg >= (REG_FR + 2) && reg <= (REG_FR + 5))
+          || (reg >= (REG_FR + 16) && reg <= (REG_FR + 31)))
     {
       *ab = 1;
       *regp = reg - REG_FR;
     }
-  else if (reg >= REG_BR + 1 && reg <= REG_BR + 5)
+  else if (reg >= (REG_BR + 1) && reg <= (REG_BR + 5))
     {
       *ab = 2;
       *regp = reg - REG_BR;
@@ -2683,17 +2756,17 @@ convert_expr_to_xy_reg (e, xy, regp)
 
   reg = e->X_add_number;
 
-  if (reg >= REG_GR && reg <= REG_GR + 127)
+  if (/* reg >= REG_GR && */ reg <= (REG_GR + 127))
     {
       *xy = 0;
       *regp = reg - REG_GR;
     }
-  else if (reg >= REG_FR && reg <= REG_FR + 127)
+  else if (reg >= REG_FR && reg <= (REG_FR + 127))
     {
       *xy = 1;
       *regp = reg - REG_FR;
     }
-  else if (reg >= REG_BR && reg <= REG_BR + 7)
+  else if (reg >= REG_BR && reg <= (REG_BR + 7))
     {
       *xy = 2;
       *regp = reg - REG_BR;
@@ -2705,7 +2778,7 @@ convert_expr_to_xy_reg (e, xy, regp)
 
 static void
 dot_radix (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   int radix;
 
@@ -2745,7 +2818,7 @@ add_unwind_entry (ptr)
 
 static void
 dot_fframe (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
 
@@ -2759,7 +2832,7 @@ dot_fframe (dummy)
 
 static void
 dot_vframe (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
   unsigned reg;
@@ -2778,7 +2851,7 @@ dot_vframe (dummy)
 
 static void
 dot_vframesp (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
 
@@ -2794,7 +2867,7 @@ dot_vframesp (dummy)
 
 static void
 dot_vframepsp (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
 
@@ -2810,7 +2883,7 @@ dot_vframepsp (dummy)
 
 static void
 dot_save (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e1, e2;
   int sep;
@@ -2887,7 +2960,7 @@ dot_save (dummy)
 
 static void
 dot_restore (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e1, e2;
   unsigned long ecount = 0;
@@ -2915,7 +2988,7 @@ dot_restore (dummy)
 
 static void
 dot_restorereg (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   unsigned int ab, reg;
   expressionS e;
@@ -2932,7 +3005,7 @@ dot_restorereg (dummy)
 
 static void
 dot_restorereg_p (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   unsigned int qp, ab, reg;
   expressionS e1, e2;
@@ -2984,6 +3057,9 @@ generate_unwind_image ()
       expressionS exp;
       set_section ((char *) special_section_name[SPECIAL_SECTION_UNWIND_INFO]);
 
+      /* Make sure the section has 8 byte alignment.  */
+      record_alignment (now_seg, 3);
+
       /* Set expression which points to start of unwind descriptor area.  */
       unwind.info = expr_build_dot ();
 
@@ -3016,7 +3092,7 @@ generate_unwind_image ()
 
 static void
 dot_handlerdata (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   generate_unwind_image ();
   demand_empty_rest_of_line ();
@@ -3024,14 +3100,14 @@ dot_handlerdata (dummy)
 
 static void
 dot_unwentry (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   demand_empty_rest_of_line ();
 }
 
 static void
 dot_altrp (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
   unsigned reg;
@@ -3140,7 +3216,7 @@ dot_savemem (psprel)
 
 static void
 dot_saveg (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e1, e2;
   int sep;
@@ -3168,7 +3244,7 @@ dot_saveg (dummy)
 
 static void
 dot_savef (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e1;
   int sep;
@@ -3182,7 +3258,7 @@ dot_savef (dummy)
 
 static void
 dot_saveb (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e1, e2;
   unsigned int reg;
@@ -3217,7 +3293,7 @@ dot_saveb (dummy)
 
 static void
 dot_savegf (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e1, e2;
   int sep;
@@ -3237,7 +3313,7 @@ dot_savegf (dummy)
 
 static void
 dot_spill (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
   unsigned char sep;
@@ -3254,7 +3330,7 @@ dot_spill (dummy)
 
 static void
 dot_spillreg (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   int sep, ab, xy, reg, treg;
   expressionS e1, e2;
@@ -3321,7 +3397,7 @@ dot_spillmem (psprel)
 
 static void
 dot_spillreg_p (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   int sep, ab, xy, reg, treg;
   expressionS e1, e2, e3;
@@ -3420,7 +3496,7 @@ dot_spillmem_p (psprel)
 
 static void
 dot_label_state (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
 
@@ -3435,7 +3511,7 @@ dot_label_state (dummy)
 
 static void
 dot_copy_state (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
 
@@ -3450,7 +3526,7 @@ dot_copy_state (dummy)
 
 static void
 dot_unwabi (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e1, e2;
   unsigned char sep;
@@ -3482,7 +3558,7 @@ dot_unwabi (dummy)
 
 static void
 dot_personality (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   char *name, *p, c;
   SKIP_WHITESPACE ();
@@ -3497,7 +3573,7 @@ dot_personality (dummy)
 
 static void
 dot_proc (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   char *name, *p, c;
   symbolS *sym;
@@ -3532,7 +3608,7 @@ dot_proc (dummy)
 
 static void
 dot_body (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   unwind.prologue = 0;
   unwind.prologue_mask = 0;
@@ -3543,10 +3619,10 @@ dot_body (dummy)
 
 static void
 dot_prologue (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   unsigned char sep;
-  int mask = 0, grsave;
+  int mask = 0, grsave = 0;
 
   if (!is_it_end_of_statement ())
     {
@@ -3584,10 +3660,11 @@ dot_prologue (dummy)
 
 static void
 dot_endp (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS e;
   unsigned char *ptr;
+  int bytes_per_address;
   long where;
   segT saved_seg;
   subsegT saved_subseg;
@@ -3610,21 +3687,26 @@ dot_endp (dummy)
   unwind.proc_end = expr_build_dot ();
 
   set_section ((char *) special_section_name[SPECIAL_SECTION_UNWIND]);
+
+  /* Make sure the section has 8 byte alignment.  */
+  record_alignment (now_seg, 3);
+
   ptr = frag_more (24);
   where = frag_now_fix () - 24;
+  bytes_per_address = bfd_arch_bits_per_address (stdoutput) / 8;
 
   /* Issue the values of  a) Proc Begin,  b) Proc End,  c) Unwind Record.  */
   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;
-  ia64_cons_fix_new (frag_now, where, 8, &e);
+  ia64_cons_fix_new (frag_now, where, bytes_per_address, &e);
 
   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_end;
-  ia64_cons_fix_new (frag_now, where + 8, 8, &e);
+  ia64_cons_fix_new (frag_now, where + bytes_per_address, bytes_per_address, &e);
 
   if (unwind.info != 0)
     {
@@ -3632,10 +3714,10 @@ dot_endp (dummy)
       e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
       e.X_add_number = 0;
       e.X_add_symbol = unwind.info;
-      ia64_cons_fix_new (frag_now, where + 16, 8, &e);
+      ia64_cons_fix_new (frag_now, where + (bytes_per_address * 2), bytes_per_address, &e);
     }
   else
-    md_number_to_chars (ptr + 16, 0, 8);
+    md_number_to_chars (ptr + (bytes_per_address * 2), 0, bytes_per_address);
 
   subseg_set (saved_seg, saved_subseg);
   unwind.proc_start = unwind.proc_end = unwind.info = 0;
@@ -3650,7 +3732,7 @@ dot_template (template)
 
 static void
 dot_regstk (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   int ins, locs, outs, rots;
 
@@ -3801,7 +3883,7 @@ dot_byteorder (byteorder)
 
 static void
 dot_psr (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   char *option;
   int ch;
@@ -3834,14 +3916,14 @@ dot_psr (dummy)
 
 static void
 dot_alias (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   as_bad (".alias not implemented yet");
 }
 
 static void
 dot_ln (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   new_logical_line (0, get_absolute_expression ());
   demand_empty_rest_of_line ();
@@ -3985,7 +4067,7 @@ dot_xfloat_cons_ua (kind)
 
 static void
 dot_reg_val (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   expressionS reg;
 
@@ -4238,7 +4320,7 @@ dot_pred_rel (type)
 
 static void
 dot_entry (dummy)
-     int dummy;
+     int dummy ATTRIBUTE_UNUSED;
 {
   const char *err;
   char *name;
@@ -4277,7 +4359,7 @@ dot_entry (dummy)
 
 static void
 dot_mem_offset (dummy)
-  int dummy;
+  int dummy ATTRIBUTE_UNUSED;
 {
   md.mem_offset.hint = 1;
   md.mem_offset.offset = get_absolute_expression ();
@@ -4307,40 +4389,40 @@ const pseudo_typeS md_pseudo_table[] =
     { "proc", dot_proc, 0 },
     { "body", dot_body, 0 },
     { "prologue", dot_prologue, 0 },
-    { "endp", dot_endp },
-    { "file", dwarf2_directive_file },
-    { "loc", dwarf2_directive_loc },
-
-    { "fframe", dot_fframe },
-    { "vframe", dot_vframe },
-    { "vframesp", dot_vframesp },
-    { "vframepsp", dot_vframepsp },
-    { "save", dot_save },
-    { "restore", dot_restore },
-    { "restorereg", dot_restorereg },
-    { "restorereg.p", dot_restorereg_p },
-    { "handlerdata", dot_handlerdata },
-    { "unwentry", dot_unwentry },
-    { "altrp", dot_altrp },
+    { "endp", dot_endp, 0 },
+    { "file", dwarf2_directive_file, 0 },
+    { "loc", dwarf2_directive_loc, 0 },
+
+    { "fframe", dot_fframe, 0 },
+    { "vframe", dot_vframe, 0 },
+    { "vframesp", dot_vframesp, 0 },
+    { "vframepsp", dot_vframepsp, 0 },
+    { "save", dot_save, 0 },
+    { "restore", dot_restore, 0 },
+    { "restorereg", dot_restorereg, 0 },
+    { "restorereg.p", dot_restorereg_p, 0 },
+    { "handlerdata", dot_handlerdata, 0 },
+    { "unwentry", dot_unwentry, 0 },
+    { "altrp", dot_altrp, 0 },
     { "savesp", dot_savemem, 0 },
     { "savepsp", dot_savemem, 1 },
-    { "save.g", dot_saveg },
-    { "save.f", dot_savef },
-    { "save.b", dot_saveb },
-    { "save.gf", dot_savegf },
-    { "spill", dot_spill },
-    { "spillreg", dot_spillreg },
+    { "save.g", dot_saveg, 0 },
+    { "save.f", dot_savef, 0 },
+    { "save.b", dot_saveb, 0 },
+    { "save.gf", dot_savegf, 0 },
+    { "spill", dot_spill, 0 },
+    { "spillreg", dot_spillreg, 0 },
     { "spillsp", dot_spillmem, 0 },
     { "spillpsp", dot_spillmem, 1 },
-    { "spillreg.p", dot_spillreg_p },
+    { "spillreg.p", dot_spillreg_p, 0 },
     { "spillsp.p", dot_spillmem_p, 0 },
     { "spillpsp.p", dot_spillmem_p, 1 },
-    { "label_state", dot_label_state },
-    { "copy_state", dot_copy_state },
-    { "unwabi", dot_unwabi },
-    { "personality", dot_personality },
+    { "label_state", dot_label_state, 0 },
+    { "copy_state", dot_copy_state, 0 },
+    { "unwabi", dot_unwabi, 0 },
+    { "personality", dot_personality, 0 },
 #if 0
-    { "estate", dot_estate },
+    { "estate", dot_estate, 0 },
 #endif
     { "mii", dot_template, 0x0 },
     { "mli", dot_template, 0x2 }, /* old format, for compatibility */
@@ -4388,13 +4470,13 @@ const pseudo_typeS md_pseudo_table[] =
 
     /* annotations/DV checking support */
     { "entry", dot_entry, 0 },
-    { "mem.offset", dot_mem_offset },
+    { "mem.offset", dot_mem_offset, 0 },
     { "pred.rel", dot_pred_rel, 0 },
     { "pred.rel.clear", dot_pred_rel, 'c' },
     { "pred.rel.imply", dot_pred_rel, 'i' },
     { "pred.rel.mutex", dot_pred_rel, 'm' },
     { "pred.safe_across_calls", dot_pred_rel, 's' },
-    { "reg.val", dot_reg_val },
+    { "reg.val", dot_reg_val, 0 },
     { "auto", dot_dv_mode, 'a' },
     { "explicit", dot_dv_mode, 'e' },
     { "default", dot_dv_mode, 'd' },
@@ -4739,9 +4821,9 @@ operand_match (idesc, index, e)
 
       if (e->X_op == O_constant
          && ((e->X_add_number >= 0
-              && e->X_add_number < ((bfd_vma) 1 << 44))
+              && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 44))
              || (e->X_add_number < 0
-                 && -e->X_add_number <= ((bfd_vma) 1 << 44))))
+                 && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 44))))
        {
          /* sign-extend */
          if (e->X_add_number >= 0
@@ -4757,9 +4839,9 @@ operand_match (idesc, index, e)
       /* bit 0 is a don't care (pr0 is hardwired to 1) */
       if (e->X_op == O_constant
          && ((e->X_add_number >= 0
-              && e->X_add_number < ((bfd_vma) 1 << 17))
+              && (bfd_vma) e->X_add_number < ((bfd_vma) 1 << 17))
              || (e->X_add_number < 0
-                 && -e->X_add_number <= ((bfd_vma) 1 << 17))))
+                 && (bfd_vma) -e->X_add_number <= ((bfd_vma) 1 << 17))))
        {
          /* sign-extend */
          if (e->X_add_number >= 0
@@ -4868,8 +4950,8 @@ operand_match (idesc, index, e)
       else
        val = e->X_add_number;
 
-      if ((val >= 0 && val < ((bfd_vma) 1 << (bits - 1)))
-         || (val < 0 && -val <= ((bfd_vma) 1 << (bits - 1))))
+      if ((val >= 0 && (bfd_vma) val < ((bfd_vma) 1 << (bits - 1)))
+         || (val < 0 && (bfd_vma) -val <= ((bfd_vma) 1 << (bits - 1))))
        return 1;
       break;
 
@@ -5103,6 +5185,95 @@ parse_operands (idesc)
   return idesc;
 }
 
+/* Keep track of state necessary to determine whether a NOP is necessary
+   to avoid an erratum in A and B step Itanium chips, and return 1 if we
+   detect a case where additional NOPs may be necessary.  */
+static int
+errata_nop_necessary_p (slot, insn_unit)
+     struct slot *slot;
+     enum ia64_unit insn_unit;
+{
+  int i;
+  struct group *this_group = md.last_groups + md.group_idx;
+  struct group *prev_group = md.last_groups + (md.group_idx + 2) % 3;
+  struct ia64_opcode *idesc = slot->idesc;
+
+  /* Test whether this could be the first insn in a problematic sequence.  */
+  if (insn_unit == IA64_UNIT_F)
+    {
+      for (i = 0; i < idesc->num_outputs; i++)
+       if (idesc->operands[i] == IA64_OPND_P1
+           || idesc->operands[i] == IA64_OPND_P2)
+         {
+           int regno = slot->opnd[i].X_add_number - REG_P;
+           if (regno >= 64)
+             abort ();
+           this_group->p_reg_set[regno] = 1;
+         }
+    }
+
+  /* Test whether this could be the second insn in a problematic sequence.  */
+  if (insn_unit == IA64_UNIT_M && slot->qp_regno > 0
+      && prev_group->p_reg_set[slot->qp_regno])
+    {
+      for (i = 0; i < idesc->num_outputs; i++)
+       if (idesc->operands[i] == IA64_OPND_R1
+           || idesc->operands[i] == IA64_OPND_R2
+           || idesc->operands[i] == IA64_OPND_R3)
+         {
+           int regno = slot->opnd[i].X_add_number - REG_GR;
+           if (regno >= 128)
+             abort ();
+           if (strncmp (idesc->name, "add", 3) != 0
+               && strncmp (idesc->name, "sub", 3) != 0
+               && strncmp (idesc->name, "shladd", 6) != 0
+               && (idesc->flags & IA64_OPCODE_POSTINC) == 0)
+             this_group->g_reg_set_conditionally[regno] = 1;
+         }
+    }
+
+  /* Test whether this could be the third insn in a problematic sequence.  */
+  for (i = 0; i < NELEMS (idesc->operands) && idesc->operands[i]; i++)
+    {
+      if (/* For fc, ptc, ptr, tak, thash, tpa, ttag, probe, ptr, ptc.  */
+         idesc->operands[i] == IA64_OPND_R3
+         /* For mov indirect.  */
+         || idesc->operands[i] == IA64_OPND_RR_R3
+         || idesc->operands[i] == IA64_OPND_DBR_R3
+         || idesc->operands[i] == IA64_OPND_IBR_R3
+         || idesc->operands[i] == IA64_OPND_PKR_R3
+         || idesc->operands[i] == IA64_OPND_PMC_R3
+         || idesc->operands[i] == IA64_OPND_PMD_R3
+         || idesc->operands[i] == IA64_OPND_MSR_R3
+         || idesc->operands[i] == IA64_OPND_CPUID_R3
+         /* For itr.  */
+         || idesc->operands[i] == IA64_OPND_ITR_R3
+         || idesc->operands[i] == IA64_OPND_DTR_R3
+         /* Normal memory addresses (load, store, xchg, cmpxchg, etc.).  */
+         || idesc->operands[i] == IA64_OPND_MR3)
+       {
+         int regno = slot->opnd[i].X_add_number - REG_GR;
+         if (regno >= 128)
+           abort ();
+         if (idesc->operands[i] == IA64_OPND_R3)
+           {
+             if (strcmp (idesc->name, "fc") != 0
+                 && strcmp (idesc->name, "tak") != 0
+                 && strcmp (idesc->name, "thash") != 0
+                 && strcmp (idesc->name, "tpa") != 0
+                 && strcmp (idesc->name, "ttag") != 0
+                 && strncmp (idesc->name, "ptr", 3) != 0
+                 && strncmp (idesc->name, "ptc", 3) != 0
+                 && strncmp (idesc->name, "probe", 5) != 0)
+             return 0;
+           }
+         if (prev_group->g_reg_set_conditionally[regno])
+           return 1;
+       }
+    }
+  return 0;
+}
+
 static void
 build_insn (slot, insnp)
      struct slot *slot;
@@ -5239,7 +5410,7 @@ emit_one_bundle ()
   struct ia64_opcode *idesc;
   int end_of_insn_group = 0, user_template = -1;
   int n, i, j, first, curr;
-  unw_rec_list *ptr, *prev;
+  unw_rec_list *ptr;
   bfd_vma t0 = 0, t1 = 0;
   struct label_fix *lfix;
   struct insn_fix *ifix;
@@ -5291,7 +5462,10 @@ emit_one_bundle ()
       for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next)
        if (ptr->r.type == prologue || ptr->r.type == prologue_gr
            || ptr->r.type == body)
-         ptr->slot_number = (unsigned long) f + i;
+         {
+           ptr->slot_number = (unsigned long) f + i;
+           ptr->slot_frag = frag_now;
+         }
 
       if (idesc->flags & IA64_OPCODE_SLOT2)
        {
@@ -5303,7 +5477,8 @@ emit_one_bundle ()
        }
       if (idesc->flags & IA64_OPCODE_LAST)
        {
-         int required_slot, required_template;
+         int required_slot;
+         unsigned int required_template;
 
          /* If we need a stop bit after an M slot, our only choice is
             template 5 (M;;MI).  If we need a stop bit after a B
@@ -5482,7 +5657,6 @@ emit_one_bundle ()
          continue;             /* try next slot */
        }
 
-      if (debug_type == DEBUG_DWARF2)
        {
          bfd_vma addr;
 
@@ -5490,15 +5664,20 @@ emit_one_bundle ()
          dwarf2_gen_line_info (addr, &md.slot[curr].debug_line);
        }
 
+      if (errata_nop_necessary_p (md.slot + curr, insn_unit))
+       as_warn (_("Additional NOP may be necessary to workaround Itanium processor A/B step errata"));
+
       build_insn (md.slot + curr, insn + i);
 
       /* Set slot counts for non prologue/body unwind records.  */
       for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next)
        if (ptr->r.type != prologue && ptr->r.type != prologue_gr
            && ptr->r.type != body)
-         ptr->slot_number = (unsigned long) f + i;
+         {
+           ptr->slot_number = (unsigned long) f + i;
+           ptr->slot_frag = frag_now;
+         }
       md.slot[curr].unwind_record = NULL;
-      unwind.next_slot_number = (unsigned long) f + i + ((i == 2)?(0x10-2):1);
 
       if (required_unit == IA64_UNIT_L)
        {
@@ -5524,7 +5703,7 @@ emit_one_bundle ()
       for (j = 0; j < md.slot[curr].num_fixups; ++j)
        {
          ifix = md.slot[curr].fixup + j;
-         fix = fix_new_exp (frag_now, frag_now_fix () - 16 + i, 4,
+         fix = fix_new_exp (frag_now, frag_now_fix () - 16 + i, 8,
                             &ifix->expr, ifix->is_pcrel, ifix->code);
          fix->tc_fix_data.opnd = ifix->opnd;
          fix->fx_plt = (fix->fx_r_type == BFD_RELOC_IA64_PLTOFF22);
@@ -5534,6 +5713,12 @@ emit_one_bundle ()
 
       end_of_insn_group = md.slot[curr].end_of_insn_group;
 
+      if (end_of_insn_group)
+       {
+         md.group_idx = (md.group_idx + 1) % 3;
+         memset (md.last_groups + md.group_idx, 0, sizeof md.last_groups[0]);
+       }
+
       /* clear slot:  */
       ia64_free_opcode (md.slot[curr].idesc);
       memset (md.slot + curr, 0, sizeof (md.slot[curr]));
@@ -5562,8 +5747,11 @@ emit_one_bundle ()
   t0 = end_of_insn_group | (template << 1) | (insn[0] << 5) | (insn[1] << 46);
   t1 = ((insn[1] >> 18) & 0x7fffff) | (insn[2] << 23);
 
-  md_number_to_chars (f + 0, t0, 8);
-  md_number_to_chars (f + 8, t1, 8);
+  number_to_chars_littleendian (f + 0, t0, 8);
+  number_to_chars_littleendian (f + 8, t1, 8);
+
+  unwind.next_slot_number = (unsigned long) f + 16;
+  unwind.next_slot_frag = frag_now;
 }
 
 int
@@ -5574,7 +5762,7 @@ md_parse_option (c, arg)
   switch (c)
     {
     /* Switches from the Intel assembler.  */
-    case 'M':
+    case 'm':
       if (strcmp (arg, "ilp64") == 0
          || strcmp (arg, "lp64") == 0
          || strcmp (arg, "p64") == 0)
@@ -5688,8 +5876,8 @@ md_show_usage (stream)
 {
   fputs (_("\
 IA-64 options:\n\
-  -Milp32|-Milp64|-Mlp64|-Mp64 select data model (default -Mlp64)\n\
-  -Mle | -Mbe            select little- or big-endian byte order (default -Mle)\n\
+  -milp32|-milp64|-mlp64|-mp64 select data model (default -mlp64)\n\
+  -mle | -mbe            select little- or big-endian byte order (default -mle)\n\
   -x | -xexplicit        turn on dependency violation checking (default)\n\
   -xauto                 automagically remove dependency violations\n\
   -xdebug                debug dependency violation checker\n"),
@@ -5740,7 +5928,7 @@ extra_goodness (int templ, int slot)
 void
 md_begin ()
 {
-  int i, j, k, t, total, ar_base, cr_base, goodness, best, regnum;
+  int i, j, k, t, total, ar_base, cr_base, goodness, best, regnum, ok;
   const char *err;
   char name[8];
 
@@ -5749,7 +5937,7 @@ md_begin ()
 
   bfd_set_section_alignment (stdoutput, text_section, 4);
 
-  target_big_endian = 0;
+  target_big_endian = TARGET_BYTES_BIG_ENDIAN;
   pseudo_func[FUNC_FPTR_RELATIVE].u.sym =
     symbol_new (".<fptr>", undefined_section, FUNC_FPTR_RELATIVE,
                &zero_address_frag);
@@ -5948,9 +6136,15 @@ md_begin ()
                  name, err);
     }
 
-  /* Default to 64-bit mode.  */
-  /* ??? This overrides the -M options, but they aren't working anyways.  */
-  md.flags |= EF_IA_64_ABI64;
+  /* Set the architecture and machine depending on defaults and command line
+     options.  */
+  if (md.flags & EF_IA_64_ABI64)
+    ok = bfd_set_arch_mach (stdoutput, bfd_arch_ia64, bfd_mach_ia64_elf64);
+  else
+    ok = bfd_set_arch_mach (stdoutput, bfd_arch_ia64, bfd_mach_ia64_elf32);
+
+  if (! ok)
+     as_warn (_("Could not set architecture and machine"));
 
   md.mem_offset.hint = 0;
   md.path = 0;
@@ -5958,6 +6152,47 @@ md_begin ()
   md.entry_labels = NULL;
 }
 
+/* Set the elf type to 64 bit ABI by default.  Cannot do this in md_begin
+   because that is called after md_parse_option which is where we do the
+   dynamic changing of md.flags based on -mlp64 or -milp32.  Also, set the
+   default endianness.  */
+
+void
+ia64_init (argc, argv)
+     int argc ATTRIBUTE_UNUSED;
+     char **argv ATTRIBUTE_UNUSED;
+{
+  md.flags = EF_IA_64_ABI64;
+  if (TARGET_BYTES_BIG_ENDIAN)
+    md.flags |= EF_IA_64_BE;
+}
+
+/* Return a string for the target object file format.  */
+
+const char *
+ia64_target_format ()
+{
+  if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+    {
+      if (md.flags & EF_IA_64_BE)
+       {
+         if (md.flags & EF_IA_64_ABI64)
+           return "elf64-ia64-big";
+         else
+           return "elf32-ia64-big";
+       }
+      else
+       {
+         if (md.flags & EF_IA_64_ABI64)
+           return "elf64-ia64-little";
+         else
+           return "elf32-ia64-little";
+       }
+    }
+  else
+    return "unknown-format";
+}
+
 void
 ia64_end_of_source ()
 {
@@ -5969,9 +6204,6 @@ ia64_end_of_source ()
 
   bfd_set_private_flags (stdoutput, md.flags);
 
-  if (debug_type == DEBUG_DWARF2)
-    dwarf2_finish ();
-
   md.mem_offset.hint = 0;
 }
 
@@ -6726,7 +6958,7 @@ dep->name, idesc->name, (rsrc_write?"write":"read"), note)
                    for (i = 0; i < NELEMS (gr_values); i++)
                      {
                        /* Uses all registers *except* the one in R3.  */
-                       if (i != (gr_values[regno].value & 0xFF))
+                       if ((unsigned)i != (gr_values[regno].value & 0xFF))
                          {
                            specs[count] = tmpl;
                            specs[count++].index = i;
@@ -8071,8 +8303,11 @@ note_register_values (idesc)
          gr_values[regno].value = CURR_SLOT.opnd[1].X_add_number;
          gr_values[regno].path = md.path;
          if (md.debug_dv)
-           fprintf (stderr, "  Know gr%d = 0x%llx\n",
-                    regno, gr_values[regno].value);
+           {
+             fprintf (stderr, "  Know gr%d = ", regno);
+             fprintf_vma (stderr, gr_values[regno].value);
+             fputs ("\n", stderr);
+           }
        }
     }
   else
@@ -8264,8 +8499,8 @@ insn_group_break (insert_stop, qp_regno, save_current)
 
 static void
 mark_resource (idesc, dep, spec, depind, path)
-     struct ia64_opcode *idesc;
-     const struct ia64_dependency *dep;
+     struct ia64_opcode *idesc ATTRIBUTE_UNUSED;
+     const struct ia64_dependency *dep ATTRIBUTE_UNUSED;
      struct rsrc *spec;
      int depind;
      int path;
@@ -8275,7 +8510,7 @@ mark_resource (idesc, dep, spec, depind, path)
       regdepstotlen += 20;
       regdeps = (struct rsrc *)
        xrealloc ((void *) regdeps,
-                 regdepstotlen * sizeof(struct rsrc));
+                 regdepstotlen * sizeof (struct rsrc));
     }
 
   regdeps[regdepslen] = *spec;
@@ -8302,9 +8537,12 @@ print_dependency (action, depind)
       if (regdeps[depind].specific && regdeps[depind].index != 0)
        fprintf (stderr, " (%d)", regdeps[depind].index);
       if (regdeps[depind].mem_offset.hint)
-       fprintf (stderr, " 0x%llx+0x%llx",
-                regdeps[depind].mem_offset.base,
-                regdeps[depind].mem_offset.offset);
+       {
+         fputs (" ", stderr);
+         fprintf_vma (stderr, regdeps[depind].mem_offset.base);
+         fputs ("+", stderr);
+         fprintf_vma (stderr, regdeps[depind].mem_offset.offset);
+       }
       fprintf (stderr, "\n");
     }
 }
@@ -8860,8 +9098,7 @@ md_assemble (str)
   CURR_SLOT.qp_regno = qp_regno;
   CURR_SLOT.idesc = idesc;
   as_where (&CURR_SLOT.src_file, &CURR_SLOT.src_line);
-  if (debug_type == DEBUG_DWARF2)
-    dwarf2_where (&CURR_SLOT.debug_line);
+  dwarf2_where (&CURR_SLOT.debug_line);
 
   /* Add unwind entry, if there is one.  */
   if (unwind.current_entry)
@@ -8892,7 +9129,7 @@ md_assemble (str)
 
 symbolS *
 md_undefined_symbol (name)
-     char *name;
+     char *name ATTRIBUTE_UNUSED;
 {
   return 0;
 }
@@ -9345,8 +9582,8 @@ fix_insn (fix, odesc, value)
 
   t0 = control_bits | (insn[0] << 5) | (insn[1] << 46);
   t1 = ((insn[1] >> 18) & 0x7fffff) | (insn[2] << 23);
-  md_number_to_chars (fixpos + 0, t0, 8);
-  md_number_to_chars (fixpos + 8, t1, 8);
+  number_to_chars_littleendian (fixpos + 0, t0, 8);
+  number_to_chars_littleendian (fixpos + 8, t1, 8);
 }
 
 /* Attempt to simplify or even eliminate a fixup.  The return value is
@@ -9359,7 +9596,7 @@ int
 md_apply_fix3 (fix, valuep, seg)
      fixS *fix;
      valueT *valuep;
-     segT seg;
+     segT seg ATTRIBUTE_UNUSED;
 {
   char *fixpos;
   valueT value = *valuep;
@@ -9437,7 +9674,7 @@ md_apply_fix3 (fix, valuep, seg)
 
 arelent *
 tc_gen_reloc (sec, fixp)
-     asection *sec;
+     asection *sec ATTRIBUTE_UNUSED;
      fixS *fixp;
 {
   arelent *reloc;
@@ -9531,42 +9768,52 @@ md_section_align (seg, size)
 
 /* Handle ia64 specific semantics of the align directive.  */
 
-int
+void
 ia64_md_do_align (n, fill, len, max)
      int n;
      const char *fill;
-     int len;
+     int len ATTRIBUTE_UNUSED;
      int max;
 {
-  /* Fill any pending bundle with nops.  */
-  if (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE)
+  if (subseg_text_p (now_seg))
     ia64_flush_insns ();
+}
 
-  /* When we align code in a text section, emit a bundle of 3 nops instead of
-     zero bytes.  We can only do this if a multiple of 16 bytes was requested.
-     N is log base 2 of the requested alignment.  */
-  if (fill == NULL
-      && bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE
-      && n > 4)
-    {
-      /* Use mfi bundle of nops with no stop bits.  */
-      static const unsigned char be_nop[]
-       = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
-           0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c};
-      static const unsigned char le_nop[]
-       = { 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-           0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
-
-      /* Make sure we are on a 16-byte boundary, in case someone has been
-        putting data into a text section.  */
-      frag_align (4, 0, 0);
+/* This is called from HANDLE_ALIGN in write.c.  Fill in the contents
+   of an rs_align_code fragment.  */
 
-      if (target_big_endian)
-       frag_align_pattern (n, be_nop, 16, max);
-      else
-       frag_align_pattern (n, le_nop, 16, max);
-      return 1;
+void
+ia64_handle_align (fragp)
+     fragS *fragp;
+{
+  /* Use mfi bundle of nops with no stop bits.  */
+  static const unsigned char be_nop[]
+    = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+       0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c};
+  static const unsigned char le_nop[]
+    = { 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+       0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
+
+  int bytes;
+  char *p;
+
+  if (fragp->fr_type != rs_align_code)
+    return;
+
+  bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
+  p = fragp->fr_literal + fragp->fr_fix;
+
+  /* Make sure we are on a 16-byte boundary, in case someone has been
+     putting data into a text section.  */
+  if (bytes & 15)
+    {
+      int fix = bytes & 15;
+      memset (p, 0, fix);
+      p += fix;
+      bytes -= fix;
+      fragp->fr_fix += fix;
     }
 
-  return 0;
+  memcpy (p, (target_big_endian ? be_nop : le_nop), 16);
+  fragp->fr_var = 16;
 }
This page took 0.040442 seconds and 4 git commands to generate.