This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

IA-64 unwind patch for -freorder-blocks miscompile


The linux kernel was failing because -freorder-blocks could put the function
epilogue in the middle of a function.  When that happened, the unwind info was
wrong for all basic blocks after the epilogue.  To fix this, we have to
save/restore the unwind state around the epilogue basic block.  This is not a
problem for the DWARF2 unwinder because we don't emit frame info for epilogues.

In order to fix this problem, the IA-64 unwind code needs to know where
the basic block boundaries are.  The simplest way to fix that was to pass
NOTE_INSN_BASIC_BLOCK notes to the unwind output routines, and that required
the final.c change.  The rest of the patch is internal to the IA-64 port.

This was tested with an ia64-linux bootstrap and testsuite run.  I've added
this to the trunk and branch.

2001-02-23  Jim Wilson  <wilson@redhat.com>

	* final.c (final_scan_insn, case NOTE_INSN_BASIC_BLOCK): Call
	IA64_UNWIND_EMIT.
	* config/ia64/ia64.c (block_num, need_copy_state): New static vars.
	(process_epilogue): New static function.
	(process_set): Call process_epilogue instead of emitting .restore
	directly.
	(process_for_unwind_directive): Handle NOTE_INSN_BASIC_BLOCK.

Index: final.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/final.c,v
retrieving revision 1.159
diff -p -r1.159 final.c
*** final.c	2001/02/18 20:50:41	1.159
--- final.c	2001/02/24 02:53:33
*************** final_scan_insn (insn, file, optimize, p
*** 2123,2128 ****
--- 2123,2131 ----
  	  break;
  
  	case NOTE_INSN_BASIC_BLOCK:
+ #ifdef IA64_UNWIND_INFO
+ 	  IA64_UNWIND_EMIT (asm_out_file, insn);
+ #endif
  	  if (flag_debug_asm)
  	    fprintf (asm_out_file, "\t%s basic block %d\n",
  		     ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index);
Index: config/ia64/ia64.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.c,v
retrieving revision 1.79
diff -p -r1.79 ia64.c
*** ia64.c	2001/03/14 02:29:02	1.79
--- ia64.c	2001/03/14 21:37:36
*************** ia64_encode_section_info (decl)
*** 6310,6317 ****
      }
  }
  
! /* Output assmebly directives for prologue regions.  */
  
  /* This function processes a SET pattern looking for specific patterns
     which result in emitting an assembly directive required for unwinding.  */
  
--- 6310,6342 ----
      }
  }
  
! /* Output assembly directives for prologue regions.  */
  
+ /* The current basic block number.  */
+ 
+ static int block_num;
+ 
+ /* True if we need a copy_state command at the start of the next block.  */
+ 
+ static int need_copy_state;
+ 
+ /* The function emits unwind directives for the start of an epilogue.  */
+ 
+ static void
+ process_epilogue ()
+ {
+   /* If this isn't the last block of the function, then we need to label the
+      current state, and copy it back in at the start of the next block.  */
+ 
+   if (block_num != n_basic_blocks - 1)
+     {
+       fprintf (asm_out_file, "\t.label_state 1\n");
+       need_copy_state = 1;
+     }
+ 
+   fprintf (asm_out_file, "\t.restore sp\n");
+ }
+ 
  /* This function processes a SET pattern looking for specific patterns
     which result in emitting an assembly directive required for unwinding.  */
  
*************** process_set (asm_out_file, pat)
*** 6358,6371 ****
  		  fputc ('\n', asm_out_file);
  		}
  	      else
! 		fprintf (asm_out_file, "\t.restore sp\n");
  	    }
  	  else
  	    abort ();
  	}
        else if (GET_CODE (src) == REG
  	       && REGNO (src) == HARD_FRAME_POINTER_REGNUM)
! 	fprintf (asm_out_file, "\t.restore sp\n");
        else
  	abort ();
  
--- 6383,6396 ----
  		  fputc ('\n', asm_out_file);
  		}
  	      else
! 		process_epilogue ();
  	    }
  	  else
  	    abort ();
  	}
        else if (GET_CODE (src) == REG
  	       && REGNO (src) == HARD_FRAME_POINTER_REGNUM)
! 	process_epilogue ();
        else
  	abort ();
  
*************** process_for_unwind_directive (asm_out_fi
*** 6536,6546 ****
       FILE *asm_out_file;
       rtx insn;
  {
!   if ((flag_unwind_tables
!        || (flag_exceptions && !exceptions_via_longjmp))
!       && RTX_FRAME_RELATED_P (insn))
      {
        rtx pat;
  
        pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
        if (pat)
--- 6561,6587 ----
       FILE *asm_out_file;
       rtx insn;
  {
!   if (flag_unwind_tables
!       || (flag_exceptions && !exceptions_via_longjmp))
      {
        rtx pat;
+ 
+       if (GET_CODE (insn) == NOTE
+ 	  && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK)
+ 	{
+ 	  block_num = NOTE_BASIC_BLOCK (insn)->index;
+ 
+ 	  /* Restore unwind state from immediately before the epilogue.  */
+ 	  if (need_copy_state)
+ 	    {
+ 	      fprintf (asm_out_file, "\t.body\n");
+ 	      fprintf (asm_out_file, "\t.copy_state 1\n");
+ 	      need_copy_state = 0;
+ 	    }
+ 	}
+ 
+       if (! RTX_FRAME_RELATED_P (insn))
+ 	return;
  
        pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
        if (pat)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]