Patchwork [ia64] Cleanup unwind info annotations

login
register
mail settings
Submitter Richard Henderson
Date Sept. 21, 2010, 9:32 p.m.
Message ID <4C992488.40804@redhat.com>
Download mbox | patch
Permalink /patch/65380/
State New
Headers show

Comments

Richard Henderson - Sept. 21, 2010, 9:32 p.m.
In the "Hookize TARGET_UNWIND_INFO" thread we found a number of
problems with the generic dwarf2 interpretation of the 
RTX_FRAME_RELATED_P insns.  While we don't actually emit dwarf2
unwind info for this target, we do convert the unwind info into
location lists for pre-dwarf3 DW_AT_frame_base.

This patch avoids all of the guesswork in dwarf2out_frame_debug_expr
by using the very specific REG_CFA_* notes.  At the same time, we
get to clean up the similar guesswork in the backend which emits
the ia64 unwind info.

I've successfully built to stage3 with this patch (standalone,
not on top of the "hookize" patch).  However, I get comparison
failures before and after the patch:

Bootstrap comparison failure!
gcc/cp/decl.o differs
gcc/cp/name-lookup.o differs

by which I conclude that ia64-linux isn't in great shape at the
moment.  I'll keep digging into this, but thought I should pass
on the patch anyway.

Comments appreciated.


r~
Steven Bosscher - Sept. 21, 2010, 10:07 p.m.
On Tue, Sep 21, 2010 at 11:32 PM, Richard Henderson <rth@redhat.com> wrote:
> Bootstrap comparison failure!
> gcc/cp/decl.o differs
> gcc/cp/name-lookup.o differs

Appears to work for HJ:

http://gcc.gnu.org/ml/gcc-testresults/2010-09/msg01971.html

Ciao!
Steven
Richard Henderson - Sept. 22, 2010, 4:24 p.m.
On 09/21/2010 03:07 PM, Steven Bosscher wrote:
> On Tue, Sep 21, 2010 at 11:32 PM, Richard Henderson <rth@redhat.com> wrote:
>> Bootstrap comparison failure!
>> gcc/cp/decl.o differs
>> gcc/cp/name-lookup.o differs
> 
> Appears to work for HJ:
> 
> http://gcc.gnu.org/ml/gcc-testresults/2010-09/msg01971.html

Well now, I wonder what's different?  I checked out that exact
svn revision and still get the same comparison failure.


r~
Steve Ellcey - Sept. 22, 2010, 4:51 p.m.
On Wed, 2010-09-22 at 09:24 -0700, Richard Henderson wrote:
> On 09/21/2010 03:07 PM, Steven Bosscher wrote:
> > On Tue, Sep 21, 2010 at 11:32 PM, Richard Henderson <rth@redhat.com> wrote:
> >> Bootstrap comparison failure!
> >> gcc/cp/decl.o differs
> >> gcc/cp/name-lookup.o differs
> > 
> > Appears to work for HJ:
> > 
> > http://gcc.gnu.org/ml/gcc-testresults/2010-09/msg01971.html
> 
> Well now, I wonder what's different?  I checked out that exact
> svn revision and still get the same comparison failure.
> 
> 
> r~

I don't have that exact version but I built 164472 (no local changes)
and that worked fine with no comparision failures.  I did recently have
to update the GCC in my build environment to fix a problem caused by a
bug in GCC 4.3.3.

Steve Ellcey
sje@cup.hp.com
Richard Henderson - Sept. 23, 2010, 4:27 p.m.
On 09/22/2010 09:51 AM, Steve Ellcey wrote:
> I don't have that exact version but I built 164472 (no local changes)
> and that worked fine with no comparision failures.  I did recently have
> to update the GCC in my build environment to fix a problem caused by a
> bug in GCC 4.3.3.

Good to know.  I updated binutils and successfully performed a 4-stage
build of c,c++ with gcc3.4 as the bootstrap compiler.

I'll try again with the unwind info patch.


r~
Richard Henderson - Sept. 23, 2010, 8:51 p.m.
On 09/23/2010 09:27 AM, Richard Henderson wrote:
> On 09/22/2010 09:51 AM, Steve Ellcey wrote:
>> I don't have that exact version but I built 164472 (no local changes)
>> and that worked fine with no comparision failures.  I did recently have
>> to update the GCC in my build environment to fix a problem caused by a
>> bug in GCC 4.3.3.
> 
> Good to know.  I updated binutils and successfully performed a 4-stage
> build of c,c++ with gcc3.4 as the bootstrap compiler.
> 
> I'll try again with the unwind info patch.

I've completed testing on ia64-linux.

I've bootstrapped the compiler with and without the patch.  I used
BOOT_CFLAGS='-O2 -g --save-temps' and then compared the .s files 
from stage2 (which gets -gtoggle and thus -g0, thus ignoring the
debug differences caused by different build paths).  There were no
differences at all, except those expected by the patched ia64.c.

Thus I conclude that the unwind directives are identical with and
without the patch.

Is the patch ok?


r~
Steve Ellcey - Sept. 23, 2010, 9:15 p.m.
On Thu, 2010-09-23 at 13:51 -0700, Richard Henderson wrote:
> On 09/23/2010 09:27 AM, Richard Henderson wrote:
> > On 09/22/2010 09:51 AM, Steve Ellcey wrote:
> >> I don't have that exact version but I built 164472 (no local changes)
> >> and that worked fine with no comparision failures.  I did recently have
> >> to update the GCC in my build environment to fix a problem caused by a
> >> bug in GCC 4.3.3.
> > 
> > Good to know.  I updated binutils and successfully performed a 4-stage
> > build of c,c++ with gcc3.4 as the bootstrap compiler.
> > 
> > I'll try again with the unwind info patch.
> 
> I've completed testing on ia64-linux.
> 
> I've bootstrapped the compiler with and without the patch.  I used
> BOOT_CFLAGS='-O2 -g --save-temps' and then compared the .s files 
> from stage2 (which gets -gtoggle and thus -g0, thus ignoring the
> debug differences caused by different build paths).  There were no
> differences at all, except those expected by the patched ia64.c.
> 
> Thus I conclude that the unwind directives are identical with and
> without the patch.
> 
> Is the patch ok?
> 
> 
> r~

I'm confused.  Which patch are we talking about here?  Do we think
things will work on IA64 HP-UX now?  My comments about testing were on
sources without your patch included, I was just confirming that I could
build IA64 Linux (without your patch and without any local changes)
without getting the diff errors that you got during bootstrap.

Steve Ellcey
sje@cup.hp.com
Richard Henderson - Sept. 23, 2010, 9:39 p.m.
On 09/23/2010 02:15 PM, Steve Ellcey wrote:
> I'm confused.  Which patch are we talking about here?  Do we think
> things will work on IA64 HP-UX now?  My comments about testing were on
> sources without your patch included, I was just confirming that I could
> build IA64 Linux (without your patch and without any local changes)
> without getting the diff errors that you got during bootstrap.

Just the patch at the top of this thread (gcc.gnu.org is down atm,
or I'd give you a link).  It rearranges the generation of the unwind
info so that there's none of the guesswork that caused failures on
hpux when the TARGET_UNWIND_INFO patch was applied.

I believe that with the unwind-info cleanup patch applied, that the
subsequent TARGET_UNWIND_INFO patch will work on ia64-hpux, yes.


r~
Steve Ellcey - Sept. 23, 2010, 9:53 p.m.
On Thu, 2010-09-23 at 14:39 -0700, Richard Henderson wrote:

> Just the patch at the top of this thread (gcc.gnu.org is down atm,
> or I'd give you a link).  It rearranges the generation of the unwind
> info so that there's none of the guesswork that caused failures on
> hpux when the TARGET_UNWIND_INFO patch was applied.
> 
> I believe that with the unwind-info cleanup patch applied, that the
> subsequent TARGET_UNWIND_INFO patch will work on ia64-hpux, yes.
> 
> 
> r~

OK, I found the patch.  It looks OK to me, but I'd like to test it in my
HP-UX and Linux builds tonight before you check it in.

Steve Ellcey
sje@cup.hp.com
Steve Ellcey - Sept. 24, 2010, 7:48 p.m.
On Thu, 2010-09-23 at 14:39 -0700, Richard Henderson wrote:
> On 09/23/2010 02:15 PM, Steve Ellcey wrote:
> > I'm confused.  Which patch are we talking about here?  Do we think
> > things will work on IA64 HP-UX now?  My comments about testing were on
> > sources without your patch included, I was just confirming that I could
> > build IA64 Linux (without your patch and without any local changes)
> > without getting the diff errors that you got during bootstrap.
> 
> Just the patch at the top of this thread (gcc.gnu.org is down atm,
> or I'd give you a link).  It rearranges the generation of the unwind
> info so that there's none of the guesswork that caused failures on
> hpux when the TARGET_UNWIND_INFO patch was applied.
> 
> I believe that with the unwind-info cleanup patch applied, that the
> subsequent TARGET_UNWIND_INFO patch will work on ia64-hpux, yes.
> 
> 
> r~

The patch didn't compile on HP-UX due to a format issue, using %ld on
HOST_WIDE_INT variables.  HOST_WIDE_INT is 'long long' on HP-UX:

/proj/opensrc/nightly/src/trunk/gcc/config/ia64/ia64.c: In function
'process_cfa_offset':
/proj/opensrc/nightly/src/trunk/gcc/config/ia64/ia64.c:9782:2: error:
format '%ld' expects type 'long int', but argument 4 has type 'long long
int' [-Werror=format]
/proj/opensrc/nightly/src/trunk/gcc/config/ia64/ia64.c:9788:2: error:
format '%ld' expects type 'long int', but argument 4 has type 'long long
int' [-Werror=format]
/proj/opensrc/nightly/src/trunk/gcc/config/ia64/ia64.c:9794:2: error:
format '%ld' expects type 'long int', but argument 4 has type 'long long
int' [-Werror=format]
/proj/opensrc/nightly/src/trunk/gcc/config/ia64/ia64.c:9800:2: error:
format '%ld' expects type 'long int', but argument 4 has type 'long long
int' [-Werror=format]
/proj/opensrc/nightly/src/trunk/gcc/config/ia64/ia64.c:9806:2: error:
format '%ld' expects type 'long int', but argument 4 has type 'long long
int' [-Werror=format]
cc1: all warnings being treated as errors

I changed the '%ld' to 'HOST_WIDE_INT_PRINT_DEC' and then it compiled
and I didn't see any regressions in the test run, so I would say that
the patch is OK with the format change.

Steve Ellcey
sje@cup.hp.com

Patch

diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index d02d2b8..b63303f 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -230,7 +230,6 @@  static void emit_predicate_relation_info (void);
 static void ia64_reorg (void);
 static bool ia64_in_small_data_p (const_tree);
 static void process_epilogue (FILE *, rtx, bool, bool);
-static int process_set (FILE *, rtx, rtx, bool, bool);
 
 static bool ia64_assemble_integer (rtx, unsigned int, int);
 static void ia64_output_function_prologue (FILE *, HOST_WIDE_INT);
@@ -318,6 +317,8 @@  static enum machine_mode ia64_promote_function_mode (const_tree,
 						     int);
 static void ia64_trampoline_init (rtx, tree, rtx);
 static void ia64_override_options_after_change (void);
+
+static void ia64_dwarf_handle_frame_unspec (const char *, rtx, int);
 
 /* Table of valid machine attributes.  */
 static const struct attribute_spec ia64_attribute_table[] =
@@ -527,6 +528,8 @@  static const struct attribute_spec ia64_attribute_table[] =
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg
 
+#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
+#define TARGET_DWARF_HANDLE_FRAME_UNSPEC  ia64_dwarf_handle_frame_unspec
 #undef TARGET_ASM_UNWIND_EMIT
 #define TARGET_ASM_UNWIND_EMIT ia64_asm_unwind_emit
 #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
@@ -3035,7 +3038,7 @@  do_spill (rtx (*move_fn) (rtx, rtx, rtx), rtx reg, HOST_WIDE_INT cfa_off,
 	  off = current_frame_info.total_size - cfa_off;
 	}
 
-      add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+      add_reg_note (insn, REG_CFA_OFFSET,
 		    gen_rtx_SET (VOIDmode,
 				 gen_rtx_MEM (GET_MODE (reg),
 					      plus_constant (base, off)),
@@ -3219,6 +3222,10 @@  ia64_expand_prologue (void)
     {
       insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* Force the unwind info to recognize this as defining a new CFA,
+	 rather than some temp register setup.  */
+      add_reg_note (insn, REG_CFA_ADJUST_CFA, NULL_RTX);
     }
 
   if (current_frame_info.total_size != 0)
@@ -3241,13 +3248,12 @@  ia64_expand_prologue (void)
       if (! frame_pointer_needed)
 	{
 	  RTX_FRAME_RELATED_P (insn) = 1;
-	  if (GET_CODE (offset) != CONST_INT)
-	    add_reg_note (insn, REG_FRAME_RELATED_EXPR,
-			  gen_rtx_SET (VOIDmode,
-				       stack_pointer_rtx,
-				       gen_rtx_PLUS (DImode,
-						     stack_pointer_rtx,
-						     frame_size_rtx)));
+	  add_reg_note (insn, REG_CFA_ADJUST_CFA,
+			gen_rtx_SET (VOIDmode,
+				     stack_pointer_rtx,
+				     gen_rtx_PLUS (DImode,
+						   stack_pointer_rtx,
+						   frame_size_rtx)));
 	}
 
       /* ??? At this point we must generate a magic insn that appears to
@@ -3275,7 +3281,11 @@  ia64_expand_prologue (void)
 
       reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM);
       insn = emit_move_insn (ar_unat_save_reg, reg);
-      RTX_FRAME_RELATED_P (insn) = (current_frame_info.r[reg_save_ar_unat] != 0);
+      if (current_frame_info.r[reg_save_ar_unat])
+	{
+	  RTX_FRAME_RELATED_P (insn) = 1;
+	  add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
+	}
 
       /* Even if we're not going to generate an epilogue, we still
 	 need to save the register so that EH works.  */
@@ -3314,8 +3324,7 @@  ia64_expand_prologue (void)
 	  /* ??? Denote pr spill/fill by a DImode move that modifies all
 	     64 hard registers.  */
 	  RTX_FRAME_RELATED_P (insn) = 1;
-	  add_reg_note (insn, REG_FRAME_RELATED_EXPR,
-			gen_rtx_SET (VOIDmode, alt_reg, reg));
+	  add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
 
 	  /* Even if we're not going to generate an epilogue, we still
 	     need to save the register so that EH works.  */
@@ -3361,6 +3370,7 @@  ia64_expand_prologue (void)
 	  reg_emitted (reg_save_ar_lc);
 	  insn = emit_move_insn (alt_reg, reg);
 	  RTX_FRAME_RELATED_P (insn) = 1;
+	  add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
 
 	  /* Even if we're not going to generate an epilogue, we still
 	     need to save the register so that EH works.  */
@@ -3387,6 +3397,7 @@  ia64_expand_prologue (void)
           reg_emitted (reg_save_b0);
 	  insn = emit_move_insn (alt_reg, reg);
 	  RTX_FRAME_RELATED_P (insn) = 1;
+	  add_reg_note (insn, REG_CFA_REGISTER, NULL_RTX);
 
 	  /* Even if we're not going to generate an epilogue, we still
 	     need to save the register so that EH works.  */
@@ -3677,6 +3688,7 @@  ia64_expand_epilogue (int sibcall_p)
     {
       insn = emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
+      add_reg_note (insn, REG_CFA_ADJUST_CFA, NULL);
     }
   else if (current_frame_info.total_size)
     {
@@ -3696,13 +3708,12 @@  ia64_expand_epilogue (int sibcall_p)
 				    offset));
 
       RTX_FRAME_RELATED_P (insn) = 1;
-      if (GET_CODE (offset) != CONST_INT)
-	add_reg_note (insn, REG_FRAME_RELATED_EXPR,
-		      gen_rtx_SET (VOIDmode,
-				   stack_pointer_rtx,
-				   gen_rtx_PLUS (DImode,
-						 stack_pointer_rtx,
-						 frame_size_rtx)));
+      add_reg_note (insn, REG_CFA_ADJUST_CFA,
+		    gen_rtx_SET (VOIDmode,
+				 stack_pointer_rtx,
+				 gen_rtx_PLUS (DImode,
+					       stack_pointer_rtx,
+					       frame_size_rtx)));
     }
 
   if (cfun->machine->ia64_eh_epilogue_bsp)
@@ -3713,11 +3724,12 @@  ia64_expand_epilogue (int sibcall_p)
   else
     {
       int fp = GR_REG (2);
-      /* We need a throw away register here, r0 and r1 are reserved, so r2 is the
-	 first available call clobbered register.  If there was a frame_pointer
-	 register, we may have swapped the names of r2 and HARD_FRAME_POINTER_REGNUM,
-	 so we have to make sure we're using the string "r2" when emitting
-	 the register name for the assembler.  */
+      /* We need a throw away register here, r0 and r1 are reserved,
+	 so r2 is the first available call clobbered register.  If
+	 there was a frame_pointer register, we may have swapped the
+	 names of r2 and HARD_FRAME_POINTER_REGNUM, so we have to make
+	 sure we're using the string "r2" when emitting the register
+	 name for the assembler.  */
       if (current_frame_info.r[reg_fp] 
           && current_frame_info.r[reg_fp] == GR_REG (2))
 	fp = HARD_FRAME_POINTER_REGNUM;
@@ -9590,6 +9602,17 @@  ia64_dwarf2out_def_steady_cfa (rtx insn, bool frame)
      + ARG_POINTER_CFA_OFFSET (current_function_decl));
 }
 
+/* All we need to do here is avoid a crash in the generic dwarf2
+   processing.  The real CFA definition is set up above.  */
+
+static void
+ia64_dwarf_handle_frame_unspec (const char * ARG_UNUSED (label),
+				rtx ARG_UNUSED (pattern),
+				int index)
+{
+  gcc_assert (index == UNSPECV_ALLOC);
+}
+
 /* The generic dwarf2 frame debug info generator does not define a
    separate region for the very end of the epilogue, so refrain from
    doing so in the IA64-specific code as well.  */
@@ -9619,53 +9642,19 @@  process_epilogue (FILE *asm_out_file, rtx insn, bool unwind, bool frame)
 		       STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
 }
 
-/* This function processes a SET pattern looking for specific patterns
-   which result in emitting an assembly directive required for unwinding.  */
+/* This function processes a SET pattern for REG_CFA_ADJUST_CFA.  */
 
-static int
-process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame)
+static void
+process_cfa_adjust_cfa (FILE *asm_out_file, rtx pat, rtx insn,
+			bool unwind, bool frame)
 {
-  rtx src = SET_SRC (pat);
   rtx dest = SET_DEST (pat);
-  int src_regno, dest_regno;
-
-  /* Look for the ALLOC insn.  */
-  if (GET_CODE (src) == UNSPEC_VOLATILE
-      && XINT (src, 1) == UNSPECV_ALLOC
-      && GET_CODE (dest) == REG)
-    {
-      dest_regno = REGNO (dest);
-
-      /* If this is the final destination for ar.pfs, then this must
-	 be the alloc in the prologue.  */
-      if (dest_regno == current_frame_info.r[reg_save_ar_pfs])
-	{
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.save ar.pfs, r%d\n",
-		     ia64_dbx_register_number (dest_regno));
-	}
-      else
-	{
-	  /* This must be an alloc before a sibcall.  We must drop the
-	     old frame info.  The easiest way to drop the old frame
-	     info is to ensure we had a ".restore sp" directive
-	     followed by a new prologue.  If the procedure doesn't
-	     have a memory-stack frame, we'll issue a dummy ".restore
-	     sp" now.  */
-	  if (current_frame_info.total_size == 0 && !frame_pointer_needed)
-	    /* if haven't done process_epilogue() yet, do it now */
-	    process_epilogue (asm_out_file, insn, unwind, frame);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.prologue\n");
-	}
-      return 1;
-    }
+  rtx src = SET_SRC (pat);
 
-  /* Look for SP = ....  */
-  if (GET_CODE (dest) == REG && REGNO (dest) == STACK_POINTER_REGNUM)
+  if (dest == stack_pointer_rtx)
     {
       if (GET_CODE (src) == PLUS)
-        {
+	{
 	  rtx op0 = XEXP (src, 0);
 	  rtx op1 = XEXP (src, 1);
 	  
@@ -9675,7 +9664,8 @@  process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame)
 	    {
 	      gcc_assert (!frame_pointer_needed);
 	      if (unwind)
-		fprintf (asm_out_file, "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n",
+		fprintf (asm_out_file,
+			 "\t.fframe "HOST_WIDE_INT_PRINT_DEC"\n",
 			 -INTVAL (op1));
 	      ia64_dwarf2out_def_steady_cfa (insn, frame);
 	    }
@@ -9684,240 +9674,298 @@  process_set (FILE *asm_out_file, rtx pat, rtx insn, bool unwind, bool frame)
 	}
       else
 	{
-	  gcc_assert (GET_CODE (src) == REG
-		      && REGNO (src) == HARD_FRAME_POINTER_REGNUM);
+	  gcc_assert (src == hard_frame_pointer_rtx);
 	  process_epilogue (asm_out_file, insn, unwind, frame);
 	}
+    }
+  else if (dest == hard_frame_pointer_rtx)
+    {
+      gcc_assert (src == stack_pointer_rtx);
+      gcc_assert (frame_pointer_needed);
 
-      return 1;
+      if (unwind)
+	fprintf (asm_out_file, "\t.vframe r%d\n",
+		 ia64_dbx_register_number (REGNO (dest)));
+      ia64_dwarf2out_def_steady_cfa (insn, frame);
     }
+  else
+    gcc_unreachable ();
+}
 
-  /* Register move we need to look at.  */
-  if (GET_CODE (dest) == REG && GET_CODE (src) == REG)
-    {
-      src_regno = REGNO (src);
-      dest_regno = REGNO (dest);
+/* This function processes a SET pattern for REG_CFA_REGISTER.  */
 
-      switch (src_regno)
-	{
-	case BR_REG (0):
-	  /* Saving return address pointer.  */
-	  gcc_assert (dest_regno == current_frame_info.r[reg_save_b0]);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.save rp, r%d\n",
-		     ia64_dbx_register_number (dest_regno));
-	  return 1;
+static void
+process_cfa_register (FILE *asm_out_file, rtx pat, bool unwind)
+{
+  rtx dest = SET_DEST (pat);
+  rtx src = SET_SRC (pat);
 
-	case PR_REG (0):
-	  gcc_assert (dest_regno == current_frame_info.r[reg_save_pr]);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.save pr, r%d\n",
-		     ia64_dbx_register_number (dest_regno));
-	  return 1;
+  int dest_regno = REGNO (dest);
+  int src_regno = REGNO (src);
 
-	case AR_UNAT_REGNUM:
-	  gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_unat]);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.save ar.unat, r%d\n",
-		     ia64_dbx_register_number (dest_regno));
-	  return 1;
+  switch (src_regno)
+    {
+    case BR_REG (0):
+      /* Saving return address pointer.  */
+      gcc_assert (dest_regno == current_frame_info.r[reg_save_b0]);
+      if (unwind)
+	fprintf (asm_out_file, "\t.save rp, r%d\n",
+		 ia64_dbx_register_number (dest_regno));
+      break;
 
-	case AR_LC_REGNUM:
-	  gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_lc]);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.save ar.lc, r%d\n",
-		     ia64_dbx_register_number (dest_regno));
-	  return 1;
+    case PR_REG (0):
+      gcc_assert (dest_regno == current_frame_info.r[reg_save_pr]);
+      if (unwind)
+	fprintf (asm_out_file, "\t.save pr, r%d\n",
+		 ia64_dbx_register_number (dest_regno));
+      break;
 
-	case STACK_POINTER_REGNUM:
-	  gcc_assert (dest_regno == HARD_FRAME_POINTER_REGNUM
-		      && frame_pointer_needed);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.vframe r%d\n",
-		     ia64_dbx_register_number (dest_regno));
-	  ia64_dwarf2out_def_steady_cfa (insn, frame);
-	  return 1;
+    case AR_UNAT_REGNUM:
+      gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_unat]);
+      if (unwind)
+	fprintf (asm_out_file, "\t.save ar.unat, r%d\n",
+		 ia64_dbx_register_number (dest_regno));
+      break;
 
-	default:
-	  /* Everything else should indicate being stored to memory.  */
-	  gcc_unreachable ();
-	}
+    case AR_LC_REGNUM:
+      gcc_assert (dest_regno == current_frame_info.r[reg_save_ar_lc]);
+      if (unwind)
+	fprintf (asm_out_file, "\t.save ar.lc, r%d\n",
+		 ia64_dbx_register_number (dest_regno));
+      break;
+
+    default:
+      /* Everything else should indicate being stored to memory.  */
+      gcc_unreachable ();
     }
+}
 
-  /* Memory store we need to look at.  */
-  if (GET_CODE (dest) == MEM && GET_CODE (src) == REG)
-    {
-      long off;
-      rtx base;
-      const char *saveop;
+/* This function processes a SET pattern for REG_CFA_OFFSET.  */
 
-      if (GET_CODE (XEXP (dest, 0)) == REG)
-	{
-	  base = XEXP (dest, 0);
-	  off = 0;
-	}
-      else
-	{
-	  gcc_assert (GET_CODE (XEXP (dest, 0)) == PLUS
-		      && GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT);
-	  base = XEXP (XEXP (dest, 0), 0);
-	  off = INTVAL (XEXP (XEXP (dest, 0), 1));
-	}
+static void
+process_cfa_offset (FILE *asm_out_file, rtx pat, bool unwind)
+{
+  rtx dest = SET_DEST (pat);
+  rtx src = SET_SRC (pat);
+  int src_regno = REGNO (src);
+  const char *saveop;
+  HOST_WIDE_INT off;
+  rtx base;
 
-      if (base == hard_frame_pointer_rtx)
-	{
-	  saveop = ".savepsp";
-	  off = - off;
-	}
-      else
-	{
-	  gcc_assert (base == stack_pointer_rtx);
-	  saveop = ".savesp";
-	}
+  gcc_assert (MEM_P (dest));
+  if (GET_CODE (XEXP (dest, 0)) == REG)
+    {
+      base = XEXP (dest, 0);
+      off = 0;
+    }
+  else
+    {
+      gcc_assert (GET_CODE (XEXP (dest, 0)) == PLUS
+		  && GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT);
+      base = XEXP (XEXP (dest, 0), 0);
+      off = INTVAL (XEXP (XEXP (dest, 0), 1));
+    }
 
-      src_regno = REGNO (src);
-      switch (src_regno)
-	{
-	case BR_REG (0):
-	  gcc_assert (!current_frame_info.r[reg_save_b0]);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off);
-	  return 1;
+  if (base == hard_frame_pointer_rtx)
+    {
+      saveop = ".savepsp";
+      off = - off;
+    }
+  else
+    {
+      gcc_assert (base == stack_pointer_rtx);
+      saveop = ".savesp";
+    }
 
-	case PR_REG (0):
-	  gcc_assert (!current_frame_info.r[reg_save_pr]);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off);
-	  return 1;
+  src_regno = REGNO (src);
+  switch (src_regno)
+    {
+    case BR_REG (0):
+      gcc_assert (!current_frame_info.r[reg_save_b0]);
+      if (unwind)
+	fprintf (asm_out_file, "\t%s rp, %ld\n", saveop, off);
+      break;
 
-	case AR_LC_REGNUM:
-	  gcc_assert (!current_frame_info.r[reg_save_ar_lc]);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off);
-	  return 1;
+    case PR_REG (0):
+      gcc_assert (!current_frame_info.r[reg_save_pr]);
+      if (unwind)
+	fprintf (asm_out_file, "\t%s pr, %ld\n", saveop, off);
+      break;
 
-	case AR_PFS_REGNUM:
-	  gcc_assert (!current_frame_info.r[reg_save_ar_pfs]);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off);
-	  return 1;
+    case AR_LC_REGNUM:
+      gcc_assert (!current_frame_info.r[reg_save_ar_lc]);
+      if (unwind)
+	fprintf (asm_out_file, "\t%s ar.lc, %ld\n", saveop, off);
+      break;
 
-	case AR_UNAT_REGNUM:
-	  gcc_assert (!current_frame_info.r[reg_save_ar_unat]);
-	  if (unwind)
-	    fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off);
-	  return 1;
+    case AR_PFS_REGNUM:
+      gcc_assert (!current_frame_info.r[reg_save_ar_pfs]);
+      if (unwind)
+	fprintf (asm_out_file, "\t%s ar.pfs, %ld\n", saveop, off);
+      break;
 
-	case GR_REG (4):
-	case GR_REG (5):
-	case GR_REG (6):
-	case GR_REG (7):
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.save.g 0x%x\n",
-		     1 << (src_regno - GR_REG (4)));
-	  return 1;
+    case AR_UNAT_REGNUM:
+      gcc_assert (!current_frame_info.r[reg_save_ar_unat]);
+      if (unwind)
+	fprintf (asm_out_file, "\t%s ar.unat, %ld\n", saveop, off);
+      break;
 
-	case BR_REG (1):
-	case BR_REG (2):
-	case BR_REG (3):
-	case BR_REG (4):
-	case BR_REG (5):
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.save.b 0x%x\n",
-		     1 << (src_regno - BR_REG (1)));
-	  return 1;
+    case GR_REG (4):
+    case GR_REG (5):
+    case GR_REG (6):
+    case GR_REG (7):
+      if (unwind)
+	fprintf (asm_out_file, "\t.save.g 0x%x\n",
+		 1 << (src_regno - GR_REG (4)));
+      break;
 
-	case FR_REG (2):
-	case FR_REG (3):
-	case FR_REG (4):
-	case FR_REG (5):
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.save.f 0x%x\n",
-		     1 << (src_regno - FR_REG (2)));
-	  return 1;
+    case BR_REG (1):
+    case BR_REG (2):
+    case BR_REG (3):
+    case BR_REG (4):
+    case BR_REG (5):
+      if (unwind)
+	fprintf (asm_out_file, "\t.save.b 0x%x\n",
+		 1 << (src_regno - BR_REG (1)));
+      break;
 
-	case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19):
-	case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23):
-	case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27):
-	case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31):
-	  if (unwind)
-	    fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n",
-		     1 << (src_regno - FR_REG (12)));
-	  return 1;
+    case FR_REG (2):
+    case FR_REG (3):
+    case FR_REG (4):
+    case FR_REG (5):
+      if (unwind)
+	fprintf (asm_out_file, "\t.save.f 0x%x\n",
+		 1 << (src_regno - FR_REG (2)));
+      break;
 
-	default:
-	  return 0;
-	}
-    }
+    case FR_REG (16): case FR_REG (17): case FR_REG (18): case FR_REG (19):
+    case FR_REG (20): case FR_REG (21): case FR_REG (22): case FR_REG (23):
+    case FR_REG (24): case FR_REG (25): case FR_REG (26): case FR_REG (27):
+    case FR_REG (28): case FR_REG (29): case FR_REG (30): case FR_REG (31):
+      if (unwind)
+	fprintf (asm_out_file, "\t.save.gf 0x0, 0x%x\n",
+		 1 << (src_regno - FR_REG (12)));
+      break;
 
-  return 0;
+    default:
+      /* ??? For some reason we mark other general registers, even those
+	 we can't represent in the unwind info.  Ignore them.  */
+      break;
+    }
 }
 
-
 /* This function looks at a single insn and emits any directives
    required to unwind this insn.  */
+
 static void
 ia64_asm_unwind_emit (FILE *asm_out_file, rtx insn)
 {
   bool unwind = (flag_unwind_tables
 		 || (flag_exceptions && !USING_SJLJ_EXCEPTIONS));
   bool frame = dwarf2out_do_frame ();
+  rtx note, pat;
+  bool handled_one;
+
+  if (!unwind && !frame)
+    return;
 
-  if (unwind || frame)
+  if (NOTE_INSN_BASIC_BLOCK_P (insn))
     {
-      rtx pat;
+      last_block = NOTE_BASIC_BLOCK (insn)->next_bb == EXIT_BLOCK_PTR;
 
-      if (NOTE_INSN_BASIC_BLOCK_P (insn))
+      /* Restore unwind state from immediately before the epilogue.  */
+      if (need_copy_state)
 	{
-	  last_block = NOTE_BASIC_BLOCK (insn)->next_bb == EXIT_BLOCK_PTR;
-
-	  /* Restore unwind state from immediately before the epilogue.  */
-	  if (need_copy_state)
+	  if (unwind)
 	    {
-	      if (unwind)
-		{
-		  fprintf (asm_out_file, "\t.body\n");
-		  fprintf (asm_out_file, "\t.copy_state %d\n",
-			   cfun->machine->state_num);
-		}
-	      if (IA64_CHANGE_CFA_IN_EPILOGUE)
-		ia64_dwarf2out_def_steady_cfa (insn, frame);
-	      need_copy_state = false;
+	      fprintf (asm_out_file, "\t.body\n");
+	      fprintf (asm_out_file, "\t.copy_state %d\n",
+		       cfun->machine->state_num);
 	    }
+	  if (IA64_CHANGE_CFA_IN_EPILOGUE)
+	    ia64_dwarf2out_def_steady_cfa (insn, frame);
+	  need_copy_state = false;
 	}
+    }
 
-      if (GET_CODE (insn) == NOTE || ! RTX_FRAME_RELATED_P (insn))
-	return;
+  if (GET_CODE (insn) == NOTE || ! RTX_FRAME_RELATED_P (insn))
+    return;
+
+  /* Look for the ALLOC insn.  */
+  if (INSN_CODE (insn) == CODE_FOR_alloc)
+    {
+      rtx dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+      int dest_regno = REGNO (dest);
 
-      pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
-      if (pat)
-	pat = XEXP (pat, 0);
+      /* If this is the final destination for ar.pfs, then this must
+	 be the alloc in the prologue.  */
+      if (dest_regno == current_frame_info.r[reg_save_ar_pfs])
+	{
+	  if (unwind)
+	    fprintf (asm_out_file, "\t.save ar.pfs, r%d\n",
+		     ia64_dbx_register_number (dest_regno));
+	}
       else
-	pat = PATTERN (insn);
+	{
+	  /* This must be an alloc before a sibcall.  We must drop the
+	     old frame info.  The easiest way to drop the old frame
+	     info is to ensure we had a ".restore sp" directive
+	     followed by a new prologue.  If the procedure doesn't
+	     have a memory-stack frame, we'll issue a dummy ".restore
+	     sp" now.  */
+	  if (current_frame_info.total_size == 0 && !frame_pointer_needed)
+	    /* if haven't done process_epilogue() yet, do it now */
+	    process_epilogue (asm_out_file, insn, unwind, frame);
+	  if (unwind)
+	    fprintf (asm_out_file, "\t.prologue\n");
+	}
+      return;
+    }
 
-      switch (GET_CODE (pat))
-        {
-	case SET:
-	  process_set (asm_out_file, pat, insn, unwind, frame);
-	  break;
+  handled_one = false;
+  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+    switch (REG_NOTE_KIND (note))
+      {
+      case REG_CFA_ADJUST_CFA:
+	pat = XEXP (note, 0);
+	if (pat == NULL)
+	  pat = PATTERN (insn);
+	process_cfa_adjust_cfa (asm_out_file, pat, insn, unwind, frame);
+	handled_one = true;
+	break;
 
-	case PARALLEL:
-	  {
-	    int par_index;
-	    int limit = XVECLEN (pat, 0);
-	    for (par_index = 0; par_index < limit; par_index++)
-	      {
-		rtx x = XVECEXP (pat, 0, par_index);
-		if (GET_CODE (x) == SET)
-		  process_set (asm_out_file, x, insn, unwind, frame);
-	      }
-	    break;
-	  }
+      case REG_CFA_OFFSET:
+	pat = XEXP (note, 0);
+	if (pat == NULL)
+	  pat = PATTERN (insn);
+	process_cfa_offset (asm_out_file, pat, unwind);
+	handled_one = true;
+	break;
 
-	default:
-	  gcc_unreachable ();
-	}
-    }
+      case REG_CFA_REGISTER:
+	pat = XEXP (note, 0);
+	if (pat == NULL)
+	  pat = PATTERN (insn);
+	process_cfa_register (asm_out_file, pat, unwind);
+	handled_one = true;
+	break;
+
+      case REG_FRAME_RELATED_EXPR:
+      case REG_CFA_DEF_CFA:
+      case REG_CFA_EXPRESSION:
+      case REG_CFA_RESTORE:
+      case REG_CFA_SET_VDRAP:
+	/* Not used in the ia64 port.  */
+	gcc_unreachable ();
+
+      default:
+	/* Not a frame-related note.  */
+	break;
+      }
+
+  /* All REG_FRAME_RELATED_P insns, besides ALLOC, are marked with the
+     explicit action to take.  No guessing required.  */
+  gcc_assert (handled_one);
 }
 
 /* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY.  */