aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog58
-rw-r--r--gas/config/tc-ia64.c1234
-rw-r--r--gas/testsuite/ChangeLog10
-rw-r--r--gas/testsuite/gas/ia64/group-2.s2
-rw-r--r--gas/testsuite/gas/ia64/ia64.exp3
-rw-r--r--gas/testsuite/gas/ia64/strange.d19
-rw-r--r--gas/testsuite/gas/ia64/strange.s18
-rw-r--r--gas/testsuite/gas/ia64/unwind-bad.l51
-rw-r--r--gas/testsuite/gas/ia64/unwind-bad.s155
-rw-r--r--gas/testsuite/gas/ia64/unwind-err.l37
-rw-r--r--gas/testsuite/gas/ia64/unwind-err.s1
-rw-r--r--gas/testsuite/gas/ia64/unwind-ok.d224
-rw-r--r--gas/testsuite/gas/ia64/unwind-ok.s272
13 files changed, 1419 insertions, 665 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 9798c28..2fd0e63 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,61 @@
+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.
+
2005-06-30 Zack Weinberg <zack@codesourcery.com>
* config/tc-arm.c (T_OPCODE_BRANCH, encode_arm_addr_mode_2)
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;
}
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index 8c85048..352f34a 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+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.
+
2005-06-30 Zack Weinberg <zack@codesourcery.com>
* gas/arm/arm.exp: Don't special case ldconst, arm7t, or copro
diff --git a/gas/testsuite/gas/ia64/group-2.s b/gas/testsuite/gas/ia64/group-2.s
index 6ddc94c..6b6b9fc 100644
--- a/gas/testsuite/gas/ia64/group-2.s
+++ b/gas/testsuite/gas/ia64/group-2.s
@@ -1,6 +1,6 @@
.section .gnu.linkonce.t.foo,"axG",@progbits,foo,comdat
.proc foo#
foo:
- .prologue 12, 33
+ .prologue 12, r33
;;
.endp foo#
diff --git a/gas/testsuite/gas/ia64/ia64.exp b/gas/testsuite/gas/ia64/ia64.exp
index 6199b24..8b4b999 100644
--- a/gas/testsuite/gas/ia64/ia64.exp
+++ b/gas/testsuite/gas/ia64/ia64.exp
@@ -84,7 +84,10 @@ if [istarget "ia64-*"] then {
run_list_test "proc" "-munwind-check=error"
run_list_test "radix" ""
run_list_test "slot2" ""
+ run_dump_test "strange"
+ run_list_test "unwind-bad" ""
run_list_test "unwind-err" "-munwind-check=error"
+ run_dump_test "unwind-ok"
run_dump_test "operand-or"
run_list_test "hint.b-err" ""
run_list_test "hint.b-warn" "-mhint.b=warning"
diff --git a/gas/testsuite/gas/ia64/strange.d b/gas/testsuite/gas/ia64/strange.d
new file mode 100644
index 0000000..287d073
--- /dev/null
+++ b/gas/testsuite/gas/ia64/strange.d
@@ -0,0 +1,19 @@
+#objdump: -s
+#name: ia64 strange
+
+.*: +file format .*
+
+Contents of section .text:
+ 0000 0c000000 01001000 00020000 00000400 .*
+ 0010 04000000 01000000 00000020 00000400 .*
+ 0020 0c000000 01002000 00020000 00000400 .*
+ 0030 04000000 01000000 00000040 00000400 .*
+ 0040 1c000000 01003000 00020000 00000020 .*
+ 0050 04000000 01000000 00000080 00000400 .*
+ 0060 04000000 01000000 000000a0 00000400 .*
+ 0070 04000000 01000000 000000c0 00000400 .*
+ 0080 04000000 01000000 000000e0 00000400 .*
+ 0090 0e000000 01000000 00020000 01000400 .*
+ 00a0 1d000000 01009000 00020080 00008400 .*
+Contents of section .data:
+ 0000 ffffff .*
diff --git a/gas/testsuite/gas/ia64/strange.s b/gas/testsuite/gas/ia64/strange.s
new file mode 100644
index 0000000..9a19b04
--- /dev/null
+++ b/gas/testsuite/gas/ia64/strange.s
@@ -0,0 +1,18 @@
+.explicit
+.text
+_start:
+{.mfi
+ nop.f 1 } nop.x 1
+{.mfi
+ nop.f 2
+} nop.x 2
+{.mfb
+ nop.f 3
+.xdata1 .data, -1 } .xdata1 .data, -1
+ nop.x 4 { nop.x 5
+} { nop.x 6 }
+ nop.x 7 {.mmf
+ nop.f 8
+} .xdata1 .data, -1 { .mfb
+ nop.f 9
+ br.ret.sptk rp }
diff --git a/gas/testsuite/gas/ia64/unwind-bad.l b/gas/testsuite/gas/ia64/unwind-bad.l
new file mode 100644
index 0000000..59a4b20
--- /dev/null
+++ b/gas/testsuite/gas/ia64/unwind-bad.l
@@ -0,0 +1,51 @@
+.*: Assembler messages:
+.*:8: Error: First operand to \.save\.g must be a positive 4-bit constant
+.*:10: Error: First operand to \.save\.g must be a positive 4-bit constant
+.*:12: Error: First operand to \.save\.g must be a positive 4-bit constant
+#FIXME .*:16: Error: Previous spill incomplete
+#FIXME .*:18: Error: Register r4 was already saved
+.*:20: Error: Operand to \.save\.f must be a positive 20-bit constant
+.*:22: Error: Operand to \.save\.f must be a positive 20-bit constant
+.*:24: Error: Operand to \.save\.f must be a positive 20-bit constant
+#FIXME .*:28: Error: Previous spill incomplete
+#FIXME .*:30: Error: Register f2 was already saved
+.*:32: Error: First operand to \.save\.b must be a positive 5-bit constant
+.*:34: Error: First operand to \.save\.b must be a positive 5-bit constant
+.*:36: Error: First operand to \.save\.b must be a positive 5-bit constant
+#FIXME .*:40: Error: Previous spill incomplete
+#FIXME .*:42: Error: Register b1 was already saved
+.*:44: Error: Operand 2 to \.spillreg must be a writable register
+.*:46: Error: Operand 1 to \.spillreg must be a preserved register
+.*:48: Error: Operand 1 to \.spillreg must be a preserved register
+.*:50: Error: Operand 1 to \.spillreg must be a preserved register
+.*:52: Error: Operand 2 to \.spillreg must be a writable register
+.*:54: Error: Operand 2 to \.spillreg must be a writable register
+.*:56: Error: Operand 1 to \.spillreg must be a preserved register
+#FIXME .*:58: Error: Floating point register cannot be spilled to general register
+#FIXME .*:60: Error: Floating point register cannot be spilled to branch register
+.*:62: Warning: Pointless use of p0 as first operand to \.spillreg\.p
+.*:64: Error: Operand 3 to \.spillreg.p must be a writable register
+.*:66: Error: Operand 3 to \.spillreg.p must be a writable register
+.*:68: Warning: Pointless use of p0 as first operand to \.restorereg\.p
+.*:78: Error: Operands to \.save\.gf may not be both zero
+.*:80: Error: First operand to \.save\.gf must be a non-negative 4-bit constant
+.*:82: Error: Second operand to \.save\.gf must be a non-negative 20-bit constant
+.*:84: Error: First operand to \.save\.gf must be a non-negative 4-bit constant
+.*:86: Error: Second operand to \.save\.gf must be a non-negative 20-bit constant
+#FIXME .*:90: Error: Previous spill incomplete
+#FIXME .*:92: Error: Register r4 was already saved
+#FIXME .*:94: Error: Register f2 was already saved
+.*:98: Error: Epilogue count of 2 exceeds number of nested prologues \(1\)
+.*:100: Error: Missing \.label_state 2
+.*:108: Error: First operand to \.save\.g must be a positive 4-bit constant
+#FIXME .*:110: Error: Second operand to \.save\.g must be a writable general registers
+.*:112: Error: Second operand to \.save\.g must be the first of 2 general registers
+.*:115: Error: First operand to \.save\.b must be a positive 5-bit constant
+#FIXME .*:117: Error: Second operand to \.save\.b must be a writable general registers
+.*:119: Error: Second operand to \.save\.b must be the first of 2 general registers
+.*:128: Error: First operand to \.prologue must be a positive 4-bit constant
+.*:134: Warning: Pointless use of zero first operand to \.prologue
+.*:140: Error: First operand to \.prologue must be a positive 4-bit constant
+#FIXME .*:141: Error: Operand to \.vframe must be a writable general registers
+#FIXME .*:147: Error: Second operand to \.prologue must be a writable general registers
+.*:153: Error: Second operand to \.prologue must be the first of 2 general registers
diff --git a/gas/testsuite/gas/ia64/unwind-bad.s b/gas/testsuite/gas/ia64/unwind-bad.s
new file mode 100644
index 0000000..9a4b7be
--- /dev/null
+++ b/gas/testsuite/gas/ia64/unwind-bad.s
@@ -0,0 +1,155 @@
+.text
+
+.proc full1
+full1:
+
+.prologue
+.spill 0
+.save.g 0
+ nop 0
+.save.g 0x10
+ nop 0
+.save.g -1
+ nop 0
+.save.g 0x3
+ nop 0
+.save.g 0x4
+ nop 0
+.save.g 0x1
+ nop 0
+.save.f 0
+ nop 0
+.save.f 0x100000
+ nop 0
+.save.f -1
+ nop 0
+.save.f 0x3
+ nop 0
+.save.f 0x4
+ nop 0
+.save.f 0x1
+ nop 0
+.save.b 0
+ nop 0
+.save.b 0x20
+ nop 0
+.save.b -1
+ nop 0
+.save.b 0x3
+ nop 0
+.save.b 0x4
+ nop 0
+.save.b 0x1
+ nop 0
+.spillreg r4, r0
+ nop 0
+.spillreg r3, r2
+ nop 0
+.spillreg r8, r9
+ nop 0
+.spillreg b6, r10
+ nop 0
+.spillreg f2, f0
+ nop 0
+.spillreg f3, f1
+ nop 0
+.spillreg f6, f7
+ nop 0
+.spillreg f4, r11
+ nop 0
+.spillreg f5, b0
+ nop 0
+.spillreg.p p0, r4, r3
+ nop 0
+.spillreg.p p1, r4, r0
+ nop 0
+.spillreg.p p1, f16, f0
+ nop 0
+.restorereg.p p0, r4
+ nop 0
+.body
+ br.ret.sptk rp
+.endp full1
+
+.proc full2
+full2:
+.prologue
+.spill 0
+.save.gf 0, 0
+ nop 0
+.save.gf 0x10, 0
+ nop 0
+.save.gf 0, 0x100000
+ nop 0
+.save.gf ~0, 0
+ nop 0
+.save.gf 0, ~0
+ nop 0
+.save.gf 1, 1
+ nop 0
+.save.gf 2, 0
+ nop 0
+.save.gf 1, 0
+ nop 0
+.save.gf 0, 1
+ nop 0
+.body
+.label_state 1
+.restore sp, 1
+ nop.x 0
+.copy_state 2
+ br.ret.sptk rp
+.endp full2
+
+.proc full3
+full3:
+.prologue
+.spill 0
+.save.g 0x10, r16
+ nop 0
+.save.g 0x01, r0
+ nop 0
+.save.g 0x06, r127
+ nop 0
+ nop 0
+.save.b 0x20, r16
+ nop 0
+.save.b 0x01, r0
+ nop 0
+.save.b 0x18, r127
+ nop 0
+ nop 0
+.body
+ br.ret.sptk rp
+.endp full3
+
+.proc simple1
+simple1:
+.prologue 0x10, r2
+ br.ret.sptk rp
+.endp simple1
+
+.proc simple2
+simple2:
+.prologue 0, r2
+ br.ret.sptk rp
+.endp simple2
+
+.proc simple3
+simple3:
+.prologue -1, r2
+.vframe r0
+ br.ret.sptk rp
+.endp simple3
+
+.proc simple4
+simple4:
+.prologue 0x1, r0
+ br.ret.sptk rp
+.endp simple4
+
+.proc simple5
+simple5:
+.prologue 0xc, r127
+ br.ret.sptk rp
+.endp simple5
diff --git a/gas/testsuite/gas/ia64/unwind-err.l b/gas/testsuite/gas/ia64/unwind-err.l
index 153451f..71cca18 100644
--- a/gas/testsuite/gas/ia64/unwind-err.l
+++ b/gas/testsuite/gas/ia64/unwind-err.l
@@ -8,27 +8,28 @@
.*:7: Error: .body outside of procedure
.*:8: Error: .spillreg outside of procedure
.*:9: Error: .spillreg.p outside of procedure
-.*:10: Error: .spillmem outside of procedure
-.*:11: Error: .spillmem.p outside of procedure
-.*:12: Error: .spillmem outside of procedure
-.*:13: Error: .spillmem.p outside of procedure
+.*:10: Error: .spillsp outside of procedure
+.*:11: Error: .spillsp.p outside of procedure
+.*:12: Error: .spillpsp outside of procedure
+.*:13: Error: .spillpsp.p outside of procedure
.*:14: Error: .restorereg outside of procedure
.*:15: Error: .restorereg.p outside of procedure
.*:24: Error: .label_state outside of body region
.*:25: Error: .copy_state outside of body region
.*:26: Error: .fframe outside of prologue
.*:27: Error: .vframe outside of prologue
-.*:28: Error: .spill outside of prologue
-.*:29: Error: .restore outside of body region
-.*:30: Error: .save outside of prologue
-.*:31: Error: .savesp outside of prologue
-.*:32: Error: .savepsp outside of prologue
-.*:33: Error: .save.g outside of prologue
-.*:34: Error: .save.gf outside of prologue
-.*:35: Error: .save.f outside of prologue
-.*:36: Error: .save.b outside of prologue
-.*:37: Error: .altrp outside of prologue
-.*:42: Error: .prologue within prologue
-.*:50: Error: .body outside of procedure
-.*:57: Warning: Initial .prologue.*
-.*:64: Warning: Initial .body.*
+.*:28: Error: .vframesp outside of prologue
+.*:29: Error: .spill outside of prologue
+.*:30: Error: .restore outside of body region
+.*:31: Error: .save outside of prologue
+.*:32: Error: .savesp outside of prologue
+.*:33: Error: .savepsp outside of prologue
+.*:34: Error: .save.g outside of prologue
+.*:35: Error: .save.gf outside of prologue
+.*:36: Error: .save.f outside of prologue
+.*:37: Error: .save.b outside of prologue
+.*:38: Error: .altrp outside of prologue
+.*:43: Error: .prologue within prologue
+.*:51: Error: .body outside of procedure
+.*:58: Warning: Initial .prologue.*
+.*:65: Warning: Initial .body.*
diff --git a/gas/testsuite/gas/ia64/unwind-err.s b/gas/testsuite/gas/ia64/unwind-err.s
index f50cc3d..81b2597 100644
--- a/gas/testsuite/gas/ia64/unwind-err.s
+++ b/gas/testsuite/gas/ia64/unwind-err.s
@@ -25,6 +25,7 @@ start:
.copy_state 1
.fframe 0
.vframe r0
+.vframesp 0
.spill 0
.restore sp
.save rp, r0
diff --git a/gas/testsuite/gas/ia64/unwind-ok.d b/gas/testsuite/gas/ia64/unwind-ok.d
new file mode 100644
index 0000000..d35d6de
--- /dev/null
+++ b/gas/testsuite/gas/ia64/unwind-ok.d
@@ -0,0 +1,224 @@
+#readelf: -u
+#name: ia64 unwind descriptors
+
+Unwind section '\.IA_64\.unwind' at offset 0x[[:xdigit:]]+ contains 8 entries:
+
+<full1>: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08]
+[[:space:]]*v[[:digit:]]+, flags=0x3 \( ?ehandler uhandler\), len=[[:digit:]]+ bytes
+[[:space:]]*R1:prologue\(rlen=8\)
+[[:space:]]*P6:fr_mem\(frmask=\[f2,f5\]\)
+[[:space:]]*P6:gr_mem\(grmask=\[r4,r7\]\)
+[[:space:]]*P1:br_mem\(brmask=\[b1,b5\]\)
+[[:space:]]*P4:spill_mask\(imask=\[rfb,rfb,--\]\)
+[[:space:]]*P7:spill_base\(pspoff=0x10-0x10\)
+[[:space:]]*P3:rp_br\(reg=b7\)
+[[:space:]]*P10:unwabi\(abi=@svr4,context=0x00\)
+[[:space:]]*R1:body\(rlen=[[:digit:]]+\)
+[[:space:]]*X2:spill_reg\(t=0,reg=r4,treg=r2\)
+[[:space:]]*X4:spill_reg_p\(qp=p1,t=1,reg=r7,treg=r31\)
+[[:space:]]*X1:spill_sprel\(reg=b1,t=2,spoff=0x8\)
+[[:space:]]*X3:spill_sprel_p\(qp=p2,t=3,reg=b5,spoff=0x10\)
+[[:space:]]*X1:spill_psprel\(reg=f2,t=4,pspoff=0x10-0x28\)
+[[:space:]]*X3:spill_psprel_p\(qp=p4,t=5,reg=f5,pspoff=0x10-0x30\)
+[[:space:]]*X2:restore\(t=6,reg=f16\)
+[[:space:]]*X4:restore_p\(qp=p8,t=7,reg=f31\)
+[[:space:]]*X2:spill_reg\(t=8,reg=ar\.bsp,treg=r16\)
+[[:space:]]*X2:spill_reg\(t=9,reg=ar\.bspstore,treg=r17\)
+[[:space:]]*X2:spill_reg\(t=10,reg=ar\.fpsr,treg=r18\)
+[[:space:]]*X2:spill_reg\(t=11,reg=ar\.lc,treg=r19\)
+[[:space:]]*X2:spill_reg\(t=12,reg=ar\.pfs,treg=r20\)
+[[:space:]]*X2:spill_reg\(t=13,reg=ar\.rnat,treg=r21\)
+[[:space:]]*X2:spill_reg\(t=14,reg=ar\.unat,treg=r22\)
+[[:space:]]*X2:spill_reg\(t=15,reg=psp,treg=r23\)
+[[:space:]]*X2:spill_reg\(t=16,reg=pr,treg=r24\)
+[[:space:]]*X2:spill_reg\(t=17,reg=rp,treg=r25\)
+[[:space:]]*X2:spill_reg\(t=18,reg=@priunat,treg=r26\)
+[[:space:]]*B1:label_state\(label=1\)
+[[:space:]]*B2:epilogue\(t=4,ecount=0\)
+[[:space:]]*B1:copy_state\(label=1\)
+#...
+<full2>: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08]
+[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes
+[[:space:]]*R2:prologue_gr\(mask=\[rp,psp,pr\],grsave=r8,rlen=14\)
+[[:space:]]*P5:frgr_mem\(grmask=\[r4,r7\],frmask=\[f2,f31\]\)
+[[:space:]]*P4:spill_mask\(imask=\[b-b,bb-,---,---,--\]\)
+[[:space:]]*P7:spill_base\(pspoff=0x10-0x10\)
+[[:space:]]*P2:br_gr\(brmask=\[b1,b5\],gr=r32\)
+[[:space:]]*X2:spill_reg\(t=6,reg=f31,treg=f31\)
+[[:space:]]*X4:spill_reg_p\(qp=p63,t=7,reg=f16,treg=f0\)
+[[:space:]]*X1:spill_sprel\(reg=f5,t=8,spoff=0x20\)
+[[:space:]]*X3:spill_sprel_p\(qp=p31,t=9,reg=f2,spoff=0x18\)
+[[:space:]]*X1:spill_psprel\(reg=b5,t=10,pspoff=0x10-0x20\)
+[[:space:]]*X3:spill_psprel_p\(qp=p15,t=11,reg=b1,pspoff=0x10-0x18\)
+[[:space:]]*X2:restore\(t=12,reg=r7\)
+[[:space:]]*X4:restore_p\(qp=p7,t=13,reg=r4\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=0\)
+[[:space:]]*R1:prologue\(rlen=0\)
+[[:space:]]*R1:body\(rlen=7\)
+[[:space:]]*B4:label_state\(label=32\)
+[[:space:]]*B3:epilogue\(t=4,ecount=32\)
+[[:space:]]*B4:copy_state\(label=32\)
+#...
+<full3>: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08]
+[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes
+[[:space:]]*R3:prologue\(rlen=33\)
+[[:space:]]*P4:spill_mask\(imask=\[rrb,brr,bb-,---,---,---,---,---,---,---,---\]\)
+[[:space:]]*P7:spill_base\(pspoff=0x10-0x10\)
+[[:space:]]*P9:gr_gr\(grmask=\[r4,r5\],r32\)
+[[:space:]]*P2:br_gr\(brmask=\[b1,b2\],gr=r34\)
+[[:space:]]*P9:gr_gr\(grmask=\[r6,r7\],r124\)
+[[:space:]]*P2:br_gr\(brmask=\[b4,b5\],gr=r126\)
+[[:space:]]*R3:body\(rlen=33\)
+#...
+<fframe>: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08]
+[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes
+[[:space:]]*R1:prologue\(rlen=1\)
+[[:space:]]*P7:mem_stack_f\(t=0,size=0\)
+[[:space:]]*R1:body\(rlen=2\)
+#...
+<vframe>: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08]
+[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes
+[[:space:]]*R1:prologue\(rlen=11\)
+[[:space:]]*P7:mem_stack_v\(t=0\)
+[[:space:]]*P3:psp_gr\(reg=r16\)
+[[:space:]]*P8:bsp_when\(t=1\)
+[[:space:]]*P3:bsp_gr\(reg=r17\)
+[[:space:]]*P8:bspstore_when\(t=2\)
+[[:space:]]*P3:bspstore_gr\(reg=r18\)
+[[:space:]]*P7:fpsr_when\(t=3\)
+[[:space:]]*P3:fpsr_gr\(reg=r19\)
+[[:space:]]*P7:lc_when\(t=4\)
+[[:space:]]*P3:lc_gr\(reg=r20\)
+[[:space:]]*P7:pfs_when\(t=5\)
+[[:space:]]*P3:pfs_gr\(reg=r21\)
+[[:space:]]*P8:rnat_when\(t=6\)
+[[:space:]]*P3:rnat_gr\(reg=r22\)
+[[:space:]]*P7:unat_when\(t=7\)
+[[:space:]]*P3:unat_gr\(reg=r23\)
+[[:space:]]*P7:pr_when\(t=8\)
+[[:space:]]*P3:pr_gr\(reg=r24\)
+[[:space:]]*P8:priunat_when_gr\(t=9\)
+[[:space:]]*P3:priunat_gr\(reg=r25\)
+[[:space:]]*P7:rp_when\(t=10\)
+[[:space:]]*P3:rp_gr\(reg=r26\)
+[[:space:]]*R1:body\(rlen=1\)
+#...
+<vframesp>: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08]
+[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes
+[[:space:]]*R1:prologue\(rlen=11\)
+[[:space:]]*P7:mem_stack_v\(t=0\)
+[[:space:]]*P7:psp_sprel\(spoff=0x0\)
+[[:space:]]*P8:bsp_when\(t=1\)
+[[:space:]]*P8:bsp_sprel\(spoff=0x8\)
+[[:space:]]*P8:bspstore_when\(t=2\)
+[[:space:]]*P8:bspstore_sprel\(spoff=0x10\)
+[[:space:]]*P7:fpsr_when\(t=3\)
+[[:space:]]*P8:fpsr_sprel\(spoff=0x18\)
+[[:space:]]*P7:lc_when\(t=4\)
+[[:space:]]*P8:lc_sprel\(spoff=0x20\)
+[[:space:]]*P7:pfs_when\(t=5\)
+[[:space:]]*P8:pfs_sprel\(spoff=0x28\)
+[[:space:]]*P8:rnat_when\(t=6\)
+[[:space:]]*P8:rnat_sprel\(spoff=0x30\)
+[[:space:]]*P7:unat_when\(t=7\)
+[[:space:]]*P8:unat_sprel\(spoff=0x38\)
+[[:space:]]*P7:pr_when\(t=8\)
+[[:space:]]*P8:pr_sprel\(spoff=0x40\)
+[[:space:]]*P8:priunat_when_mem\(t=9\)
+[[:space:]]*P8:priunat_sprel\(spoff=0x48\)
+[[:space:]]*P7:rp_when\(t=10\)
+[[:space:]]*P8:rp_sprel\(spoff=0x50\)
+[[:space:]]*R1:body\(rlen=1\)
+#...
+<psp>: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08]
+[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes
+[[:space:]]*R1:prologue\(rlen=11\)
+[[:space:]]*P7:mem_stack_v\(t=0\)
+[[:space:]]*P7:psp_sprel\(spoff=0x0\)
+[[:space:]]*P8:bsp_when\(t=1\)
+[[:space:]]*P8:bsp_psprel\(pspoff=0x10-0x18\)
+[[:space:]]*P8:bspstore_when\(t=2\)
+[[:space:]]*P8:bspstore_psprel\(pspoff=0x10-0x20\)
+[[:space:]]*P7:fpsr_when\(t=3\)
+[[:space:]]*P7:fpsr_psprel\(pspoff=0x10-0x28\)
+[[:space:]]*P7:lc_when\(t=4\)
+[[:space:]]*P7:lc_psprel\(pspoff=0x10-0x30\)
+[[:space:]]*P7:pfs_when\(t=5\)
+[[:space:]]*P7:pfs_psprel\(pspoff=0x10-0x38\)
+[[:space:]]*P8:rnat_when\(t=6\)
+[[:space:]]*P8:rnat_psprel\(pspoff=0x10-0x40\)
+[[:space:]]*P7:unat_when\(t=7\)
+[[:space:]]*P7:unat_psprel\(pspoff=0x10-0x48\)
+[[:space:]]*P7:pr_when\(t=8\)
+[[:space:]]*P7:pr_psprel\(pspoff=0x10-0x50\)
+[[:space:]]*P8:priunat_when_mem\(t=9\)
+[[:space:]]*P8:priunat_psprel\(pspoff=0x10-0x58\)
+[[:space:]]*P7:rp_when\(t=10\)
+[[:space:]]*P7:rp_psprel\(pspoff=0x10-0x60\)
+[[:space:]]*R1:body\(rlen=1\)
+#...
+<simple>: \[0x[[:xdigit:]]*0-0x[[:xdigit:]]*0\], info at \+0x[[:xdigit:]]*[08]
+[[:space:]]*v[[:digit:]]+, flags=0x0( \(\))?, len=[[:digit:]]+ bytes
+#pass
diff --git a/gas/testsuite/gas/ia64/unwind-ok.s b/gas/testsuite/gas/ia64/unwind-ok.s
new file mode 100644
index 0000000..f2cc0cf
--- /dev/null
+++ b/gas/testsuite/gas/ia64/unwind-ok.s
@@ -0,0 +1,272 @@
+.text
+.proc personality
+personality:
+ br.ret.sptk rp
+.endp personality
+
+.proc full1
+full1:
+
+.prologue
+.spill 0
+.save.g 0x1
+ nop 0
+.save.f 0x1
+ nop 0
+.save.b 0x01
+ nop 0
+.save.g 0x8
+ nop 0
+.save.f 0x8
+ nop 0
+.save.b 0x10
+ nop 0
+.altrp b7
+ nop 0
+.unwabi @svr4, 0
+ nop 0
+
+.body
+.spillreg r4, r2
+ nop 0
+.spillreg.p p1, r7, r127
+ nop 0
+.spillsp b1, 0x08
+ nop 0
+.spillsp.p p2, b5, 0x10
+ nop 0
+.spillpsp f2, 0x18
+ nop 0
+.spillpsp.p p4, f5, 0x20
+ nop 0
+.restorereg f16
+ nop 0
+.restorereg.p p8, f31
+ nop 0
+
+.spillreg ar.bsp, r16
+ nop 0
+.spillreg ar.bspstore, r17
+ nop 0
+.spillreg ar.fpsr, r18
+ nop 0
+.spillreg ar.lc, r19
+ nop 0
+.spillreg ar.pfs, r20
+ nop 0
+.spillreg ar.rnat, r21
+ nop 0
+.spillreg ar.unat, r22
+ nop 0
+.spillreg psp, r23
+ nop 0
+.spillreg pr, r24
+ nop 0
+.spillreg rp, r25
+ nop 0
+.spillreg @priunat, r26
+ nop 0
+
+.label_state 1
+ nop 0
+.restore sp
+ nop.x 0
+.copy_state 1
+ br.ret.sptk rp
+
+.personality personality
+.handlerdata
+ data4 -1
+ data4 0
+
+.endp full1
+
+.proc full2
+full2:
+
+.prologue 0xb, r8
+.spill 0
+.save.gf 0x1, 0x00001
+ nop 0
+ nop 0
+.save.b 0x11, r32
+ nop 0
+ nop 0
+.save.gf 0x8, 0x80000
+ nop 0
+ nop 0
+.spillreg f31, f127
+ nop 0
+.spillreg.p p63, f16, f32
+ nop 0
+.spillsp f5, 0x20
+ nop 0
+.spillsp.p p31, f2, 0x18
+ nop 0
+.spillpsp b5, 0x10
+ nop 0
+.spillpsp.p p15, b1, 0x08
+ nop 0
+.restorereg r7
+ nop 0
+.restorereg.p p7, r4
+ nop 0
+
+.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue
+.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue
+.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue
+.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue
+.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue
+.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue
+.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue
+.body; .prologue; .body; .prologue; .body; .prologue; .body; .prologue
+
+.body
+.label_state 32
+ nop 0
+.restore sp, 32
+ nop.x 0
+.copy_state 32
+ br.ret.sptk rp
+.endp full2
+
+.proc full3
+full3:
+
+.prologue
+.spill 0
+.save.g 0x3, r32
+ nop 0
+ nop 0
+.save.b 0x03, r34
+ nop 0
+ nop 0
+.save.g 0xc, r124
+ nop 0
+ nop 0
+.save.b 0x18, r126
+ nop 0
+ nop 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+.body
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ nop.x 0
+ br.ret.sptk rp
+.endp full3
+
+.proc fframe
+fframe:
+.prologue
+.fframe 0
+ nop 0
+.body
+ br.ret.sptk rp
+.endp fframe
+
+.proc vframe
+vframe:
+.prologue
+.vframe r16
+ nop 0
+.save ar.bsp, r17
+ nop 0
+.save ar.bspstore, r18
+ nop 0
+.save ar.fpsr, r19
+ nop 0
+.save ar.lc, r20
+ nop 0
+.save ar.pfs, r21
+ nop 0
+.save ar.rnat, r22
+ nop 0
+.save ar.unat, r23
+ nop 0
+.save pr, r24
+ nop 0
+.save @priunat, r25
+ nop 0
+.save rp, r26
+ nop 0
+.body
+ br.ret.sptk rp
+.endp vframe
+
+.proc vframesp
+vframesp:
+.prologue
+.vframesp 0
+ nop 0
+.savesp ar.bsp, 0x08
+ nop 0
+.savesp ar.bspstore, 0x10
+ nop 0
+.savesp ar.fpsr, 0x18
+ nop 0
+.savesp ar.lc, 0x20
+ nop 0
+.savesp ar.pfs, 0x28
+ nop 0
+.savesp ar.rnat, 0x30
+ nop 0
+.savesp ar.unat, 0x38
+ nop 0
+.savesp pr, 0x40
+ nop 0
+.savesp @priunat, 0x48
+ nop 0
+.savesp rp, 0x50
+ nop 0
+.body
+ br.ret.sptk rp
+.endp vframesp
+
+.proc psp
+psp:
+.prologue
+.vframesp 0
+ nop 0
+.savepsp ar.bsp, 0x08
+ nop 0
+.savepsp ar.bspstore, 0x10
+ nop 0
+.savepsp ar.fpsr, 0x18
+ nop 0
+.savepsp ar.lc, 0x20
+ nop 0
+.savepsp ar.pfs, 0x28
+ nop 0
+.savepsp ar.rnat, 0x30
+ nop 0
+.savepsp ar.unat, 0x38
+ nop 0
+.savepsp pr, 0x40
+ nop 0
+.savepsp @priunat, 0x48
+ nop 0
+.savepsp rp, 0x50
+ nop 0
+.body
+ br.ret.sptk rp
+.endp psp
+
+.proc simple
+simple:
+.unwentry
+ br.ret.sptk rp
+.endp simple