aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2005-01-31 09:46:15 +0000
committerJan Beulich <jbeulich@novell.com>2005-01-31 09:46:15 +0000
commit75e0991382fb4617434490056616fab346359fc2 (patch)
treeee462516b5bfbb7befa70abf62d2dcf1fc5b2480 /gas
parentf4660e2c883d36c3551141051ec3917e2656f3eb (diff)
downloadgdb-75e0991382fb4617434490056616fab346359fc2.zip
gdb-75e0991382fb4617434490056616fab346359fc2.tar.gz
gdb-75e0991382fb4617434490056616fab346359fc2.tar.bz2
gas/
2005-01-31 Jan Beulich <jbeulich@novell.com> * config/tc-ia64.c (unwind): Remove proc_end (now an automatic variable in dot_endp). Add body and insn. Make prologue, prologue_mask, body, and insn bitfields. (fixup_unw_records): Remove spurious new-lines from end of diagnostic messages. (in_procedure, in_prologue, in_body): New. (dot_fframe, dot_vframe, dot_vframesp, dot_vframepsp, dot_save, dot_restore, dot_restorereg, dot_restorereg_p, dot_handlerdata, dot_unwentry, dot_altrp, dot_savemem, dot_saveg, dot_savef, dot_saveb, dot_savegf, dot_spill, dot_spillreg, dot_spillmem, dot_spillreg_p, dot_spillmem_p, dot_label_state, dot_copy_state, dot_unwabi, dot_personality): Use the appropriate one of the above. (dot_proc): Clear unwind.proc_start; set to current location only if none of the entry points were valid. Check for non-zero-length entry point names. Check that entry points aren't defined, yet. Clear unwind.prologue, unwind.body, and unwind.insn. (dot_body): Call in_procedure. Check that first directive in procedure had no insns emitted before. Set unwind.body. (dot_prologue): Call in_procedure. Check that not already in prologue. Check that first directive in procedure had no insns emitted before. Clear unwind.body. (dot_endp): Call in_procedure. Declare proc_end. Check for non-zero- length entry point names. Check that entry points became defined. (md_assemble): Set unwind.insn once unwind.proc_start is defined. gas/testsuite/ 2005-01-31 Jan Beulich <jbeulich@novell.com> * gas/ia64/proc.[ls]: New. * gas/ia64/unwind-err.[ls]: New. * gas/ia64/ia64.exp: Run new tests.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog27
-rw-r--r--gas/config/tc-ia64.c241
-rw-r--r--gas/testsuite/ChangeLog6
-rw-r--r--gas/testsuite/gas/ia64/ia64.exp2
-rw-r--r--gas/testsuite/gas/ia64/proc.l5
-rw-r--r--gas/testsuite/gas/ia64/proc.s13
-rw-r--r--gas/testsuite/gas/ia64/unwind-err.l34
-rw-r--r--gas/testsuite/gas/ia64/unwind-err.s68
8 files changed, 354 insertions, 42 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 73079cf..0af5769 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,32 @@
2005-01-31 Jan Beulich <jbeulich@novell.com>
+ * config/tc-ia64.c (unwind): Remove proc_end (now an automatic
+ variable in dot_endp). Add body and insn. Make prologue,
+ prologue_mask, body, and insn bitfields.
+ (fixup_unw_records): Remove spurious new-lines from end of diagnostic
+ messages.
+ (in_procedure, in_prologue, in_body): New.
+ (dot_fframe, dot_vframe, dot_vframesp, dot_vframepsp, dot_save,
+ dot_restore, dot_restorereg, dot_restorereg_p, dot_handlerdata,
+ dot_unwentry, dot_altrp, dot_savemem, dot_saveg, dot_savef, dot_saveb,
+ dot_savegf, dot_spill, dot_spillreg, dot_spillmem, dot_spillreg_p,
+ dot_spillmem_p, dot_label_state, dot_copy_state, dot_unwabi,
+ dot_personality): Use the appropriate one of the above.
+ (dot_proc): Clear unwind.proc_start; set to current location only if
+ none of the entry points were valid. Check for non-zero-length entry
+ point names. Check that entry points aren't defined, yet. Clear
+ unwind.prologue, unwind.body, and unwind.insn.
+ (dot_body): Call in_procedure. Check that first directive in procedure
+ had no insns emitted before. Set unwind.body.
+ (dot_prologue): Call in_procedure. Check that not already in prologue.
+ Check that first directive in procedure had no insns emitted before.
+ Clear unwind.body.
+ (dot_endp): Call in_procedure. Declare proc_end. Check for non-zero-
+ length entry point names. Check that entry points became defined.
+ (md_assemble): Set unwind.insn once unwind.proc_start is defined.
+
+2005-01-31 Jan Beulich <jbeulich@novell.com>
+
* config/tc-ia64.c (emit_one_bundle): Snapshot manual bundling state
before actually using it. Don't generate an error in manual bundling
mode when looking at an insn requiring slot 2 but not yet at slot 2.
diff --git a/gas/config/tc-ia64.c b/gas/config/tc-ia64.c
index 51bf2ed..7d87cc5 100644
--- a/gas/config/tc-ia64.c
+++ b/gas/config/tc-ia64.c
@@ -684,7 +684,6 @@ static struct
/* These are used to create the unwind table entry for this function. */
symbolS *proc_start;
- symbolS *proc_end;
symbolS *info; /* pointer to unwind info */
symbolS *personality_routine;
segT saved_text_seg;
@@ -692,8 +691,10 @@ static struct
unsigned int force_unwind_entry : 1; /* force generation of unwind entry? */
/* TRUE if processing unwind directives in a prologue region. */
- int prologue;
- int prologue_mask;
+ unsigned int prologue : 1;
+ unsigned int prologue_mask : 4;
+ unsigned int body : 1;
+ unsigned int insn : 1;
unsigned int prologue_count; /* number of .prologues seen so far */
/* Prologue counts at previous .label_state directives. */
struct label_prologue_count * saved_prologue_counts;
@@ -2785,7 +2786,7 @@ fixup_unw_records (list, before_relax)
case frgr_mem:
if (!region)
{
- as_bad ("frgr_mem record before region record!\n");
+ as_bad ("frgr_mem record before region record!");
return;
}
region->r.record.r.mask.fr_mem |= ptr->r.record.p.frmask;
@@ -2796,7 +2797,7 @@ fixup_unw_records (list, before_relax)
case fr_mem:
if (!region)
{
- as_bad ("fr_mem record before region record!\n");
+ as_bad ("fr_mem record before region record!");
return;
}
region->r.record.r.mask.fr_mem |= ptr->r.record.p.rmask;
@@ -2805,7 +2806,7 @@ fixup_unw_records (list, before_relax)
case gr_mem:
if (!region)
{
- as_bad ("gr_mem record before region record!\n");
+ as_bad ("gr_mem record before region record!");
return;
}
region->r.record.r.mask.gr_mem |= ptr->r.record.p.rmask;
@@ -2814,7 +2815,7 @@ fixup_unw_records (list, before_relax)
case br_mem:
if (!region)
{
- as_bad ("br_mem record before region record!\n");
+ as_bad ("br_mem record before region record!");
return;
}
region->r.record.r.mask.br_mem |= ptr->r.record.p.brmask;
@@ -2824,7 +2825,7 @@ fixup_unw_records (list, before_relax)
case gr_gr:
if (!region)
{
- as_bad ("gr_gr record before region record!\n");
+ as_bad ("gr_gr record before region record!");
return;
}
set_imask (region, ptr->r.record.p.grmask, t, 2);
@@ -2832,7 +2833,7 @@ fixup_unw_records (list, before_relax)
case br_gr:
if (!region)
{
- as_bad ("br_gr record before region record!\n");
+ as_bad ("br_gr record before region record!");
return;
}
set_imask (region, ptr->r.record.p.brmask, t, 3);
@@ -3067,6 +3068,43 @@ dot_special_section (which)
set_section ((char *) special_section_name[which]);
}
+static int
+in_procedure (const char *directive)
+{
+ if (unwind.proc_start
+ && (!unwind.saved_text_seg || strcmp (directive, "endp") == 0))
+ return 1;
+ as_bad (".%s outside of procedure", directive);
+ ignore_rest_of_line ();
+ return 0;
+}
+
+static int
+in_prologue (const char *directive)
+{
+ if (in_procedure (directive))
+ {
+ if (unwind.prologue)
+ return 1;
+ as_bad (".%s outside of prologue", directive);
+ ignore_rest_of_line ();
+ }
+ return 0;
+}
+
+static int
+in_body (const char *directive)
+{
+ if (in_procedure (directive))
+ {
+ if (unwind.body)
+ return 1;
+ as_bad (".%s outside of body region", directive);
+ ignore_rest_of_line ();
+ }
+ return 0;
+}
+
static void
add_unwind_entry (ptr)
unw_rec_list *ptr;
@@ -3088,6 +3126,9 @@ dot_fframe (dummy)
{
expressionS e;
+ if (!in_prologue ("fframe"))
+ return;
+
parse_operand (&e);
if (e.X_op != O_constant)
@@ -3103,6 +3144,9 @@ dot_vframe (dummy)
expressionS e;
unsigned reg;
+ if (!in_prologue ("vframe"))
+ return;
+
parse_operand (&e);
reg = e.X_add_number - REG_GR;
if (e.X_op == O_register && reg < 128)
@@ -3121,6 +3165,9 @@ dot_vframesp (dummy)
{
expressionS e;
+ if (!in_prologue ("vframesp"))
+ return;
+
parse_operand (&e);
if (e.X_op == O_constant)
{
@@ -3137,6 +3184,9 @@ dot_vframepsp (dummy)
{
expressionS e;
+ if (!in_prologue ("vframepsp"))
+ return;
+
parse_operand (&e);
if (e.X_op == O_constant)
{
@@ -3155,6 +3205,9 @@ dot_save (dummy)
int sep;
int reg1, reg2;
+ if (!in_prologue ("save"))
+ return;
+
sep = parse_operand (&e1);
if (sep != ',')
as_bad ("No second operand to .save");
@@ -3232,6 +3285,9 @@ dot_restore (dummy)
unsigned long ecount; /* # of _additional_ regions to pop */
int sep;
+ if (!in_body ("restore"))
+ return;
+
sep = parse_operand (&e1);
if (e1.X_op != O_register || e1.X_add_number != REG_GR + 12)
{
@@ -3274,6 +3330,9 @@ dot_restorereg (dummy)
unsigned int ab, reg;
expressionS e;
+ if (!in_procedure ("restorereg"))
+ return;
+
parse_operand (&e);
if (!convert_expr_to_ab_reg (&e, &ab, &reg))
@@ -3292,6 +3351,9 @@ dot_restorereg_p (dummy)
expressionS e1, e2;
int sep;
+ if (!in_procedure ("restorereg.p"))
+ return;
+
sep = parse_operand (&e1);
if (sep != ',')
{
@@ -3525,6 +3587,8 @@ static void
dot_handlerdata (dummy)
int dummy ATTRIBUTE_UNUSED;
{
+ if (!in_procedure ("handlerdata"))
+ return;
unwind.force_unwind_entry = 1;
/* Remember which segment we're in so we can switch back after .endp */
@@ -3542,6 +3606,8 @@ static void
dot_unwentry (dummy)
int dummy ATTRIBUTE_UNUSED;
{
+ if (!in_procedure ("unwentry"))
+ return;
unwind.force_unwind_entry = 1;
demand_empty_rest_of_line ();
}
@@ -3553,6 +3619,9 @@ dot_altrp (dummy)
expressionS e;
unsigned reg;
+ if (!in_prologue ("altrp"))
+ return;
+
parse_operand (&e);
reg = e.X_add_number - REG_BR;
if (e.X_op == O_register && reg < 8)
@@ -3569,6 +3638,9 @@ dot_savemem (psprel)
int sep;
int reg1, val;
+ if (!in_prologue (psprel ? "savepsp" : "savesp"))
+ return;
+
sep = parse_operand (&e1);
if (sep != ',')
as_bad ("No second operand to .save%ssp", psprel ? "p" : "");
@@ -3661,6 +3733,10 @@ dot_saveg (dummy)
{
expressionS e1, e2;
int sep;
+
+ if (!in_prologue ("save.g"))
+ return;
+
sep = parse_operand (&e1);
if (sep == ',')
parse_operand (&e2);
@@ -3689,6 +3765,10 @@ dot_savef (dummy)
{
expressionS e1;
int sep;
+
+ if (!in_prologue ("save.f"))
+ return;
+
sep = parse_operand (&e1);
if (e1.X_op != O_constant)
@@ -3706,6 +3786,9 @@ dot_saveb (dummy)
unsigned char sep;
int brmask;
+ if (!in_prologue ("save.b"))
+ return;
+
sep = parse_operand (&e1);
if (e1.X_op != O_constant)
{
@@ -3738,6 +3821,10 @@ dot_savegf (dummy)
{
expressionS e1, e2;
int sep;
+
+ if (!in_prologue ("save.gf"))
+ return;
+
sep = parse_operand (&e1);
if (sep == ',')
parse_operand (&e2);
@@ -3759,6 +3846,9 @@ dot_spill (dummy)
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 ();
@@ -3776,6 +3866,9 @@ dot_spillreg (dummy)
int sep, ab, xy, reg, treg;
expressionS e1, e2;
+ if (!in_procedure ("spillreg"))
+ return;
+
sep = parse_operand (&e1);
if (sep != ',')
{
@@ -3807,6 +3900,9 @@ dot_spillmem (psprel)
expressionS e1, e2;
int sep, ab, reg;
+ if (!in_procedure ("spillmem"))
+ return;
+
sep = parse_operand (&e1);
if (sep != ',')
{
@@ -3844,6 +3940,9 @@ dot_spillreg_p (dummy)
expressionS e1, e2, e3;
unsigned int qp;
+ if (!in_procedure ("spillreg.p"))
+ return;
+
sep = parse_operand (&e1);
if (sep != ',')
{
@@ -3891,6 +3990,9 @@ dot_spillmem_p (psprel)
int sep, ab, reg;
unsigned int qp;
+ if (!in_procedure ("spillmem.p"))
+ return;
+
sep = parse_operand (&e1);
if (sep != ',')
{
@@ -3996,6 +4098,9 @@ dot_label_state (dummy)
{
expressionS e;
+ if (!in_body ("label_state"))
+ return;
+
parse_operand (&e);
if (e.X_op != O_constant)
{
@@ -4012,6 +4117,9 @@ dot_copy_state (dummy)
{
expressionS e;
+ if (!in_body ("copy_state"))
+ return;
+
parse_operand (&e);
if (e.X_op != O_constant)
{
@@ -4029,6 +4137,9 @@ dot_unwabi (dummy)
expressionS e1, e2;
unsigned char sep;
+ if (!in_procedure ("unwabi"))
+ return;
+
sep = parse_operand (&e1);
if (sep != ',')
{
@@ -4059,6 +4170,8 @@ dot_personality (dummy)
int dummy ATTRIBUTE_UNUSED;
{
char *name, *p, c;
+ if (!in_procedure ("personality"))
+ return;
SKIP_WHITESPACE ();
name = input_line_pointer;
c = get_symbol_end ();
@@ -4077,7 +4190,7 @@ dot_proc (dummy)
char *name, *p, c;
symbolS *sym;
- unwind.proc_start = expr_build_dot ();
+ unwind.proc_start = 0;
/* Parse names of main and alternate entry points and mark them as
function symbols: */
while (1)
@@ -4086,22 +4199,34 @@ dot_proc (dummy)
name = input_line_pointer;
c = get_symbol_end ();
p = input_line_pointer;
- sym = symbol_find_or_make (name);
- if (unwind.proc_start == 0)
+ if (!*name)
+ as_bad ("Empty argument of .proc");
+ else
{
- unwind.proc_start = sym;
+ sym = symbol_find_or_make (name);
+ if (S_IS_DEFINED (sym))
+ as_bad ("`%s' was already defined", name);
+ else if (unwind.proc_start == 0)
+ {
+ unwind.proc_start = sym;
+ }
+ symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
}
- symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
*p = c;
SKIP_WHITESPACE ();
if (*input_line_pointer != ',')
break;
++input_line_pointer;
}
+ if (unwind.proc_start == 0)
+ unwind.proc_start = expr_build_dot ();
demand_empty_rest_of_line ();
ia64_do_align (16);
+ unwind.prologue = 0;
unwind.prologue_count = 0;
+ unwind.body = 0;
+ unwind.insn = 0;
unwind.list = unwind.tail = unwind.current_entry = NULL;
unwind.personality_routine = 0;
}
@@ -4110,8 +4235,14 @@ static void
dot_body (dummy)
int dummy ATTRIBUTE_UNUSED;
{
+ if (!in_procedure ("body"))
+ return;
+ if (!unwind.prologue && !unwind.body && unwind.insn)
+ as_warn ("Initial .body should precede any instructions");
+
unwind.prologue = 0;
unwind.prologue_mask = 0;
+ unwind.body = 1;
add_unwind_entry (output_body ());
demand_empty_rest_of_line ();
@@ -4124,6 +4255,17 @@ dot_prologue (dummy)
unsigned char sep;
int mask = 0, grsave = 0;
+ if (!in_procedure ("prologue"))
+ return;
+ if (unwind.prologue)
+ {
+ as_bad (".prologue within prologue");
+ ignore_rest_of_line ();
+ return;
+ }
+ if (!unwind.body && unwind.insn)
+ as_warn ("Initial .prologue should precede any instructions");
+
if (!is_it_end_of_statement ())
{
expressionS e1, e2;
@@ -4156,6 +4298,7 @@ dot_prologue (dummy)
unwind.prologue = 1;
unwind.prologue_mask = mask;
+ unwind.body = 0;
++unwind.prologue_count;
}
@@ -4172,6 +4315,9 @@ dot_endp (dummy)
char *name, *p, c;
symbolS *sym;
+ if (!in_procedure ("endp"))
+ return;
+
if (unwind.saved_text_seg)
{
saved_seg = unwind.saved_text_seg;
@@ -4192,8 +4338,10 @@ dot_endp (dummy)
if (unwind.info || unwind.force_unwind_entry)
{
+ symbolS *proc_end;
+
subseg_set (md.last_text_seg, 0);
- unwind.proc_end = expr_build_dot ();
+ proc_end = expr_build_dot ();
start_unwind_section (saved_seg, SPECIAL_SECTION_UNWIND, 0);
@@ -4217,7 +4365,7 @@ dot_endp (dummy)
e.X_op = O_pseudo_fixup;
e.X_op_symbol = pseudo_func[FUNC_SEG_RELATIVE].u.sym;
e.X_add_number = 0;
- e.X_add_symbol = unwind.proc_end;
+ e.X_add_symbol = proc_end;
ia64_cons_fix_new (frag_now, where + bytes_per_address,
bytes_per_address, &e);
@@ -4247,32 +4395,39 @@ dot_endp (dummy)
name = input_line_pointer;
c = get_symbol_end ();
p = input_line_pointer;
- sym = symbol_find (name);
- if (sym && unwind.proc_start
- && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
- && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size == NULL)
- {
- fragS *fr = symbol_get_frag (unwind.proc_start);
- fragS *frag = symbol_get_frag (sym);
-
- /* Check whether the function label is at or beyond last
- .proc directive. */
- while (fr && fr != frag)
- fr = fr->fr_next;
- if (fr)
- {
- if (frag == frag_now && SEG_NORMAL (now_seg))
- S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
- else
+ if (!*name)
+ as_bad ("Empty argument of .endp");
+ else
+ {
+ sym = symbol_find (name);
+ if (!sym || !S_IS_DEFINED (sym))
+ as_bad ("`%s' was not defined within procedure", name);
+ else if (unwind.proc_start
+ && (symbol_get_bfdsym (sym)->flags & BSF_FUNCTION)
+ && S_GET_SIZE (sym) == 0 && symbol_get_obj (sym)->size == NULL)
+ {
+ fragS *fr = symbol_get_frag (unwind.proc_start);
+ fragS *frag = symbol_get_frag (sym);
+
+ /* Check whether the function label is at or beyond last
+ .proc directive. */
+ while (fr && fr != frag)
+ fr = fr->fr_next;
+ if (fr)
{
- symbol_get_obj (sym)->size =
- (expressionS *) xmalloc (sizeof (expressionS));
- symbol_get_obj (sym)->size->X_op = O_subtract;
- symbol_get_obj (sym)->size->X_add_symbol
- = symbol_new (FAKE_LABEL_NAME, now_seg,
- frag_now_fix (), frag_now);
- symbol_get_obj (sym)->size->X_op_symbol = sym;
- symbol_get_obj (sym)->size->X_add_number = 0;
+ if (frag == frag_now && SEG_NORMAL (now_seg))
+ S_SET_SIZE (sym, frag_now_fix () - S_GET_VALUE (sym));
+ else
+ {
+ symbol_get_obj (sym)->size =
+ (expressionS *) xmalloc (sizeof (expressionS));
+ symbol_get_obj (sym)->size->X_op = O_subtract;
+ symbol_get_obj (sym)->size->X_add_symbol
+ = symbol_new (FAKE_LABEL_NAME, now_seg,
+ frag_now_fix (), frag_now);
+ symbol_get_obj (sym)->size->X_op_symbol = sym;
+ symbol_get_obj (sym)->size->X_add_number = 0;
+ }
}
}
}
@@ -4283,7 +4438,7 @@ dot_endp (dummy)
++input_line_pointer;
}
demand_empty_rest_of_line ();
- unwind.proc_start = unwind.proc_end = unwind.info = 0;
+ unwind.proc_start = unwind.info = 0;
}
static void
@@ -10213,6 +10368,8 @@ md_assemble (str)
CURR_SLOT.unwind_record = unwind.current_entry;
unwind.current_entry = NULL;
}
+ if (unwind.proc_start && S_IS_DEFINED (unwind.proc_start))
+ unwind.insn = 1;
/* Check for dependency violations. */
if (md.detect_dv)
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index bfc1de6..353e3ff 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,5 +1,11 @@
2005-01-31 Jan Beulich <jbeulich@novell.com>
+ * gas/ia64/proc.[ls]: New.
+ * gas/ia64/unwind-err.[ls]: New.
+ * gas/ia64/ia64.exp: Run new tests.
+
+2005-01-31 Jan Beulich <jbeulich@novell.com>
+
* gas/ia64/bundling.[ds]: New.
* gas/ia64/label.[ls]: New.
* gas/ia64/last.[ls]: New.
diff --git a/gas/testsuite/gas/ia64/ia64.exp b/gas/testsuite/gas/ia64/ia64.exp
index 57cea89..c5dc9e1 100644
--- a/gas/testsuite/gas/ia64/ia64.exp
+++ b/gas/testsuite/gas/ia64/ia64.exp
@@ -65,5 +65,7 @@ if [istarget "ia64-*"] then {
run_dump_test "bundling"
run_list_test "label" ""
run_list_test "last" ""
+ run_list_test "proc" ""
run_list_test "slot2" ""
+ run_list_test "unwind-err" ""
}
diff --git a/gas/testsuite/gas/ia64/proc.l b/gas/testsuite/gas/ia64/proc.l
new file mode 100644
index 0000000..8b33228
--- /dev/null
+++ b/gas/testsuite/gas/ia64/proc.l
@@ -0,0 +1,5 @@
+.*: Assembler messages:
+.*:4: Error: .* already defined.*
+.*:7: Error: .* not defined.*
+.*:12: Error: Empty argument of .proc
+.*:13: Error: Empty argument of .endp
diff --git a/gas/testsuite/gas/ia64/proc.s b/gas/testsuite/gas/ia64/proc.s
new file mode 100644
index 0000000..9225a0a
--- /dev/null
+++ b/gas/testsuite/gas/ia64/proc.s
@@ -0,0 +1,13 @@
+func1::
+ br.ret.sptk rp
+
+.proc func, func1, func2
+func::
+ br.ret.sptk rp
+.endp func, func1, func2
+
+func2::
+ br.ret.sptk rp
+
+.proc
+.endp
diff --git a/gas/testsuite/gas/ia64/unwind-err.l b/gas/testsuite/gas/ia64/unwind-err.l
new file mode 100644
index 0000000..7641df7
--- /dev/null
+++ b/gas/testsuite/gas/ia64/unwind-err.l
@@ -0,0 +1,34 @@
+.*: Assembler messages:
+.*:1: Error: .endp outside of procedure
+.*:2: Error: .personality outside of procedure
+.*:3: Error: .unwentry outside of procedure
+.*:4: Error: .unwabi outside of procedure
+.*:5: Error: .handlerdata outside of procedure
+.*:6: Error: .prologue outside of procedure
+.*: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
+.*: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
+.*:52: Error: .body outside of procedure
+.*:59: Warning: Initial .prologue.*
+.*:66: Warning: Initial .body.*
diff --git a/gas/testsuite/gas/ia64/unwind-err.s b/gas/testsuite/gas/ia64/unwind-err.s
new file mode 100644
index 0000000..49cb6c9
--- /dev/null
+++ b/gas/testsuite/gas/ia64/unwind-err.s
@@ -0,0 +1,68 @@
+.endp xyz
+.personality personality
+.unwentry
+.unwabi @svr4, 0
+.handlerdata
+.prologue
+.body
+.spillreg r4, r8
+.spillreg.p p1, r4, r8
+.spillsp r5, 0
+.spillsp.p p2, r5, 0
+.spillpsp r6, 0
+.spillpsp.p p2, r6, 0
+.restorereg r4
+.restorereg.p p1, r4
+
+.proc personality
+personality:
+.endp personality
+
+.proc start
+start:
+
+.label_state 1
+.copy_state 1
+.fframe 0
+.vframe r0
+.spill 0
+.restore sp
+.save rp, r0
+.savesp pr, 0
+.savepsp ar.fpsr, 0
+.save.g 2
+.save.gf 2,2
+.save.f 2
+.save.b 2
+.altrp b7
+.body
+
+
+ .prologue
+ .prologue
+ .save ar.lc, r31
+ mov r31 = ar.lc
+ ;;
+ .body
+ .body
+ br.ret.sptk rp
+ ;;
+.personality personality
+.handlerdata
+.body
+
+.endp start
+
+.proc late_prologue
+late_prologue:
+ nop 0
+ .prologue
+ nop 0
+.endp late_prologue
+
+.proc late_body
+late_body:
+ nop 0
+ .body
+ nop 0
+.endp late_body