that are predicatable. */
expressionS qp;
+ /* Optimize for which CPU. */
+ enum
+ {
+ itanium1,
+ itanium2
+ } tune;
+
/* What to do when hint.b is used. */
enum
{
}
md;
+/* These are not const, because they are modified to MMI for non-itanium1
+ targets below. */
+/* MFI bundle of nops. */
+static unsigned char le_nop[16] =
+{
+ 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00
+};
+/* MFI bundle of nops with stop-bit. */
+static unsigned char le_nop_stop[16] =
+{
+ 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00
+};
+
/* application registers: */
#define AR_K0 0
static void dot_psr PARAMS ((int));
static void dot_alias PARAMS ((int));
static void dot_ln PARAMS ((int));
-static char *parse_section_name PARAMS ((void));
+static void cross_section PARAMS ((int ref, void (*cons) PARAMS((int)), int ua));
static void dot_xdata PARAMS ((int));
static void stmt_float_cons PARAMS ((int));
static void stmt_cons_ua PARAMS ((int));
}
/* Output COUNT bytes to a memory location. */
-static unsigned char *vbyte_mem_ptr = NULL;
+static char *vbyte_mem_ptr = NULL;
void
output_vbyte_mem (count, ptr, comment)
unsigned long imask_size;
{
imask[0] = UNW_P4;
- (*f) (imask_size, imask, NULL);
+ (*f) (imask_size, (char *) imask, NULL);
}
static void
};
static void
-start_unwind_section (const segT text_seg, int sec_index, int linkonce_empty)
+start_unwind_section (const segT text_seg, int sec_index)
{
/*
Use a slightly ugly scheme to derive the unwind section names from
prefix = special_linkonce_name [sec_index - SPECIAL_SECTION_UNWIND];
suffix += sizeof (".gnu.linkonce.t.") - 1;
}
- else if (linkonce_empty)
- return;
prefix_len = strlen (prefix);
suffix_len = strlen (suffix);
expressionS exp;
bfd_reloc_code_real_type reloc;
- start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 0);
+ start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO);
/* Make sure the section has 4 byte alignment for ILP32 and
8 byte alignment for LP64. */
unwind.personality_routine = 0;
}
}
- else
- start_unwind_section (text_seg, SPECIAL_SECTION_UNWIND_INFO, 1);
free_saved_prologue_counts ();
unwind.list = unwind.tail = unwind.current_entry = NULL;
dot_spillreg (dummy)
int dummy ATTRIBUTE_UNUSED;
{
- int sep, ab, xy, reg, treg;
+ int sep;
+ unsigned int ab, xy, reg, treg;
expressionS e1, e2;
if (!in_procedure ("spillreg"))
int psprel;
{
expressionS e1, e2;
- int sep, ab, reg;
+ int sep;
+ unsigned int ab, reg;
if (!in_procedure ("spillmem"))
return;
dot_spillreg_p (dummy)
int dummy ATTRIBUTE_UNUSED;
{
- int sep, ab, xy, reg, treg;
+ int sep;
+ unsigned int ab, xy, reg, treg;
expressionS e1, e2, e3;
unsigned int qp;
int psprel;
{
expressionS e1, e2, e3;
- int sep, ab, reg;
+ int sep;
+ unsigned int ab, reg;
unsigned int qp;
if (!in_procedure ("spillmem.p"))
int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
- unsigned char *ptr;
+ char *ptr;
int bytes_per_address;
long where;
segT saved_seg;
subseg_set (md.last_text_seg, 0);
proc_end = expr_build_dot ();
- start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
+ start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND);
/* Make sure that section has 4 byte alignment for ILP32 and
8 byte alignment for LP64. */
bytes_per_address);
}
- else
- start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 1);
-
subseg_set (saved_seg, saved_subseg);
if (unwind.proc_start)
demand_empty_rest_of_line ();
}
-static char *
-parse_section_name ()
+static void
+cross_section (ref, cons, ua)
+ int ref;
+ void (*cons) PARAMS((int));
+ int ua;
{
- char *name;
- int len;
+ char *start, *end;
+ int saved_auto_align;
+ unsigned int section_count;
SKIP_WHITESPACE ();
- if (*input_line_pointer == '"')
+ start = input_line_pointer;
+ if (*start == '"')
+ {
+ int len;
+ char *name;
+
name = demand_copy_C_string (&len);
+ obstack_free(¬es, name);
+ if (!name)
+ {
+ ignore_rest_of_line ();
+ return;
+ }
+ }
else
{
- char *start = input_line_pointer;
char c = get_symbol_end ();
if (input_line_pointer == start)
{
as_bad ("Missing section name");
ignore_rest_of_line ();
- return 0;
+ return;
}
- name = obstack_copy (¬es, start, input_line_pointer - start + 1);
*input_line_pointer = c;
}
- if (!name)
- {
- ignore_rest_of_line ();
- return 0;
- }
+ end = input_line_pointer;
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
{
as_bad ("Comma expected after section name");
ignore_rest_of_line ();
- return 0;
+ return;
}
- ++input_line_pointer; /* skip comma */
- return name;
+ *end = '\0';
+ end = input_line_pointer + 1; /* skip comma */
+ input_line_pointer = start;
+ md.keep_pending_output = 1;
+ section_count = bfd_count_sections(stdoutput);
+ obj_elf_section (0);
+ if (section_count != bfd_count_sections(stdoutput))
+ as_warn ("Creating sections with .xdataN/.xrealN/.xstringZ is deprecated.");
+ input_line_pointer = end;
+ saved_auto_align = md.auto_align;
+ if (ua)
+ md.auto_align = 0;
+ (*cons) (ref);
+ if (ua)
+ md.auto_align = saved_auto_align;
+ obj_elf_previous (0);
+ md.keep_pending_output = 0;
}
static void
dot_xdata (size)
int size;
{
- char *name = parse_section_name ();
- if (!name)
- return;
-
- md.keep_pending_output = 1;
- set_section (name);
- cons (size);
- obj_elf_previous (0);
- md.keep_pending_output = 0;
+ cross_section (size, cons, 0);
}
/* Why doesn't float_cons() call md_cons_align() the way cons() does? */
dot_xfloat_cons (kind)
int kind;
{
- char *name = parse_section_name ();
- if (!name)
- return;
-
- md.keep_pending_output = 1;
- set_section (name);
- stmt_float_cons (kind);
- obj_elf_previous (0);
- md.keep_pending_output = 0;
+ cross_section (kind, stmt_float_cons, 0);
}
static void
dot_xstringer (zero)
int zero;
{
- char *name = parse_section_name ();
- if (!name)
- return;
-
- md.keep_pending_output = 1;
- set_section (name);
- stringer (zero);
- obj_elf_previous (0);
- md.keep_pending_output = 0;
+ cross_section (zero, stringer, 0);
}
static void
dot_xdata_ua (size)
int size;
{
- int saved_auto_align = md.auto_align;
- char *name = parse_section_name ();
- if (!name)
- return;
-
- md.keep_pending_output = 1;
- set_section (name);
- md.auto_align = 0;
- cons (size);
- md.auto_align = saved_auto_align;
- obj_elf_previous (0);
- md.keep_pending_output = 0;
+ cross_section (size, cons, 1);
}
static void
dot_xfloat_cons_ua (kind)
int kind;
{
- int saved_auto_align = md.auto_align;
- char *name = parse_section_name ();
- if (!name)
- return;
-
- md.keep_pending_output = 1;
- set_section (name);
- md.auto_align = 0;
- stmt_float_cons (kind);
- md.auto_align = saved_auto_align;
- obj_elf_previous (0);
- md.keep_pending_output = 0;
+ cross_section (kind, float_cons, 1);
}
/* .reg.val <regname>,value */
{
const struct ia64_operand *odesc, *o2desc;
struct ia64_opcode *idesc = slot->idesc;
- bfd_signed_vma insn, val;
+ bfd_vma insn;
+ bfd_signed_vma val;
const char *err;
int i;
bfd_vma insn[3] = { -1, -1, -1 };
struct ia64_opcode *idesc;
int end_of_insn_group = 0, user_template = -1;
- int n, i, j, first, curr;
+ int n, i, j, first, curr, last_slot;
unw_rec_list *ptr, *last_ptr, *end_ptr;
bfd_vma t0 = 0, t1 = 0;
struct label_fix *lfix;
curr = first;
idesc = md.slot[curr].idesc;
end_of_insn_group = 0;
+ last_slot = -1;
for (i = 0; i < 3 && md.num_slots_in_use > 0; ++i)
{
/* If we have unwind records, we may need to update some now. */
}
if (insn_unit != required_unit)
- {
- if (required_unit == IA64_UNIT_L
- && insn_unit == IA64_UNIT_I
- && !(idesc->flags & IA64_OPCODE_X_IN_MLX))
- {
- /* we got ourselves an MLX template but the current
- instruction isn't an X-unit, or an I-unit instruction
- that can go into the X slot of an MLX template. Duh. */
- if (md.num_slots_in_use >= NUM_SLOTS)
- {
- as_bad_where (md.slot[curr].src_file,
- md.slot[curr].src_line,
- "`%s' can't go in X slot of "
- "MLX template", idesc->name);
- /* drop this insn so we don't livelock: */
- --md.num_slots_in_use;
- }
- break;
- }
- continue; /* try next slot */
- }
+ continue; /* Try next slot. */
if (debug_type == DEBUG_DWARF2 || md.slot[curr].loc_directive_seen)
{
++i;
}
--md.num_slots_in_use;
+ last_slot = i;
/* now is a good time to fix up the labels for this insn: */
for (lfix = md.slot[curr].label_fixups; lfix; lfix = lfix->next)
{
if (md.num_slots_in_use > 0)
{
- as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
- "`%s' does not fit into %s template",
- idesc->name, ia64_templ_desc[template].name);
- --md.num_slots_in_use;
+ if (last_slot >= 2)
+ as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+ "`%s' does not fit into bundle", idesc->name);
+ else if (last_slot < 0)
+ {
+ as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+ "`%s' does not fit into %s template",
+ idesc->name, ia64_templ_desc[template].name);
+ /* Drop first insn so we don't livelock. */
+ --md.num_slots_in_use;
+ know (curr == first);
+ ia64_free_opcode (md.slot[curr].idesc);
+ memset (md.slot + curr, 0, sizeof (md.slot[curr]));
+ md.slot[curr].user_template = -1;
+ }
+ else
+ {
+ const char *where;
+
+ if (template == 2)
+ where = "X slot";
+ else if (last_slot == 0)
+ where = "slots 2 or 3";
+ else
+ where = "slot 3";
+ as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
+ "`%s' can't go in %s of %s template",
+ idesc->name, where, ia64_templ_desc[template].name);
+ }
}
else
as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
else
return 0;
}
+ else if (strncmp (arg, "tune=", 5) == 0)
+ {
+ arg += 5;
+ if (strcmp (arg, "itanium1") == 0)
+ md.tune = itanium1;
+ else if (strcmp (arg, "itanium2") == 0)
+ md.tune = itanium2;
+ else
+ return 0;
+ }
else
return 0;
break;
EF_IA_64_NOFUNCDESC_CONS_GP)\n\
-milp32|-milp64|-mlp64|-mp64 select data model (default -mlp64)\n\
-mle | -mbe select little- or big-endian byte order (default -mle)\n\
+ -mtune=[itanium1|itanium2]\n\
+ tune for a specific CPU (default -mtune=itanium2)\n\
-munwind-check=[warning|error]\n\
unwind directive check (default -munwind-check=warning)\n\
-mhint.b=[ok|warning|error]\n\
static inline int
extra_goodness (int templ, int slot)
{
- if (slot == 1 && match (templ, IA64_TYPE_F, slot))
- return 2;
- if (slot == 2 && match (templ, IA64_TYPE_B, slot))
- return 1;
- return 0;
+ switch (md.tune)
+ {
+ case itanium1:
+ if (slot == 1 && match (templ, IA64_TYPE_F, slot))
+ return 2;
+ else if (slot == 2 && match (templ, IA64_TYPE_B, slot))
+ return 1;
+ else
+ return 0;
+ break;
+ case itanium2:
+ if (match (templ, IA64_TYPE_M, slot)
+ || match (templ, IA64_TYPE_I, slot))
+ /* Favor M- and I-unit NOPs. We definitely want to avoid
+ F-unit and B-unit may cause split-issue or less-than-optimal
+ branch-prediction. */
+ return 2;
+ else
+ return 0;
+ break;
+ default:
+ abort ();
+ return 0;
+ }
}
/* This function is called once, at assembler startup time. It sets
symbol_new (".<iplt>", undefined_section, FUNC_IPLT_RELOC,
&zero_address_frag);
+ if (md.tune != itanium1)
+ {
+ /* Convert MFI NOPs bundles into MMI NOPs bundles. */
+ le_nop[0] = 0x8;
+ le_nop_stop[0] = 0x9;
+ }
+
/* Compute the table of best templates. We compute goodness as a
- base 4 value, in which each match counts for 3, each F counts
- for 2, each B counts for 1. This should maximize the number of
- F and B nops in the chosen bundles, which is good because these
- pipelines are least likely to be overcommitted. */
+ base 4 value, in which each match counts for 3. Match-failures
+ result in NOPs and we use extra_goodness() to pick the execution
+ units that are best suited for issuing the NOP. */
for (i = 0; i < IA64_NUM_TYPES; ++i)
for (j = 0; j < IA64_NUM_TYPES; ++j)
for (k = 0; k < IA64_NUM_TYPES; ++k)
/* FIXME: We should change it to unwind_check_error someday. */
md.unwind_check = unwind_check_warning;
md.hint_b = hint_b_error;
+ md.tune = itanium2;
}
/* Return a string for the target object file format. */
{
if (full > 0)
as_bad ("Standalone `#' is illegal");
- else
- as_bad ("Zero-length symbol is illegal");
}
else if (len < full - 1)
as_warn ("Redundant `#' suffix operators");
ia64_handle_align (fragp)
fragS *fragp;
{
- /* Use mfi bundle of nops with no stop bits. */
- static const unsigned char le_nop[]
- = { 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
- static const unsigned char le_nop_stop[]
- = { 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00};
-
int bytes;
char *p;
const unsigned char *nop;