aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2005-07-01 06:51:39 +0000
committerJan Beulich <jbeulich@novell.com>2005-07-01 06:51:39 +0000
commite4e8248d79d8461adf8b0cf22086e85a4c9ee0a4 (patch)
treeca212d70445e1db6133eb28d30620140141e24cb /gas/config
parent85d162e6db2034e9763e6c77892c914b0dc03b1d (diff)
downloadgdb-e4e8248d79d8461adf8b0cf22086e85a4c9ee0a4.zip
gdb-e4e8248d79d8461adf8b0cf22086e85a4c9ee0a4.tar.gz
gdb-e4e8248d79d8461adf8b0cf22086e85a4c9ee0a4.tar.bz2
gas/
2005-07-01 Jan Beulich <jbeulich@novell.com> * config/tc-ia64.c (line_separator_chars): Add '{' and '}'. (output_spill_psprel, output_spill_psprel_p): Combine. (output_spill_sprel, output_spill_sprel_p): Combine. (output_spill_reg, output_spill_regp_p): Combine. (process_one_record): Handle psp_psprel. (parse_predicate_and_operand): New. (convert_expr_to_ab_reg): Two new parameters. Return void. Always initialize output values. Emit diagnostic case here. (convert_expr_to_xy_reg): Likewise. Don't allow r0, f0, and f1. (add_unwind_entry): New second parameter. Allow first parameter to be NULL. Parse optional tag, emit warning about further support for it otherwise being missing. Check end-of-line when requested. (dot_fframe): Clear operand when wrong. Allow tag. (dot_vframe): Likewise. (dot_vframesp): Likewise. Rename parameter, issue warning when psp relative. (dot_vframepsp): Remove. (dot_altrp): Clear operand when wrong. Allow tag. (dot_save): Likewise. Let default case also go through add_unwind_entry. (dot_savemem): Likewise. (dot_restore): Don't return when wrong operand. Allow tag. (dot_spillreg, dot_spillreg_p): Combine. Simplify by using parse_predicate_and_operand and the new arguments to convert_expr_to_ab_reg and convert_expr_to_xy_reg. Don't return when wrong operand. Allow tag. (dot_restorereg, dot_restorereg_p): Likewise. (dot_spillmem, dot_spillmem_p): Likewise. (dot_saveg): Clear operand when wrong. Perform tighter operand checks. Allow tag. (dot_savef): Likewise. (dot_saveb): Likewise. (dot_savegf): Likewise. (dot_spill): Remove end-of-line check. Combine. Simplify by using parse_predicate_and_operand and the new arguments to convert_expr_to_ab_reg and convert_expr_to_xy_reg. Don't return when wrong operand. Allow tag. (popcount): New. (dot_label_state): Don't return when wrong operand. (dot_copy_state): Likewise. (dot_unwabi): Likewise. Check if in prologue. (dot_body): Don't call demand_empty_rest_of_line. (dot_prologue): Type of mask and grsave is unsigned. Perform tighter operand checks. (md_pseudo_table): Also use dot_restorereg for .restorereg.p. Also use dot_spillreg for .spillreg.p. Also use dot_spillmem for .spillpsp.p and .spillsp.p. Also use dot_vframesp for .vframepsp. (parse_operand): New second parameter. Don't deal with '}' here anymore. Don't advance past end-of-line. (parse_operands): Pass second argument to parse_operand. (ia64_start_line): Prevent out-of-bounds access through input_line_pointer. Deal with '}' here. (ia64_unrecognized_line): Don't deal with '}' here. (dot_alias): Use ignore_rest_of_line not its deprecated alias discard_rest_of_line. gas/testsuite/ 2005-07-01 Jan Beulich <jbeulich@novell.com> * gas/ia64/group-2.s: Use register as second operand of .prologue. * gas/ia64/unwind-err.s: Add check for .vframesp. * gas/ia64/unwind-err.l: Adjust. * gas/ia64/strange.[sd]: New. * gas/ia64/unwind-bad.[sl]: New. * gas/ia64/unwind-ok.[sd]: New. * gas/ia64/ia64.exp: Run new tests.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-ia64.c1234
1 files changed, 588 insertions, 646 deletions
diff --git a/gas/config/tc-ia64.c b/gas/config/tc-ia64.c
index cab32cd..fe0f9a0 100644
--- a/gas/config/tc-ia64.c
+++ b/gas/config/tc-ia64.c
@@ -193,7 +193,7 @@ const char line_comment_chars[] = "#";
/* Characters which may be used to separate multiple commands on a
single line. */
-const char line_separator_chars[] = ";";
+const char line_separator_chars[] = ";{}";
/* Characters which are used to indicate an exponent in a floating
point number. */
@@ -736,6 +736,7 @@ static struct
/* TRUE if processing unwind directives in a prologue region. */
unsigned int prologue : 1;
unsigned int prologue_mask : 4;
+ unsigned int prologue_gr : 7;
unsigned int body : 1;
unsigned int insn : 1;
unsigned int prologue_count; /* number of .prologues seen so far */
@@ -762,11 +763,9 @@ static void dot_proc PARAMS ((int));
static void dot_fframe PARAMS ((int));
static void dot_vframe PARAMS ((int));
static void dot_vframesp PARAMS ((int));
-static void dot_vframepsp PARAMS ((int));
static void dot_save PARAMS ((int));
static void dot_restore PARAMS ((int));
static void dot_restorereg PARAMS ((int));
-static void dot_restorereg_p PARAMS ((int));
static void dot_handlerdata PARAMS ((int));
static void dot_unwentry PARAMS ((int));
static void dot_altrp PARAMS ((int));
@@ -778,8 +777,6 @@ static void dot_savegf PARAMS ((int));
static void dot_spill PARAMS ((int));
static void dot_spillreg PARAMS ((int));
static void dot_spillmem PARAMS ((int));
-static void dot_spillreg_p PARAMS ((int));
-static void dot_spillmem_p PARAMS ((int));
static void dot_label_state PARAMS ((int));
static void dot_copy_state PARAMS ((int));
static void dot_unwabi PARAMS ((int));
@@ -809,14 +806,14 @@ static void dot_serialize PARAMS ((int));
static void dot_dv_mode PARAMS ((int));
static void dot_entry PARAMS ((int));
static void dot_mem_offset PARAMS ((int));
-static void add_unwind_entry PARAMS((unw_rec_list *ptr));
+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 unsigned int operand_width PARAMS ((enum ia64_opnd));
static enum operand_match_result operand_match PARAMS ((const struct ia64_opcode *idesc,
int index,
expressionS *e));
-static int parse_operand PARAMS ((expressionS *e));
+static int parse_operand PARAMS ((expressionS *, int));
static struct ia64_opcode * parse_operands PARAMS ((struct ia64_opcode *));
static void build_insn PARAMS ((struct slot *, bfd_vma *));
static void emit_one_bundle PARAMS ((void));
@@ -937,15 +934,11 @@ static unw_rec_list *output_unwabi PARAMS ((unsigned long, unsigned long));
static unw_rec_list *output_epilogue PARAMS ((unsigned long));
static unw_rec_list *output_label_state PARAMS ((unsigned long));
static unw_rec_list *output_copy_state PARAMS ((unsigned long));
-static unw_rec_list *output_spill_psprel PARAMS ((unsigned int, unsigned int, unsigned int));
-static unw_rec_list *output_spill_sprel PARAMS ((unsigned int, unsigned int, unsigned int));
-static unw_rec_list *output_spill_psprel_p PARAMS ((unsigned int, unsigned int, unsigned int,
+static unw_rec_list *output_spill_psprel PARAMS ((unsigned int, unsigned int, unsigned int,
unsigned int));
-static unw_rec_list *output_spill_sprel_p PARAMS ((unsigned int, unsigned int, unsigned int,
+static unw_rec_list *output_spill_sprel PARAMS ((unsigned int, unsigned int, unsigned int,
unsigned int));
static unw_rec_list *output_spill_reg PARAMS ((unsigned int, unsigned int, unsigned int,
- unsigned int));
-static unw_rec_list *output_spill_reg_p PARAMS ((unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int));
static void process_one_record PARAMS ((unw_rec_list *, vbyte_func));
static void process_unw_records PARAMS ((unw_rec_list *, vbyte_func));
@@ -956,8 +949,9 @@ static unsigned long slot_index PARAMS ((unsigned long, fragS *,
int));
static unw_rec_list *optimize_unw_records PARAMS ((unw_rec_list *));
static void fixup_unw_records PARAMS ((unw_rec_list *, int));
-static int convert_expr_to_ab_reg PARAMS ((expressionS *, unsigned int *, unsigned int *));
-static int convert_expr_to_xy_reg PARAMS ((expressionS *, unsigned int *, unsigned int *));
+static int parse_predicate_and_operand PARAMS ((expressionS *, unsigned *, const char *));
+static void convert_expr_to_ab_reg PARAMS ((const expressionS *, unsigned int *, unsigned int *, const char *, int));
+static void convert_expr_to_xy_reg PARAMS ((const expressionS *, unsigned int *, unsigned int *, const char *, int));
static unsigned int get_saved_prologue_count PARAMS ((unsigned long));
static void save_prologue_count PARAMS ((unsigned long, unsigned int));
static void free_saved_prologue_counts PARAMS ((void));
@@ -2288,39 +2282,13 @@ output_copy_state (unsigned long label)
}
static unw_rec_list *
-output_spill_psprel (ab, reg, offset)
- unsigned int ab;
- unsigned int reg;
- unsigned int offset;
-{
- unw_rec_list *ptr = alloc_record (spill_psprel);
- ptr->r.record.x.ab = ab;
- ptr->r.record.x.reg = reg;
- ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset);
- return ptr;
-}
-
-static unw_rec_list *
-output_spill_sprel (ab, reg, offset)
- unsigned int ab;
- unsigned int reg;
- unsigned int offset;
-{
- unw_rec_list *ptr = alloc_record (spill_sprel);
- ptr->r.record.x.ab = ab;
- ptr->r.record.x.reg = reg;
- ptr->r.record.x.spoff = offset / 4;
- return ptr;
-}
-
-static unw_rec_list *
-output_spill_psprel_p (ab, reg, offset, predicate)
+output_spill_psprel (ab, reg, offset, predicate)
unsigned int ab;
unsigned int reg;
unsigned int offset;
unsigned int predicate;
{
- unw_rec_list *ptr = alloc_record (spill_psprel_p);
+ unw_rec_list *ptr = alloc_record (predicate ? spill_psprel_p : spill_psprel);
ptr->r.record.x.ab = ab;
ptr->r.record.x.reg = reg;
ptr->r.record.x.pspoff = ENCODED_PSP_OFFSET (offset);
@@ -2329,13 +2297,13 @@ output_spill_psprel_p (ab, reg, offset, predicate)
}
static unw_rec_list *
-output_spill_sprel_p (ab, reg, offset, predicate)
+output_spill_sprel (ab, reg, offset, predicate)
unsigned int ab;
unsigned int reg;
unsigned int offset;
unsigned int predicate;
{
- unw_rec_list *ptr = alloc_record (spill_sprel_p);
+ unw_rec_list *ptr = alloc_record (predicate ? spill_sprel_p : spill_sprel);
ptr->r.record.x.ab = ab;
ptr->r.record.x.reg = reg;
ptr->r.record.x.spoff = offset / 4;
@@ -2344,29 +2312,14 @@ output_spill_sprel_p (ab, reg, offset, predicate)
}
static unw_rec_list *
-output_spill_reg (ab, reg, targ_reg, xy)
- unsigned int ab;
- unsigned int reg;
- unsigned int targ_reg;
- unsigned int xy;
-{
- unw_rec_list *ptr = alloc_record (spill_reg);
- ptr->r.record.x.ab = ab;
- ptr->r.record.x.reg = reg;
- ptr->r.record.x.treg = targ_reg;
- ptr->r.record.x.xy = xy;
- return ptr;
-}
-
-static unw_rec_list *
-output_spill_reg_p (ab, reg, targ_reg, xy, predicate)
+output_spill_reg (ab, reg, targ_reg, xy, predicate)
unsigned int ab;
unsigned int reg;
unsigned int targ_reg;
unsigned int xy;
unsigned int predicate;
{
- unw_rec_list *ptr = alloc_record (spill_reg_p);
+ unw_rec_list *ptr = alloc_record (predicate ? spill_reg_p : spill_reg);
ptr->r.record.x.ab = ab;
ptr->r.record.x.reg = reg;
ptr->r.record.x.treg = targ_reg;
@@ -2577,6 +2530,28 @@ calc_record_size (list)
return vbyte_count;
}
+/* Return the number of bits set in the input value.
+ Perhaps this has a better place... */
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# define popcount __builtin_popcount
+#else
+static int
+popcount (unsigned x)
+{
+ static const unsigned char popcnt[16] =
+ {
+ 0, 1, 1, 2,
+ 1, 2, 2, 3,
+ 1, 2, 2, 3,
+ 2, 3, 3, 4
+ };
+
+ if (x < NELEMS (popcnt))
+ return popcnt[x];
+ return popcnt[x % NELEMS (popcnt)] + popcount (x / NELEMS (popcnt));
+}
+#endif
+
/* Update IMASK bitmask to reflect the fact that one or more registers
of type TYPE are saved starting at instruction with index T. If N
bits are set in REGMASK, it is assumed that instructions T through
@@ -3000,17 +2975,43 @@ ia64_convert_frag (fragS *frag)
}
static int
-convert_expr_to_ab_reg (e, ab, regp)
- expressionS *e;
+parse_predicate_and_operand (e, qp, po)
+ expressionS * e;
+ unsigned * qp;
+ const char * po;
+{
+ int sep = parse_operand (e, ',');
+
+ *qp = e->X_add_number - REG_P;
+ if (e->X_op != O_register || *qp > 63)
+ {
+ as_bad ("First operand to .%s must be a predicate", po);
+ *qp = 0;
+ }
+ else if (*qp == 0)
+ as_warn ("Pointless use of p0 as first operand to .%s", po);
+ if (sep == ',')
+ sep = parse_operand (e, ',');
+ else
+ e->X_op = O_absent;
+ return sep;
+}
+
+static void
+convert_expr_to_ab_reg (e, ab, regp, po, n)
+ const expressionS *e;
unsigned int *ab;
unsigned int *regp;
+ const char * po;
+ int n;
{
- unsigned int reg;
+ unsigned int reg = e->X_add_number;
+
+ *ab = *regp = 0; /* Anything valid is good here. */
if (e->X_op != O_register)
- return 0;
+ reg = REG_GR; /* Anything invalid is good here. */
- reg = e->X_add_number;
if (reg >= (REG_GR + 4) && reg <= (REG_GR + 7))
{
*ab = 0;
@@ -3045,31 +3046,33 @@ convert_expr_to_ab_reg (e, ab, regp)
case REG_AR + AR_LC: *regp = 10; break;
default:
- return 0;
+ as_bad ("Operand %d to .%s must be a preserved register", n, po);
+ break;
}
}
- return 1;
}
-static int
-convert_expr_to_xy_reg (e, xy, regp)
- expressionS *e;
+static void
+convert_expr_to_xy_reg (e, xy, regp, po, n)
+ const expressionS *e;
unsigned int *xy;
unsigned int *regp;
+ const char * po;
+ int n;
{
- unsigned int reg;
+ unsigned int reg = e->X_add_number;
- if (e->X_op != O_register)
- return 0;
+ *xy = *regp = 0; /* Anything valid is good here. */
- reg = e->X_add_number;
+ if (e->X_op != O_register)
+ reg = REG_GR; /* Anything invalid is good here. */
- if (/* reg >= REG_GR && */ reg <= (REG_GR + 127))
+ if (reg >= (REG_GR + 1) && reg <= (REG_GR + 127))
{
*xy = 0;
*regp = reg - REG_GR;
}
- else if (reg >= REG_FR && reg <= (REG_FR + 127))
+ else if (reg >= (REG_FR + 2) && reg <= (REG_FR + 127))
{
*xy = 1;
*regp = reg - REG_FR;
@@ -3080,8 +3083,7 @@ convert_expr_to_xy_reg (e, xy, regp)
*regp = reg - REG_BR;
}
else
- return -1;
- return 1;
+ as_bad ("Operand %d to .%s must be a writable register", n, po);
}
static void
@@ -3210,18 +3212,48 @@ in_body (const char *directive)
}
static void
-add_unwind_entry (ptr)
+add_unwind_entry (ptr, sep)
unw_rec_list *ptr;
+ int sep;
{
- if (unwind.tail)
- unwind.tail->next = ptr;
- else
- unwind.list = ptr;
- unwind.tail = ptr;
+ if (ptr)
+ {
+ if (unwind.tail)
+ unwind.tail->next = ptr;
+ else
+ unwind.list = ptr;
+ unwind.tail = ptr;
+
+ /* The current entry can in fact be a chain of unwind entries. */
+ if (unwind.current_entry == NULL)
+ unwind.current_entry = ptr;
+ }
/* The current entry can in fact be a chain of unwind entries. */
if (unwind.current_entry == NULL)
unwind.current_entry = ptr;
+
+ if (sep == ',')
+ {
+ /* Parse a tag permitted for the current directive. */
+ int ch;
+
+ SKIP_WHITESPACE ();
+ ch = get_symbol_end ();
+ /* FIXME: For now, just issue a warning that this isn't implemented. */
+ {
+ static int warned;
+
+ if (!warned)
+ {
+ warned = 1;
+ as_warn ("Tags on unwind pseudo-ops aren't supported, yet");
+ }
+ }
+ *input_line_pointer = ch;
+ }
+ if (sep != NOT_A_CHAR)
+ demand_empty_rest_of_line ();
}
static void
@@ -3229,16 +3261,19 @@ dot_fframe (dummy)
int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
+ int sep;
if (!in_prologue ("fframe"))
return;
- parse_operand (&e);
+ sep = parse_operand (&e, ',');
if (e.X_op != O_constant)
- as_bad ("Operand to .fframe must be a constant");
- else
- add_unwind_entry (output_mem_stack_f (e.X_add_number));
+ {
+ as_bad ("First operand to .fframe must be a constant");
+ e.X_add_number = 0;
+ }
+ add_unwind_entry (output_mem_stack_f (e.X_add_number), sep);
}
static void
@@ -3247,58 +3282,47 @@ dot_vframe (dummy)
{
expressionS e;
unsigned reg;
+ int sep;
if (!in_prologue ("vframe"))
return;
- parse_operand (&e);
+ sep = parse_operand (&e, ',');
reg = e.X_add_number - REG_GR;
- if (e.X_op == O_register && reg < 128)
+ if (e.X_op != O_register || reg > 127)
{
- add_unwind_entry (output_mem_stack_v ());
- if (! (unwind.prologue_mask & 2))
- add_unwind_entry (output_psp_gr (reg));
+ as_bad ("First operand to .vframe must be a general register");
+ reg = 0;
}
- else
- as_bad ("First operand to .vframe must be a general register");
+ add_unwind_entry (output_mem_stack_v (), sep);
+ if (! (unwind.prologue_mask & 2))
+ add_unwind_entry (output_psp_gr (reg), NOT_A_CHAR);
+ else if (reg != unwind.prologue_gr
+ + (unsigned) popcount (unwind.prologue_mask & (-2 << 1)))
+ as_warn ("Operand of .vframe contradicts .prologue");
}
static void
-dot_vframesp (dummy)
- int dummy ATTRIBUTE_UNUSED;
+dot_vframesp (psp)
+ int psp;
{
expressionS e;
+ int sep;
- if (!in_prologue ("vframesp"))
- return;
-
- parse_operand (&e);
- if (e.X_op == O_constant)
- {
- add_unwind_entry (output_mem_stack_v ());
- add_unwind_entry (output_psp_sprel (e.X_add_number));
- }
- else
- as_bad ("Operand to .vframesp must be a constant (sp-relative offset)");
-}
-
-static void
-dot_vframepsp (dummy)
- int dummy ATTRIBUTE_UNUSED;
-{
- expressionS e;
+ if (psp)
+ as_warn (".vframepsp is meaningless, assuming .vframesp was meant");
- if (!in_prologue ("vframepsp"))
+ if (!in_prologue ("vframesp"))
return;
- parse_operand (&e);
- if (e.X_op == O_constant)
+ sep = parse_operand (&e, ',');
+ if (e.X_op != O_constant)
{
- add_unwind_entry (output_mem_stack_v ());
- add_unwind_entry (output_psp_sprel (e.X_add_number));
+ as_bad ("Operand to .vframesp must be a constant (sp-relative offset)");
+ e.X_add_number = 0;
}
- else
- as_bad ("Operand to .vframepsp must be a constant (psp-relative offset)");
+ add_unwind_entry (output_mem_stack_v (), sep);
+ add_unwind_entry (output_psp_sprel (e.X_add_number), NOT_A_CHAR);
}
static void
@@ -3306,106 +3330,115 @@ dot_save (dummy)
int dummy ATTRIBUTE_UNUSED;
{
expressionS e1, e2;
+ unsigned reg1, reg2;
int sep;
- int reg1, reg2;
if (!in_prologue ("save"))
return;
- sep = parse_operand (&e1);
- if (sep != ',')
- as_bad ("No second operand to .save");
- sep = parse_operand (&e2);
+ sep = parse_operand (&e1, ',');
+ if (sep == ',')
+ sep = parse_operand (&e2, ',');
+ else
+ e2.X_op = O_absent;
reg1 = e1.X_add_number;
- reg2 = e2.X_add_number - REG_GR;
-
/* Make sure its a valid ar.xxx reg, OR its br0, aka 'rp'. */
- if (e1.X_op == O_register)
+ if (e1.X_op != O_register)
{
- if (e2.X_op == O_register && reg2 >= 0 && reg2 < 128)
- {
- switch (reg1)
- {
- case REG_AR + AR_BSP:
- add_unwind_entry (output_bsp_when ());
- add_unwind_entry (output_bsp_gr (reg2));
- break;
- case REG_AR + AR_BSPSTORE:
- add_unwind_entry (output_bspstore_when ());
- add_unwind_entry (output_bspstore_gr (reg2));
- break;
- case REG_AR + AR_RNAT:
- add_unwind_entry (output_rnat_when ());
- add_unwind_entry (output_rnat_gr (reg2));
- break;
- case REG_AR + AR_UNAT:
- add_unwind_entry (output_unat_when ());
- add_unwind_entry (output_unat_gr (reg2));
- break;
- case REG_AR + AR_FPSR:
- add_unwind_entry (output_fpsr_when ());
- add_unwind_entry (output_fpsr_gr (reg2));
- break;
- case REG_AR + AR_PFS:
- add_unwind_entry (output_pfs_when ());
- if (! (unwind.prologue_mask & 4))
- add_unwind_entry (output_pfs_gr (reg2));
- break;
- case REG_AR + AR_LC:
- add_unwind_entry (output_lc_when ());
- add_unwind_entry (output_lc_gr (reg2));
- break;
- case REG_BR:
- add_unwind_entry (output_rp_when ());
- if (! (unwind.prologue_mask & 8))
- add_unwind_entry (output_rp_gr (reg2));
- break;
- case REG_PR:
- add_unwind_entry (output_preds_when ());
- if (! (unwind.prologue_mask & 1))
- add_unwind_entry (output_preds_gr (reg2));
- break;
- case REG_PRIUNAT:
- add_unwind_entry (output_priunat_when_gr ());
- add_unwind_entry (output_priunat_gr (reg2));
- break;
- default:
- as_bad ("First operand not a valid register");
- }
- }
- else
- as_bad (" Second operand not a valid register");
+ as_bad ("First operand to .save not a register");
+ reg1 = REG_PR; /* Anything valid is good here. */
+ }
+ reg2 = e2.X_add_number - REG_GR;
+ if (e2.X_op != O_register || reg2 > 127)
+ {
+ as_bad ("Second operand to .save not a valid register");
+ reg2 = 0;
+ }
+ switch (reg1)
+ {
+ case REG_AR + AR_BSP:
+ add_unwind_entry (output_bsp_when (), sep);
+ add_unwind_entry (output_bsp_gr (reg2), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_BSPSTORE:
+ add_unwind_entry (output_bspstore_when (), sep);
+ add_unwind_entry (output_bspstore_gr (reg2), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_RNAT:
+ add_unwind_entry (output_rnat_when (), sep);
+ add_unwind_entry (output_rnat_gr (reg2), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_UNAT:
+ add_unwind_entry (output_unat_when (), sep);
+ add_unwind_entry (output_unat_gr (reg2), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_FPSR:
+ add_unwind_entry (output_fpsr_when (), sep);
+ add_unwind_entry (output_fpsr_gr (reg2), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_PFS:
+ add_unwind_entry (output_pfs_when (), sep);
+ if (! (unwind.prologue_mask & 4))
+ add_unwind_entry (output_pfs_gr (reg2), NOT_A_CHAR);
+ else if (reg2 != unwind.prologue_gr
+ + (unsigned) popcount (unwind.prologue_mask & (-4 << 1)))
+ as_warn ("Second operand of .save contradicts .prologue");
+ break;
+ case REG_AR + AR_LC:
+ add_unwind_entry (output_lc_when (), sep);
+ add_unwind_entry (output_lc_gr (reg2), NOT_A_CHAR);
+ break;
+ case REG_BR:
+ add_unwind_entry (output_rp_when (), sep);
+ if (! (unwind.prologue_mask & 8))
+ add_unwind_entry (output_rp_gr (reg2), NOT_A_CHAR);
+ else if (reg2 != unwind.prologue_gr)
+ as_warn ("Second operand of .save contradicts .prologue");
+ break;
+ case REG_PR:
+ add_unwind_entry (output_preds_when (), sep);
+ if (! (unwind.prologue_mask & 1))
+ add_unwind_entry (output_preds_gr (reg2), NOT_A_CHAR);
+ else if (reg2 != unwind.prologue_gr
+ + (unsigned) popcount (unwind.prologue_mask & (-1 << 1)))
+ as_warn ("Second operand of .save contradicts .prologue");
+ break;
+ case REG_PRIUNAT:
+ add_unwind_entry (output_priunat_when_gr (), sep);
+ add_unwind_entry (output_priunat_gr (reg2), NOT_A_CHAR);
+ break;
+ default:
+ as_bad ("First operand to .save not a valid register");
+ add_unwind_entry (NULL, sep);
+ break;
}
- else
- as_bad ("First operand not a register");
}
static void
dot_restore (dummy)
int dummy ATTRIBUTE_UNUSED;
{
- expressionS e1, e2;
+ expressionS e1;
unsigned long ecount; /* # of _additional_ regions to pop */
int sep;
if (!in_body ("restore"))
return;
- sep = parse_operand (&e1);
+ sep = parse_operand (&e1, ',');
if (e1.X_op != O_register || e1.X_add_number != REG_GR + 12)
- {
- as_bad ("First operand to .restore must be stack pointer (sp)");
- return;
- }
+ as_bad ("First operand to .restore must be stack pointer (sp)");
if (sep == ',')
{
- parse_operand (&e2);
+ expressionS e2;
+
+ sep = parse_operand (&e2, ',');
if (e2.X_op != O_constant || e2.X_add_number < 0)
{
as_bad ("Second operand to .restore must be a constant >= 0");
- return;
+ e2.X_add_number = 0;
}
ecount = e2.X_add_number;
}
@@ -3416,10 +3449,10 @@ dot_restore (dummy)
{
as_bad ("Epilogue count of %lu exceeds number of nested prologues (%u)",
ecount + 1, unwind.prologue_count);
- return;
+ ecount = 0;
}
- add_unwind_entry (output_epilogue (ecount));
+ add_unwind_entry (output_epilogue (ecount), sep);
if (ecount < unwind.prologue_count)
unwind.prologue_count -= ecount + 1;
@@ -3428,58 +3461,27 @@ dot_restore (dummy)
}
static void
-dot_restorereg (dummy)
- int dummy ATTRIBUTE_UNUSED;
-{
- unsigned int ab, reg;
- expressionS e;
-
- if (!in_procedure ("restorereg"))
- return;
-
- parse_operand (&e);
-
- if (!convert_expr_to_ab_reg (&e, &ab, &reg))
- {
- as_bad ("First operand to .restorereg must be a preserved register");
- return;
- }
- add_unwind_entry (output_spill_reg (ab, reg, 0, 0));
-}
-
-static void
-dot_restorereg_p (dummy)
- int dummy ATTRIBUTE_UNUSED;
+dot_restorereg (pred)
+ int pred;
{
unsigned int qp, ab, reg;
- expressionS e1, e2;
+ expressionS e;
int sep;
+ const char * const po = pred ? "restorereg.p" : "restorereg";
- if (!in_procedure ("restorereg.p"))
+ if (!in_procedure (po))
return;
- sep = parse_operand (&e1);
- if (sep != ',')
- {
- as_bad ("No second operand to .restorereg.p");
- return;
- }
-
- parse_operand (&e2);
-
- qp = e1.X_add_number - REG_P;
- if (e1.X_op != O_register || qp > 63)
+ if (pred)
+ sep = parse_predicate_and_operand (&e, &qp, po);
+ else
{
- as_bad ("First operand to .restorereg.p must be a predicate");
- return;
+ sep = parse_operand (&e, ',');
+ qp = 0;
}
+ convert_expr_to_ab_reg (&e, &ab, &reg, po, 1 + pred);
- if (!convert_expr_to_ab_reg (&e2, &ab, &reg))
- {
- as_bad ("Second operand to .restorereg.p must be a preserved register");
- return;
- }
- add_unwind_entry (output_spill_reg_p (ab, reg, 0, 0, qp));
+ add_unwind_entry (output_spill_reg (ab, reg, 0, 0, qp), sep);
}
static char *special_linkonce_name[] =
@@ -3607,7 +3609,7 @@ generate_unwind_image (const segT text_seg)
/* Mark the end of the unwind info, so that we can compute the size of the
last unwind region. */
- add_unwind_entry (output_endp ());
+ add_unwind_entry (output_endp (), NOT_A_CHAR);
/* Force out pending instructions, to make sure all unwind records have
a valid slot_number field. */
@@ -3723,12 +3725,14 @@ dot_altrp (dummy)
if (!in_prologue ("altrp"))
return;
- parse_operand (&e);
+ parse_operand (&e, 0);
reg = e.X_add_number - REG_BR;
- if (e.X_op == O_register && reg < 8)
- add_unwind_entry (output_rp_br (reg));
- else
- as_bad ("First operand not a valid branch register");
+ if (e.X_op != O_register || reg > 7)
+ {
+ as_bad ("First operand to .altrp not a valid branch register");
+ reg = 0;
+ }
+ add_unwind_entry (output_rp_br (reg), 0);
}
static void
@@ -3738,182 +3742,210 @@ dot_savemem (psprel)
expressionS e1, e2;
int sep;
int reg1, val;
+ const char * const po = psprel ? "savepsp" : "savesp";
- if (!in_prologue (psprel ? "savepsp" : "savesp"))
+ if (!in_prologue (po))
return;
- sep = parse_operand (&e1);
- if (sep != ',')
- as_bad ("No second operand to .save%ssp", psprel ? "p" : "");
- sep = parse_operand (&e2);
+ sep = parse_operand (&e1, ',');
+ if (sep == ',')
+ sep = parse_operand (&e2, ',');
+ else
+ e2.X_op = O_absent;
reg1 = e1.X_add_number;
val = e2.X_add_number;
/* Make sure its a valid ar.xxx reg, OR its br0, aka 'rp'. */
- if (e1.X_op == O_register)
+ if (e1.X_op != O_register)
{
- if (e2.X_op == O_constant)
- {
- switch (reg1)
- {
- case REG_AR + AR_BSP:
- add_unwind_entry (output_bsp_when ());
- add_unwind_entry ((psprel
- ? output_bsp_psprel
- : output_bsp_sprel) (val));
- break;
- case REG_AR + AR_BSPSTORE:
- add_unwind_entry (output_bspstore_when ());
- add_unwind_entry ((psprel
- ? output_bspstore_psprel
- : output_bspstore_sprel) (val));
- break;
- case REG_AR + AR_RNAT:
- add_unwind_entry (output_rnat_when ());
- add_unwind_entry ((psprel
- ? output_rnat_psprel
- : output_rnat_sprel) (val));
- break;
- case REG_AR + AR_UNAT:
- add_unwind_entry (output_unat_when ());
- add_unwind_entry ((psprel
- ? output_unat_psprel
- : output_unat_sprel) (val));
- break;
- case REG_AR + AR_FPSR:
- add_unwind_entry (output_fpsr_when ());
- add_unwind_entry ((psprel
- ? output_fpsr_psprel
- : output_fpsr_sprel) (val));
- break;
- case REG_AR + AR_PFS:
- add_unwind_entry (output_pfs_when ());
- add_unwind_entry ((psprel
- ? output_pfs_psprel
- : output_pfs_sprel) (val));
- break;
- case REG_AR + AR_LC:
- add_unwind_entry (output_lc_when ());
- add_unwind_entry ((psprel
- ? output_lc_psprel
- : output_lc_sprel) (val));
- break;
- case REG_BR:
- add_unwind_entry (output_rp_when ());
- add_unwind_entry ((psprel
- ? output_rp_psprel
- : output_rp_sprel) (val));
- break;
- case REG_PR:
- add_unwind_entry (output_preds_when ());
- add_unwind_entry ((psprel
- ? output_preds_psprel
- : output_preds_sprel) (val));
- break;
- case REG_PRIUNAT:
- add_unwind_entry (output_priunat_when_mem ());
- add_unwind_entry ((psprel
- ? output_priunat_psprel
- : output_priunat_sprel) (val));
- break;
- default:
- as_bad ("First operand not a valid register");
- }
- }
- else
- as_bad (" Second operand not a valid constant");
+ as_bad ("First operand to .%s not a register", po);
+ reg1 = REG_PR; /* Anything valid is good here. */
+ }
+ if (e2.X_op != O_constant)
+ {
+ as_bad ("Second operand to .%s not a constant", po);
+ val = 0;
+ }
+
+ switch (reg1)
+ {
+ case REG_AR + AR_BSP:
+ add_unwind_entry (output_bsp_when (), sep);
+ add_unwind_entry ((psprel
+ ? output_bsp_psprel
+ : output_bsp_sprel) (val), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_BSPSTORE:
+ add_unwind_entry (output_bspstore_when (), sep);
+ add_unwind_entry ((psprel
+ ? output_bspstore_psprel
+ : output_bspstore_sprel) (val), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_RNAT:
+ add_unwind_entry (output_rnat_when (), sep);
+ add_unwind_entry ((psprel
+ ? output_rnat_psprel
+ : output_rnat_sprel) (val), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_UNAT:
+ add_unwind_entry (output_unat_when (), sep);
+ add_unwind_entry ((psprel
+ ? output_unat_psprel
+ : output_unat_sprel) (val), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_FPSR:
+ add_unwind_entry (output_fpsr_when (), sep);
+ add_unwind_entry ((psprel
+ ? output_fpsr_psprel
+ : output_fpsr_sprel) (val), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_PFS:
+ add_unwind_entry (output_pfs_when (), sep);
+ add_unwind_entry ((psprel
+ ? output_pfs_psprel
+ : output_pfs_sprel) (val), NOT_A_CHAR);
+ break;
+ case REG_AR + AR_LC:
+ add_unwind_entry (output_lc_when (), sep);
+ add_unwind_entry ((psprel
+ ? output_lc_psprel
+ : output_lc_sprel) (val), NOT_A_CHAR);
+ break;
+ case REG_BR:
+ add_unwind_entry (output_rp_when (), sep);
+ add_unwind_entry ((psprel
+ ? output_rp_psprel
+ : output_rp_sprel) (val), NOT_A_CHAR);
+ break;
+ case REG_PR:
+ add_unwind_entry (output_preds_when (), sep);
+ add_unwind_entry ((psprel
+ ? output_preds_psprel
+ : output_preds_sprel) (val), NOT_A_CHAR);
+ break;
+ case REG_PRIUNAT:
+ add_unwind_entry (output_priunat_when_mem (), sep);
+ add_unwind_entry ((psprel
+ ? output_priunat_psprel
+ : output_priunat_sprel) (val), NOT_A_CHAR);
+ break;
+ default:
+ as_bad ("First operand to .%s not a valid register", po);
+ add_unwind_entry (NULL, sep);
+ break;
}
- else
- as_bad ("First operand not a register");
}
static void
dot_saveg (dummy)
int dummy ATTRIBUTE_UNUSED;
{
- expressionS e1, e2;
+ expressionS e;
+ unsigned grmask;
int sep;
if (!in_prologue ("save.g"))
return;
- sep = parse_operand (&e1);
- if (sep == ',')
- parse_operand (&e2);
+ sep = parse_operand (&e, ',');
- if (e1.X_op != O_constant)
- as_bad ("First operand to .save.g must be a constant.");
- else
+ grmask = e.X_add_number;
+ if (e.X_op != O_constant
+ || e.X_add_number <= 0
+ || e.X_add_number > 0xf)
{
- int grmask = e1.X_add_number;
- if (sep != ',')
- add_unwind_entry (output_gr_mem (grmask));
- else
+ as_bad ("First operand to .save.g must be a positive 4-bit constant");
+ grmask = 0;
+ }
+
+ if (sep == ',')
+ {
+ unsigned reg;
+ int n = popcount (grmask);
+
+ parse_operand (&e, 0);
+ reg = e.X_add_number - REG_GR;
+ if (e.X_op != O_register || reg > 127)
{
- int reg = e2.X_add_number - REG_GR;
- if (e2.X_op == O_register && reg >= 0 && reg < 128)
- add_unwind_entry (output_gr_gr (grmask, reg));
- else
- as_bad ("Second operand is an invalid register.");
+ as_bad ("Second operand to .save.g must be a general register");
+ reg = 0;
+ }
+ else if (reg > 128U - n)
+ {
+ as_bad ("Second operand to .save.g must be the first of %d general registers", n);
+ reg = 0;
}
+ add_unwind_entry (output_gr_gr (grmask, reg), 0);
}
+ else
+ add_unwind_entry (output_gr_mem (grmask), 0);
}
static void
dot_savef (dummy)
int dummy ATTRIBUTE_UNUSED;
{
- expressionS e1;
- int sep;
+ expressionS e;
if (!in_prologue ("save.f"))
return;
- sep = parse_operand (&e1);
+ parse_operand (&e, 0);
- if (e1.X_op != O_constant)
- as_bad ("Operand to .save.f must be a constant.");
- else
- add_unwind_entry (output_fr_mem (e1.X_add_number));
+ if (e.X_op != O_constant
+ || e.X_add_number <= 0
+ || e.X_add_number > 0xfffff)
+ {
+ as_bad ("Operand to .save.f must be a positive 20-bit constant");
+ e.X_add_number = 0;
+ }
+ add_unwind_entry (output_fr_mem (e.X_add_number), 0);
}
static void
dot_saveb (dummy)
int dummy ATTRIBUTE_UNUSED;
{
- expressionS e1, e2;
- unsigned int reg;
- unsigned char sep;
- int brmask;
+ expressionS e;
+ unsigned brmask;
+ int sep;
if (!in_prologue ("save.b"))
return;
- sep = parse_operand (&e1);
- if (e1.X_op != O_constant)
+ sep = parse_operand (&e, ',');
+
+ brmask = e.X_add_number;
+ if (e.X_op != O_constant
+ || e.X_add_number <= 0
+ || e.X_add_number > 0x1f)
{
- as_bad ("First operand to .save.b must be a constant.");
- return;
+ as_bad ("First operand to .save.b must be a positive 5-bit constant");
+ brmask = 0;
}
- brmask = e1.X_add_number;
if (sep == ',')
{
- sep = parse_operand (&e2);
- reg = e2.X_add_number - REG_GR;
- if (e2.X_op != O_register || reg > 127)
+ unsigned reg;
+ int n = popcount (brmask);
+
+ parse_operand (&e, 0);
+ reg = e.X_add_number - REG_GR;
+ if (e.X_op != O_register || reg > 127)
{
- as_bad ("Second operand to .save.b must be a general register.");
- return;
+ as_bad ("Second operand to .save.b must be a general register");
+ reg = 0;
}
- add_unwind_entry (output_br_gr (brmask, e2.X_add_number));
+ else if (reg > 128U - n)
+ {
+ as_bad ("Second operand to .save.b must be the first of %d general registers", n);
+ reg = 0;
+ }
+ add_unwind_entry (output_br_gr (brmask, reg), 0);
}
else
- add_unwind_entry (output_br_mem (brmask));
-
- if (!is_end_of_line[sep] && !is_it_end_of_statement ())
- demand_empty_rest_of_line ();
+ add_unwind_entry (output_br_mem (brmask), 0);
}
static void
@@ -3921,23 +3953,38 @@ dot_savegf (dummy)
int dummy ATTRIBUTE_UNUSED;
{
expressionS e1, e2;
- int sep;
if (!in_prologue ("save.gf"))
return;
- sep = parse_operand (&e1);
- if (sep == ',')
- parse_operand (&e2);
-
- if (e1.X_op != O_constant || sep != ',' || e2.X_op != O_constant)
- as_bad ("Both operands of .save.gf must be constants.");
+ if (parse_operand (&e1, ',') == ',')
+ parse_operand (&e2, 0);
else
+ e2.X_op = O_absent;
+
+ if (e1.X_op != O_constant
+ || e1.X_add_number < 0
+ || e1.X_add_number > 0xf)
+ {
+ as_bad ("First operand to .save.gf must be a non-negative 4-bit constant");
+ e1.X_op = O_absent;
+ e1.X_add_number = 0;
+ }
+ if (e2.X_op != O_constant
+ || e2.X_add_number < 0
+ || e2.X_add_number > 0xfffff)
{
- int grmask = e1.X_add_number;
- int frmask = e2.X_add_number;
- add_unwind_entry (output_frgr_mem (grmask, frmask));
+ as_bad ("Second operand to .save.gf must be a non-negative 20-bit constant");
+ e2.X_op = O_absent;
+ e2.X_add_number = 0;
}
+ if (e1.X_op == O_constant
+ && e2.X_op == O_constant
+ && e1.X_add_number == 0
+ && e2.X_add_number == 0)
+ as_bad ("Operands to .save.gf may not be both zero");
+
+ add_unwind_entry (output_frgr_mem (e1.X_add_number, e2.X_add_number), 0);
}
static void
@@ -3945,201 +3992,93 @@ dot_spill (dummy)
int dummy ATTRIBUTE_UNUSED;
{
expressionS e;
- unsigned char sep;
if (!in_prologue ("spill"))
return;
- sep = parse_operand (&e);
- if (!is_end_of_line[sep] && !is_it_end_of_statement ())
- demand_empty_rest_of_line ();
+ parse_operand (&e, 0);
if (e.X_op != O_constant)
- as_bad ("Operand to .spill must be a constant");
- else
- add_unwind_entry (output_spill_base (e.X_add_number));
-}
-
-static void
-dot_spillreg (dummy)
- int dummy ATTRIBUTE_UNUSED;
-{
- int sep;
- unsigned int ab, xy, reg, treg;
- expressionS e1, e2;
-
- if (!in_procedure ("spillreg"))
- return;
-
- sep = parse_operand (&e1);
- if (sep != ',')
- {
- as_bad ("No second operand to .spillreg");
- return;
- }
-
- parse_operand (&e2);
-
- if (!convert_expr_to_ab_reg (&e1, &ab, &reg))
{
- as_bad ("First operand to .spillreg must be a preserved register");
- return;
- }
-
- if (!convert_expr_to_xy_reg (&e2, &xy, &treg))
- {
- as_bad ("Second operand to .spillreg must be a register");
- return;
+ as_bad ("Operand to .spill must be a constant");
+ e.X_add_number = 0;
}
-
- add_unwind_entry (output_spill_reg (ab, reg, treg, xy));
+ add_unwind_entry (output_spill_base (e.X_add_number), 0);
}
static void
-dot_spillmem (psprel)
- int psprel;
+dot_spillreg (pred)
+ int pred;
{
- expressionS e1, e2;
int sep;
- unsigned int ab, reg;
+ unsigned int qp, ab, xy, reg, treg;
+ expressionS e;
+ const char * const po = pred ? "spillreg.p" : "spillreg";
- if (!in_procedure ("spillmem"))
+ if (!in_procedure (po))
return;
- sep = parse_operand (&e1);
- if (sep != ',')
- {
- as_bad ("Second operand missing");
- return;
- }
-
- parse_operand (&e2);
-
- if (!convert_expr_to_ab_reg (&e1, &ab, &reg))
- {
- as_bad ("First operand to .spill%s must be a preserved register",
- psprel ? "psp" : "sp");
- return;
- }
-
- if (e2.X_op != O_constant)
- {
- as_bad ("Second operand to .spill%s must be a constant",
- psprel ? "psp" : "sp");
- return;
- }
-
- if (psprel)
- add_unwind_entry (output_spill_psprel (ab, reg, e2.X_add_number));
+ if (pred)
+ sep = parse_predicate_and_operand (&e, &qp, po);
else
- add_unwind_entry (output_spill_sprel (ab, reg, e2.X_add_number));
-}
-
-static void
-dot_spillreg_p (dummy)
- int dummy ATTRIBUTE_UNUSED;
-{
- int sep;
- unsigned int ab, xy, reg, treg;
- expressionS e1, e2, e3;
- unsigned int qp;
-
- if (!in_procedure ("spillreg.p"))
- return;
-
- sep = parse_operand (&e1);
- if (sep != ',')
- {
- as_bad ("No second and third operand to .spillreg.p");
- return;
- }
-
- sep = parse_operand (&e2);
- if (sep != ',')
- {
- as_bad ("No third operand to .spillreg.p");
- return;
- }
-
- parse_operand (&e3);
-
- qp = e1.X_add_number - REG_P;
-
- if (e1.X_op != O_register || qp > 63)
- {
- as_bad ("First operand to .spillreg.p must be a predicate");
- return;
- }
-
- if (!convert_expr_to_ab_reg (&e2, &ab, &reg))
{
- as_bad ("Second operand to .spillreg.p must be a preserved register");
- return;
+ sep = parse_operand (&e, ',');
+ qp = 0;
}
+ convert_expr_to_ab_reg (&e, &ab, &reg, po, 1 + pred);
- if (!convert_expr_to_xy_reg (&e3, &xy, &treg))
- {
- as_bad ("Third operand to .spillreg.p must be a register");
- return;
- }
+ if (sep == ',')
+ sep = parse_operand (&e, ',');
+ else
+ e.X_op = O_absent;
+ convert_expr_to_xy_reg (&e, &xy, &treg, po, 2 + pred);
- add_unwind_entry (output_spill_reg_p (ab, reg, treg, xy, qp));
+ add_unwind_entry (output_spill_reg (ab, reg, treg, xy, qp), sep);
}
static void
-dot_spillmem_p (psprel)
+dot_spillmem (psprel)
int psprel;
{
- expressionS e1, e2, e3;
- int sep;
- unsigned int ab, reg;
- unsigned int qp;
-
- if (!in_procedure ("spillmem.p"))
- return;
-
- sep = parse_operand (&e1);
- if (sep != ',')
- {
- as_bad ("Second operand missing");
- return;
- }
+ expressionS e;
+ int pred = (psprel < 0), sep;
+ unsigned int qp, ab, reg;
+ const char * po;
- parse_operand (&e2);
- if (sep != ',')
+ if (pred)
{
- as_bad ("Second operand missing");
- return;
+ psprel = ~psprel;
+ po = psprel ? "spillpsp.p" : "spillsp.p";
}
+ else
+ po = psprel ? "spillpsp" : "spillsp";
- parse_operand (&e3);
-
- qp = e1.X_add_number - REG_P;
- if (e1.X_op != O_register || qp > 63)
- {
- as_bad ("First operand to .spill%s_p must be a predicate",
- psprel ? "psp" : "sp");
- return;
- }
+ if (!in_procedure (po))
+ return;
- if (!convert_expr_to_ab_reg (&e2, &ab, &reg))
+ if (pred)
+ sep = parse_predicate_and_operand (&e, &qp, po);
+ else
{
- as_bad ("Second operand to .spill%s_p must be a preserved register",
- psprel ? "psp" : "sp");
- return;
+ sep = parse_operand (&e, ',');
+ qp = 0;
}
+ convert_expr_to_ab_reg (&e, &ab, &reg, po, 1 + pred);
- if (e3.X_op != O_constant)
+ if (sep == ',')
+ sep = parse_operand (&e, ',');
+ else
+ e.X_op = O_absent;
+ if (e.X_op != O_constant)
{
- as_bad ("Third operand to .spill%s_p must be a constant",
- psprel ? "psp" : "sp");
- return;
+ as_bad ("Operand %d to .%s must be a constant", 2 + pred, po);
+ e.X_add_number = 0;
}
if (psprel)
- add_unwind_entry (output_spill_psprel_p (ab, reg, e3.X_add_number, qp));
+ add_unwind_entry (output_spill_psprel (ab, reg, e.X_add_number, qp), sep);
else
- add_unwind_entry (output_spill_sprel_p (ab, reg, e3.X_add_number, qp));
+ add_unwind_entry (output_spill_sprel (ab, reg, e.X_add_number, qp), sep);
}
static unsigned int
@@ -4206,14 +4145,15 @@ dot_label_state (dummy)
if (!in_body ("label_state"))
return;
- parse_operand (&e);
- if (e.X_op != O_constant)
+ parse_operand (&e, 0);
+ if (e.X_op == O_constant)
+ save_prologue_count (e.X_add_number, unwind.prologue_count);
+ else
{
as_bad ("Operand to .label_state must be a constant");
- return;
+ e.X_add_number = 0;
}
- add_unwind_entry (output_label_state (e.X_add_number));
- save_prologue_count (e.X_add_number, unwind.prologue_count);
+ add_unwind_entry (output_label_state (e.X_add_number), 0);
}
static void
@@ -4225,14 +4165,15 @@ dot_copy_state (dummy)
if (!in_body ("copy_state"))
return;
- parse_operand (&e);
- if (e.X_op != O_constant)
+ parse_operand (&e, 0);
+ if (e.X_op == O_constant)
+ unwind.prologue_count = get_saved_prologue_count (e.X_add_number);
+ else
{
as_bad ("Operand to .copy_state must be a constant");
- return;
+ e.X_add_number = 0;
}
- add_unwind_entry (output_copy_state (e.X_add_number));
- unwind.prologue_count = get_saved_prologue_count (e.X_add_number);
+ add_unwind_entry (output_copy_state (e.X_add_number), 0);
}
static void
@@ -4242,32 +4183,28 @@ dot_unwabi (dummy)
expressionS e1, e2;
unsigned char sep;
- if (!in_procedure ("unwabi"))
+ if (!in_prologue ("unwabi"))
return;
- sep = parse_operand (&e1);
- if (sep != ',')
- {
- as_bad ("Second operand to .unwabi missing");
- return;
- }
- sep = parse_operand (&e2);
- if (!is_end_of_line[sep] && !is_it_end_of_statement ())
- demand_empty_rest_of_line ();
+ sep = parse_operand (&e1, ',');
+ if (sep == ',')
+ parse_operand (&e2, 0);
+ else
+ e2.X_op = O_absent;
if (e1.X_op != O_constant)
{
as_bad ("First operand to .unwabi must be a constant");
- return;
+ e1.X_add_number = 0;
}
if (e2.X_op != O_constant)
{
as_bad ("Second operand to .unwabi must be a constant");
- return;
+ e2.X_add_number = 0;
}
- add_unwind_entry (output_unwabi (e1.X_add_number, e2.X_add_number));
+ add_unwind_entry (output_unwabi (e1.X_add_number, e2.X_add_number), 0);
}
static void
@@ -4374,16 +4311,14 @@ dot_body (dummy)
unwind.prologue_mask = 0;
unwind.body = 1;
- add_unwind_entry (output_body ());
- demand_empty_rest_of_line ();
+ add_unwind_entry (output_body (), 0);
}
static void
dot_prologue (dummy)
int dummy ATTRIBUTE_UNUSED;
{
- unsigned char sep;
- int mask = 0, grsave = 0;
+ unsigned mask = 0, grsave = 0;
if (!in_procedure ("prologue"))
return;
@@ -4398,36 +4333,53 @@ dot_prologue (dummy)
if (!is_it_end_of_statement ())
{
- expressionS e1, e2;
- sep = parse_operand (&e1);
- if (sep != ',')
- as_bad ("No second operand to .prologue");
- sep = parse_operand (&e2);
- if (!is_end_of_line[sep] && !is_it_end_of_statement ())
- demand_empty_rest_of_line ();
-
- if (e1.X_op == O_constant)
- {
- mask = e1.X_add_number;
+ expressionS e;
+ int n, sep = parse_operand (&e, ',');
- if (e2.X_op == O_constant)
- grsave = e2.X_add_number;
- else if (e2.X_op == O_register
- && (grsave = e2.X_add_number - REG_GR) < 128)
- ;
- else
- as_bad ("Second operand not a constant or general register");
+ if (e.X_op != O_constant
+ || e.X_add_number < 0
+ || e.X_add_number > 0xf)
+ as_bad ("First operand to .prologue must be a positive 4-bit constant");
+ else if (e.X_add_number == 0)
+ as_warn ("Pointless use of zero first operand to .prologue");
+ else
+ mask = e.X_add_number;
+ n = popcount (mask);
- add_unwind_entry (output_prologue_gr (mask, grsave));
- }
+ if (sep == ',')
+ parse_operand (&e, 0);
else
- as_bad ("First operand not a constant");
+ e.X_op = O_absent;
+ if (e.X_op == O_constant
+ && e.X_add_number >= 0
+ && e.X_add_number < 128)
+ {
+ if (md.unwind_check == unwind_check_error)
+ as_warn ("Using a constant as second operand to .prologue is deprecated");
+ grsave = e.X_add_number;
+ }
+ else if (e.X_op != O_register
+ || (grsave = e.X_add_number - REG_GR) > 127)
+ {
+ as_bad ("Second operand to .prologue must be a general register");
+ grsave = 0;
+ }
+ else if (grsave > 128U - n)
+ {
+ as_bad ("Second operand to .prologue must be the first of %d general registers", n);
+ grsave = 0;
+ }
+
}
+
+ if (mask)
+ add_unwind_entry (output_prologue_gr (mask, grsave), 0);
else
- add_unwind_entry (output_prologue ());
+ add_unwind_entry (output_prologue (), 0);
unwind.prologue = 1;
unwind.prologue_mask = mask;
+ unwind.prologue_gr = grsave;
unwind.body = 0;
++unwind.prologue_count;
}
@@ -5332,11 +5284,11 @@ const pseudo_typeS md_pseudo_table[] =
{ "fframe", dot_fframe, 0 },
{ "vframe", dot_vframe, 0 },
{ "vframesp", dot_vframesp, 0 },
- { "vframepsp", dot_vframepsp, 0 },
+ { "vframepsp", dot_vframesp, 1 },
{ "save", dot_save, 0 },
{ "restore", dot_restore, 0 },
{ "restorereg", dot_restorereg, 0 },
- { "restorereg.p", dot_restorereg_p, 0 },
+ { "restorereg.p", dot_restorereg, 1 },
{ "handlerdata", dot_handlerdata, 0 },
{ "unwentry", dot_unwentry, 0 },
{ "altrp", dot_altrp, 0 },
@@ -5350,9 +5302,9 @@ const pseudo_typeS md_pseudo_table[] =
{ "spillreg", dot_spillreg, 0 },
{ "spillsp", dot_spillmem, 0 },
{ "spillpsp", dot_spillmem, 1 },
- { "spillreg.p", dot_spillreg_p, 0 },
- { "spillsp.p", dot_spillmem_p, 0 },
- { "spillpsp.p", dot_spillmem_p, 1 },
+ { "spillreg.p", dot_spillreg, 1 },
+ { "spillsp.p", dot_spillmem, ~0 },
+ { "spillpsp.p", dot_spillmem, ~1 },
{ "label_state", dot_label_state, 0 },
{ "copy_state", dot_copy_state, 0 },
{ "unwabi", dot_unwabi, 0 },
@@ -6045,27 +5997,19 @@ operand_match (idesc, index, e)
}
static int
-parse_operand (e)
+parse_operand (e, more)
expressionS *e;
+ int more;
{
int sep = '\0';
memset (e, 0, sizeof (*e));
e->X_op = O_absent;
SKIP_WHITESPACE ();
- if (*input_line_pointer != '}')
- expression (e);
- sep = *input_line_pointer++;
-
- if (sep == '}')
- {
- if (!md.manual_bundling)
- as_warn ("Found '}' when manual bundling is off");
- else
- CURR_SLOT.manual_bundling_off = 1;
- md.manual_bundling = 0;
- sep = '\0';
- }
+ expression (e);
+ sep = *input_line_pointer;
+ if (more && (sep == ',' || sep == more))
+ ++input_line_pointer;
return sep;
}
@@ -6124,7 +6068,7 @@ parse_operands (idesc)
{
if (i < NELEMS (CURR_SLOT.opnd))
{
- sep = parse_operand (CURR_SLOT.opnd + i);
+ sep = parse_operand (CURR_SLOT.opnd + i, '=');
if (CURR_SLOT.opnd[i].X_op == O_absent)
break;
}
@@ -6132,7 +6076,7 @@ parse_operands (idesc)
{
expressionS dummy;
- sep = parse_operand (&dummy);
+ sep = parse_operand (&dummy, '=');
if (dummy.X_op == O_absent)
break;
}
@@ -6177,7 +6121,7 @@ parse_operands (idesc)
/* now we can parse the first arg: */
saved_input_pointer = input_line_pointer;
input_line_pointer = first_arg;
- sep = parse_operand (CURR_SLOT.opnd + 0);
+ sep = parse_operand (CURR_SLOT.opnd + 0, '=');
if (sep != '=')
--num_outputs; /* force error */
input_line_pointer = saved_input_pointer;
@@ -7614,6 +7558,15 @@ ia64_end_of_source ()
void
ia64_start_line ()
{
+ static int first;
+
+ if (!first) {
+ /* Make sure we don't reference input_line_pointer[-1] when that's
+ not valid. */
+ first = 1;
+ return;
+ }
+
if (md.qp.X_op == O_register)
as_bad ("qualifying predicate not followed by instruction");
md.qp.X_op = O_absent;
@@ -7636,38 +7589,8 @@ ia64_start_line ()
else
insn_group_break (1, 0, 0);
}
-}
-
-/* This is a hook for ia64_frob_label, so that it can distinguish tags from
- labels. */
-static int defining_tag = 0;
-
-int
-ia64_unrecognized_line (ch)
- int ch;
-{
- switch (ch)
+ else if (input_line_pointer[-1] == '{')
{
- case '(':
- expression (&md.qp);
- if (*input_line_pointer++ != ')')
- {
- as_bad ("Expected ')'");
- return 0;
- }
- if (md.qp.X_op != O_register)
- {
- as_bad ("Qualifying predicate expected");
- return 0;
- }
- if (md.qp.X_add_number < REG_P || md.qp.X_add_number >= REG_P + 64)
- {
- as_bad ("Predicate register expected");
- return 0;
- }
- return 1;
-
- case '{':
if (md.manual_bundling)
as_warn ("Found '{' when manual bundling is already turned on");
else
@@ -7684,9 +7607,9 @@ ia64_unrecognized_line (ch)
else
as_warn (_("Found '{' after explicit switch to automatic mode"));
}
- return 1;
-
- case '}':
+ }
+ else if (input_line_pointer[-1] == '}')
+ {
if (!md.manual_bundling)
as_warn ("Found '}' when manual bundling is off");
else
@@ -7699,17 +7622,36 @@ ia64_unrecognized_line (ch)
&& !md.mode_explicitly_set
&& !md.default_explicit_mode)
dot_dv_mode ('A');
+ }
+}
- /* Allow '{' to follow on the same line. We also allow ";;", but that
- happens automatically because ';' is an end of line marker. */
- SKIP_WHITESPACE ();
- if (input_line_pointer[0] == '{')
+/* This is a hook for ia64_frob_label, so that it can distinguish tags from
+ labels. */
+static int defining_tag = 0;
+
+int
+ia64_unrecognized_line (ch)
+ int ch;
+{
+ switch (ch)
+ {
+ case '(':
+ expression (&md.qp);
+ if (*input_line_pointer++ != ')')
{
- input_line_pointer++;
- return ia64_unrecognized_line ('{');
+ as_bad ("Expected ')'");
+ return 0;
+ }
+ if (md.qp.X_op != O_register)
+ {
+ as_bad ("Qualifying predicate expected");
+ return 0;
+ }
+ if (md.qp.X_add_number < REG_P || md.qp.X_add_number >= REG_P + 64)
+ {
+ as_bad ("Predicate register expected");
+ return 0;
}
-
- demand_empty_rest_of_line ();
return 1;
case '[':
@@ -11732,7 +11674,7 @@ dot_alias (int section)
if (name == end_name)
{
as_bad (_("expected symbol name"));
- discard_rest_of_line ();
+ ignore_rest_of_line ();
return;
}