/* ia64-specific option processing: */
-const char *md_shortopts = "M:N:x::";
+const char *md_shortopts = "m:N:x::";
struct option md_longopts[] =
{
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;
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 } },
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 */
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;
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 *));
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;
output_vbyte_mem (count, ptr, comment)
int count;
char *ptr;
- char *comment;
+ char *comment ATTRIBUTE_UNUSED;
{
int x;
if (vbyte_mem_ptr == NULL)
void
count_output (count, ptr, comment)
int count;
- char *ptr;
- char *comment;
+ char *ptr ATTRIBUTE_UNUSED;
+ char *comment ATTRIBUTE_UNUSED;
{
vbyte_count += count;
}
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
{
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:
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)
if (ptr->r.type != body)
{
last_addr = last->slot_number;
+ last_frag = last->slot_frag;
switch (last->r.type)
{
case frgr_mem:
}
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;
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;
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;
static void
dot_radix (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
int radix;
static void
dot_fframe (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
static void
dot_vframe (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
unsigned reg;
static void
dot_vframesp (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
static void
dot_vframepsp (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
static void
dot_save (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e1, e2;
int sep;
static void
dot_restore (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e1, e2;
unsigned long ecount = 0;
static void
dot_restorereg (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
unsigned int ab, reg;
expressionS e;
static void
dot_restorereg_p (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
unsigned int qp, ab, reg;
expressionS e1, e2;
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 ();
static void
dot_handlerdata (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
generate_unwind_image ();
demand_empty_rest_of_line ();
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;
static void
dot_saveg (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e1, e2;
int sep;
static void
dot_savef (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e1;
int sep;
static void
dot_saveb (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e1, e2;
unsigned int reg;
static void
dot_savegf (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e1, e2;
int sep;
static void
dot_spill (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
unsigned char sep;
static void
dot_spillreg (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
int sep, ab, xy, reg, treg;
expressionS e1, e2;
static void
dot_spillreg_p (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
int sep, ab, xy, reg, treg;
expressionS e1, e2, e3;
static void
dot_label_state (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
static void
dot_copy_state (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
static void
dot_unwabi (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS e1, e2;
unsigned char sep;
static void
dot_personality (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
char *name, *p, c;
SKIP_WHITESPACE ();
static void
dot_proc (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
char *name, *p, c;
symbolS *sym;
static void
dot_body (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
unwind.prologue = 0;
unwind.prologue_mask = 0;
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 ())
{
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;
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)
{
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;
static void
dot_regstk (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
int ins, locs, outs, rots;
static void
dot_psr (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
char *option;
int ch;
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 ();
static void
dot_reg_val (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
expressionS reg;
static void
dot_entry (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
const char *err;
char *name;
static void
dot_mem_offset (dummy)
- int dummy;
+ int dummy ATTRIBUTE_UNUSED;
{
md.mem_offset.hint = 1;
md.mem_offset.offset = get_absolute_expression ();
{ "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 */
/* 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' },
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
/* 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
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;
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;
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;
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)
{
}
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
continue; /* try next slot */
}
- if (debug_type == DEBUG_DWARF2)
{
bfd_vma addr;
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)
{
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);
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]));
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
switch (c)
{
/* Switches from the Intel assembler. */
- case 'M':
+ case 'm':
if (strcmp (arg, "ilp64") == 0
|| strcmp (arg, "lp64") == 0
|| strcmp (arg, "p64") == 0)
{
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"),
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];
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);
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;
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 ()
{
bfd_set_private_flags (stdoutput, md.flags);
- if (debug_type == DEBUG_DWARF2)
- dwarf2_finish ();
-
md.mem_offset.hint = 0;
}
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;
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
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;
regdepstotlen += 20;
regdeps = (struct rsrc *)
xrealloc ((void *) regdeps,
- regdepstotlen * sizeof(struct rsrc));
+ regdepstotlen * sizeof (struct rsrc));
}
regdeps[regdepslen] = *spec;
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");
}
}
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)
symbolS *
md_undefined_symbol (name)
- char *name;
+ char *name ATTRIBUTE_UNUSED;
{
return 0;
}
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
md_apply_fix3 (fix, valuep, seg)
fixS *fix;
valueT *valuep;
- segT seg;
+ segT seg ATTRIBUTE_UNUSED;
{
char *fixpos;
valueT value = *valuep;
arelent *
tc_gen_reloc (sec, fixp)
- asection *sec;
+ asection *sec ATTRIBUTE_UNUSED;
fixS *fixp;
{
arelent *reloc;
/* 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;
}