/* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture.
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
struct hash_control *const_hash; /* constant hash table */
struct hash_control *entry_hash; /* code entry hint hash table */
- symbolS *regsym[REG_NUM];
-
/* If X_op is != O_absent, the registername for the instruction's
qualifying predicate. If NULL, p0 is assumed for instructions
that are predicatable. */
int pointer_size; /* size in bytes of a pointer */
int pointer_size_shift; /* shift size of a pointer for alignment */
+
+ symbolS *indregsym[IND_RR - IND_CPUID + 1];
}
md;
#define AR_BSP 17
#define AR_BSPSTORE 18
#define AR_RNAT 19
+#define AR_FCR 21
+#define AR_EFLAG 24
+#define AR_CSD 25
+#define AR_SSD 26
+#define AR_CFLG 27
+#define AR_FSR 28
+#define AR_FIR 29
+#define AR_FDR 30
+#define AR_CCV 32
#define AR_UNAT 36
#define AR_FPSR 40
#define AR_ITC 44
#define AR_PFS 64
#define AR_LC 65
+#define AR_EC 66
static const struct
{
const char *name;
- int regnum;
+ unsigned int regnum;
}
ar[] =
{
- {"ar.k0", 0}, {"ar.k1", 1}, {"ar.k2", 2}, {"ar.k3", 3},
- {"ar.k4", 4}, {"ar.k5", 5}, {"ar.k6", 6}, {"ar.k7", 7},
- {"ar.rsc", 16}, {"ar.bsp", 17},
- {"ar.bspstore", 18}, {"ar.rnat", 19},
- {"ar.fcr", 21}, {"ar.eflag", 24},
- {"ar.csd", 25}, {"ar.ssd", 26},
- {"ar.cflg", 27}, {"ar.fsr", 28},
- {"ar.fir", 29}, {"ar.fdr", 30},
- {"ar.ccv", 32}, {"ar.unat", 36},
- {"ar.fpsr", 40}, {"ar.itc", 44},
- {"ar.pfs", 64}, {"ar.lc", 65},
- {"ar.ec", 66},
+ {"ar.k0", AR_K0}, {"ar.k1", AR_K0 + 1},
+ {"ar.k2", AR_K0 + 2}, {"ar.k3", AR_K0 + 3},
+ {"ar.k4", AR_K0 + 4}, {"ar.k5", AR_K0 + 5},
+ {"ar.k6", AR_K0 + 6}, {"ar.k7", AR_K7},
+ {"ar.rsc", AR_RSC}, {"ar.bsp", AR_BSP},
+ {"ar.bspstore", AR_BSPSTORE}, {"ar.rnat", AR_RNAT},
+ {"ar.fcr", AR_FCR}, {"ar.eflag", AR_EFLAG},
+ {"ar.csd", AR_CSD}, {"ar.ssd", AR_SSD},
+ {"ar.cflg", AR_CFLG}, {"ar.fsr", AR_FSR},
+ {"ar.fir", AR_FIR}, {"ar.fdr", AR_FDR},
+ {"ar.ccv", AR_CCV}, {"ar.unat", AR_UNAT},
+ {"ar.fpsr", AR_FPSR}, {"ar.itc", AR_ITC},
+ {"ar.pfs", AR_PFS}, {"ar.lc", AR_LC},
+ {"ar.ec", AR_EC},
};
+/* control registers: */
+
+#define CR_DCR 0
+#define CR_ITM 1
+#define CR_IVA 2
+#define CR_PTA 8
+#define CR_GPTA 9
#define CR_IPSR 16
#define CR_ISR 17
#define CR_IIP 19
#define CR_IFS 23
#define CR_IIM 24
#define CR_IHA 25
+#define CR_LID 64
#define CR_IVR 65
#define CR_TPR 66
#define CR_EOI 67
#define CR_IRR0 68
#define CR_IRR3 71
+#define CR_ITV 72
+#define CR_PMV 73
+#define CR_CMCV 74
#define CR_LRR0 80
#define CR_LRR1 81
-/* control registers: */
static const struct
{
const char *name;
- int regnum;
+ unsigned int regnum;
}
cr[] =
{
- {"cr.dcr", 0},
- {"cr.itm", 1},
- {"cr.iva", 2},
- {"cr.pta", 8},
- {"cr.gpta", 9},
- {"cr.ipsr", 16},
- {"cr.isr", 17},
- {"cr.iip", 19},
- {"cr.ifa", 20},
- {"cr.itir", 21},
- {"cr.iipa", 22},
- {"cr.ifs", 23},
- {"cr.iim", 24},
- {"cr.iha", 25},
- {"cr.lid", 64},
- {"cr.ivr", 65},
- {"cr.tpr", 66},
- {"cr.eoi", 67},
- {"cr.irr0", 68},
- {"cr.irr1", 69},
- {"cr.irr2", 70},
- {"cr.irr3", 71},
- {"cr.itv", 72},
- {"cr.pmv", 73},
- {"cr.cmcv", 74},
- {"cr.lrr0", 80},
- {"cr.lrr1", 81}
+ {"cr.dcr", CR_DCR},
+ {"cr.itm", CR_ITM},
+ {"cr.iva", CR_IVA},
+ {"cr.pta", CR_PTA},
+ {"cr.gpta", CR_GPTA},
+ {"cr.ipsr", CR_IPSR},
+ {"cr.isr", CR_ISR},
+ {"cr.iip", CR_IIP},
+ {"cr.ifa", CR_IFA},
+ {"cr.itir", CR_ITIR},
+ {"cr.iipa", CR_IIPA},
+ {"cr.ifs", CR_IFS},
+ {"cr.iim", CR_IIM},
+ {"cr.iha", CR_IHA},
+ {"cr.lid", CR_LID},
+ {"cr.ivr", CR_IVR},
+ {"cr.tpr", CR_TPR},
+ {"cr.eoi", CR_EOI},
+ {"cr.irr0", CR_IRR0},
+ {"cr.irr1", CR_IRR0 + 1},
+ {"cr.irr2", CR_IRR0 + 2},
+ {"cr.irr3", CR_IRR3},
+ {"cr.itv", CR_ITV},
+ {"cr.pmv", CR_PMV},
+ {"cr.cmcv", CR_CMCV},
+ {"cr.lrr0", CR_LRR0},
+ {"cr.lrr1", CR_LRR1}
};
#define PSR_MFL 4
static const struct
{
const char *name;
- int regnum;
+ unsigned int regnum;
}
indirect_reg[] =
{
static void dot_entry PARAMS ((int));
static void dot_mem_offset PARAMS ((int));
static void add_unwind_entry PARAMS((unw_rec_list *, int));
-static symbolS *declare_register PARAMS ((const char *name, int regnum));
-static void declare_register_set PARAMS ((const char *, int, int));
+static symbolS *declare_register PARAMS ((const char *name, unsigned int regnum));
+static void declare_register_set PARAMS ((const char *, unsigned int, unsigned int));
static unsigned int operand_width PARAMS ((enum ia64_opnd));
static enum operand_match_result operand_match PARAMS ((const struct ia64_opcode *idesc,
int index,
first_addr = (unsigned long) &first_frag->fr_literal;
/* This can happen if there is section switching in the middle of a
- function, causing the frag chain for the function to be broken. */
+ function, causing the frag chain for the function to be broken.
+ It is too difficult to recover safely from this problem, so we just
+ exit with an error. */
if (first_frag == NULL)
- {
- /* We get six warnings for one problem, because of the loop in
- fixup_unw_records, and because fixup_unw_records is called 3
- times: once before creating the variant frag, once to estimate
- its size, and once to relax it. This is unreasonable, so we use
- a static var to make sure we only emit the warning once. */
- static int warned = 0;
-
- if (!warned)
- {
- as_warn ("Corrupted unwind info due to unsupported section switching");
- warned = 1;
- }
-
- return index;
- }
+ as_fatal ("Section switching in code is not supported.");
}
/* Add in the used part of the last frag. */
static symbolS *
declare_register (name, regnum)
const char *name;
- int regnum;
+ unsigned int regnum;
{
const char *err;
symbolS *sym;
static void
declare_register_set (prefix, num_regs, base_regnum)
const char *prefix;
- int num_regs;
- int base_regnum;
+ unsigned int num_regs;
+ unsigned int base_regnum;
{
char name[8];
- int i;
+ unsigned int i;
for (i = 0; i < num_regs; ++i)
{
- sprintf (name, "%s%u", prefix, i);
+ snprintf (name, sizeof (name), "%s%u", prefix, i);
declare_register (name, base_regnum + i);
}
}
return OPERAND_MATCH;
break;
+ case IA64_OPND_IMMU5b:
+ if (e->X_op == O_constant)
+ {
+ val = e->X_add_number;
+ if (val >= 32 && val <= 63)
+ return OPERAND_MATCH;
+ else
+ return OPERAND_OUT_OF_RANGE;
+ }
+ break;
+
case IA64_OPND_CCNT5:
case IA64_OPND_CNT5:
case IA64_OPND_CNT6:
int addr_mod;
first = (md.curr_slot + NUM_SLOTS - md.num_slots_in_use) % NUM_SLOTS;
- know (first >= 0 & first < NUM_SLOTS);
+ know (first >= 0 && first < NUM_SLOTS);
n = MIN (3, md.num_slots_in_use);
/* Determine template: user user_template if specified, best match
changing NOPs in front of this slot. */
for (j = i; j < 3; ++j)
insn[j] = nop[ia64_templ_desc[required_template].exec_unit[j]];
+
+ /* We just picked a template that includes the stop bit in the
+ middle, so we don't need another one emitted later. */
+ md.slot[curr].end_of_insn_group = 0;
}
template = required_template;
}
else
as_fatal ("emit_one_bundle: unexpected dynamic op");
- sprintf (mnemonic, "%s.%c", idesc->name, "?imbfxx"[insn_unit]);
+ snprintf (mnemonic, sizeof (mnemonic), "%s.%c",
+ idesc->name, "?imbfxx"[insn_unit]);
opnd1 = idesc->operands[0];
opnd2 = idesc->operands[1];
ia64_free_opcode (idesc);
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);
fix->fx_file = md.slot[curr].src_file;
fix->fx_line = md.slot[curr].src_line;
}
curr = (curr + 1) % NUM_SLOTS;
idesc = md.slot[curr].idesc;
}
- if (manual_bundling > 0)
+
+ /* A user template was specified, but the first following instruction did
+ not fit. This can happen with or without manual bundling. */
+ if (md.num_slots_in_use > 0 && 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 if (manual_bundling > 0)
{
if (md.num_slots_in_use > 0)
{
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;
as_bad_where (md.slot[curr].src_file, md.slot[curr].src_line,
"Missing '}' at end of file");
}
+
know (md.num_slots_in_use < NUM_SLOTS);
t0 = end_of_insn_group | (template << 1) | (insn[0] << 5) | (insn[1] << 46);
void
md_begin ()
{
- int i, j, k, t, goodness, best, regnum, ok;
+ int i, j, k, t, goodness, best, ok;
const char *err;
char name[8];
md.entry_hash = hash_new ();
/* general registers: */
- for (i = REG_GR; i < REG_GR + 128; ++i)
- {
- sprintf (name, "r%d", i - REG_GR);
- md.regsym[i] = declare_register (name, i);
- }
+ declare_register_set ("r", 128, REG_GR);
+ declare_register ("gp", REG_GR + 1);
+ declare_register ("sp", REG_GR + 12);
+ declare_register ("tp", REG_GR + 13);
+ declare_register_set ("ret", 4, REG_GR + 8);
/* floating point registers: */
- for (i = REG_FR; i < REG_FR + 128; ++i)
- {
- sprintf (name, "f%d", i - REG_FR);
- md.regsym[i] = declare_register (name, i);
- }
-
- /* application registers: */
- for (i = REG_AR; i < REG_AR + 128; ++i)
- {
- sprintf (name, "ar%d", i - REG_AR);
- md.regsym[i] = declare_register (name, i);
- }
-
- /* control registers: */
- for (i = REG_CR; i < REG_CR + 128; ++i)
- {
- sprintf (name, "cr%d", i - REG_CR);
- md.regsym[i] = declare_register (name, i);
- }
-
- /* predicate registers: */
- for (i = REG_P; i < REG_P + 64; ++i)
- {
- sprintf (name, "p%d", i - REG_P);
- md.regsym[i] = declare_register (name, i);
- }
+ declare_register_set ("f", 128, REG_FR);
+ declare_register_set ("farg", 8, REG_FR + 8);
+ declare_register_set ("fret", 8, REG_FR + 8);
/* branch registers: */
- for (i = REG_BR; i < REG_BR + 8; ++i)
- {
- sprintf (name, "b%d", i - REG_BR);
- md.regsym[i] = declare_register (name, i);
- }
-
- md.regsym[REG_IP] = declare_register ("ip", REG_IP);
- md.regsym[REG_CFM] = declare_register ("cfm", REG_CFM);
- md.regsym[REG_PR] = declare_register ("pr", REG_PR);
- md.regsym[REG_PR_ROT] = declare_register ("pr.rot", REG_PR_ROT);
- md.regsym[REG_PSR] = declare_register ("psr", REG_PSR);
- md.regsym[REG_PSR_L] = declare_register ("psr.l", REG_PSR_L);
- md.regsym[REG_PSR_UM] = declare_register ("psr.um", REG_PSR_UM);
+ declare_register_set ("b", 8, REG_BR);
+ declare_register ("rp", REG_BR + 0);
- for (i = 0; i < NELEMS (indirect_reg); ++i)
- {
- regnum = indirect_reg[i].regnum;
- md.regsym[regnum] = declare_register (indirect_reg[i].name, regnum);
- }
+ /* predicate registers: */
+ declare_register_set ("p", 64, REG_P);
+ declare_register ("pr", REG_PR);
+ declare_register ("pr.rot", REG_PR_ROT);
- /* define synonyms for application registers: */
+ /* application registers: */
+ declare_register_set ("ar", 128, REG_AR);
for (i = 0; i < NELEMS (ar); ++i)
declare_register (ar[i].name, REG_AR + ar[i].regnum);
- /* define synonyms for control registers: */
+ /* control registers: */
+ declare_register_set ("cr", 128, REG_CR);
for (i = 0; i < NELEMS (cr); ++i)
declare_register (cr[i].name, REG_CR + cr[i].regnum);
- declare_register ("gp", REG_GR + 1);
- declare_register ("sp", REG_GR + 12);
- declare_register ("tp", REG_GR + 13);
- declare_register ("rp", REG_BR + 0);
+ declare_register ("ip", REG_IP);
+ declare_register ("cfm", REG_CFM);
+ declare_register ("psr", REG_PSR);
+ declare_register ("psr.l", REG_PSR_L);
+ declare_register ("psr.um", REG_PSR_UM);
+
+ for (i = 0; i < NELEMS (indirect_reg); ++i)
+ {
+ unsigned int regnum = indirect_reg[i].regnum;
+
+ md.indregsym[regnum - IND_CPUID] = declare_register (indirect_reg[i].name, regnum);
+ }
/* pseudo-registers used to specify unwind info: */
declare_register ("psp", REG_PSP);
- declare_register_set ("ret", 4, REG_GR + 8);
- declare_register_set ("farg", 8, REG_FR + 8);
- declare_register_set ("fret", 8, REG_FR + 8);
-
for (i = 0; i < NELEMS (const_bits); ++i)
{
err = hash_insert (md.const_hash, const_bits[i].name,
r->X_add_number = REG_GR;
}
l->X_op = O_index;
- l->X_op_symbol = md.regsym[l->X_add_number];
+ l->X_op_symbol = md.indregsym[l->X_add_number - IND_CPUID];
l->X_add_number = r->X_add_number;
return 1;
}
IC:rse-writers.
15+16) Represents reserved instructions, which the assembler does not
generate.
+ 17) CR[TPR] has a RAW dependency only between mov-to-CR-TPR and
+ mov-to-PSR-l or ssm instructions that set PSR.i, PSR.pp or PSR.up.
Memory resources (i.e. locations in memory) are *not* marked or tracked by
this code; there are no dependency violations based on memory access.
break;
case IA64_RS_CRX:
- /* Handle all CR[REG] resources */
- if (note == 0 || note == 1)
+ /* Handle all CR[REG] resources.
+ ??? FIXME: The rule 17 isn't really handled correctly. */
+ if (note == 0 || note == 1 || note == 17)
{
if (idesc->operands[!rsrc_write] == IA64_OPND_CR3)
{
int certain = (matchtype == 1 && CURR_SLOT.qp_regno == 0);
if (path != 0)
- sprintf (pathmsg, " when entry is at label '%s'",
+ snprintf (pathmsg, sizeof (pathmsg),
+ " when entry is at label '%s'",
md.entry_labels[path - 1]);
if (matchtype == 1 && rs->index >= 0)
- sprintf (indexmsg, ", specific resource number is %d",
+ snprintf (indexmsg, sizeof (indexmsg),
+ ", specific resource number is %d",
rs->index);
- sprintf (msg, "Use of '%s' %s %s dependency '%s' (%s)%s%s",
+ snprintf (msg, sizeof (msg),
+ "Use of '%s' %s %s dependency '%s' (%s)%s%s",
idesc->name,
(certain ? "violates" : "may violate"),
dv_mode[dep->mode], dep->name,
as_bad_where (fixp->fx_file, fixp->fx_line,
"Cannot represent %s relocation in object file",
bfd_get_reloc_code_name (fixp->fx_r_type));
+ free (reloc);
+ return NULL;
}
return reloc;
}
{
char *file; /* The file where the directive is seen. */
unsigned int line; /* The line number the directive is at. */
- const char *name; /* The orignale name of the symbol. */
+ const char *name; /* The original name of the symbol. */
};
/* Called for .alias and .secalias directives. If SECTION is 1, it is