ICE in verify_local_live_at_start, current CVS

Richard Henderson rth@cygnus.com
Fri Feb 4 13:34:00 GMT 2000


On Wed, Feb 02, 2000 at 10:07:39AM -0800, Zack Weinberg wrote:
> $ /work/build/gcc/gcc/cc1 rdbz.i -g -O2 -o rdbz.s
>  fetch
> rdbz.i: In function `fetch':
> rdbz.i:113: Internal compiler error in `verify_local_live_at_start',
> 	    at flow.c:2555
> Please submit a full bug report.

Oh geez.  Push the bubble down one place and it comes back another.

Ok, this time for real.  There is no longer two bits of code to 
figure out what the live return registers are.  There is only one
bit of code with a callback.

Bootstrapped on Alpha, MIPS, and x86.  Hopefully there's not too
many other combinations that could go wrong.


r~


        * function.c (diddle_return_value): Rework to use a callback function.
        Use current_function_return_rtx if it's been set up.
        (do_clobber_return_reg, clobber_return_register): New.
        (do_use_return_reg, use_return_register): New.
        (expand_function_end): Use them.
        * stmt.c (expand_null_return): Likewise.
        * function.h: Declare them.
        * flow.c (mark_regs_live_at_end): Use diddle_return_value.
        (mark_reg): Change arguments as appropriate for callback.
        * integrate.c (expand_inline_function): Revert 19 Jan change.

Index: flow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flow.c,v
retrieving revision 1.215
diff -c -p -d -r1.215 flow.c
*** flow.c	2000/02/02 13:56:01	1.215
--- flow.c	2000/02/04 21:24:12
*************** static int set_noop_p			PARAMS ((rtx));
*** 320,326 ****
  static int noop_move_p			PARAMS ((rtx));
  static void notice_stack_pointer_modification PARAMS ((rtx, rtx, void *));
  static void record_volatile_insns	PARAMS ((rtx));
! static void mark_reg			PARAMS ((regset, rtx));
  static void mark_regs_live_at_end	PARAMS ((regset));
  static void life_analysis_1		PARAMS ((rtx, int, int));
  static void calculate_global_regs_live	PARAMS ((sbitmap, sbitmap, int));
--- 320,326 ----
  static int noop_move_p			PARAMS ((rtx));
  static void notice_stack_pointer_modification PARAMS ((rtx, rtx, void *));
  static void record_volatile_insns	PARAMS ((rtx));
! static void mark_reg			PARAMS ((rtx, void *));
  static void mark_regs_live_at_end	PARAMS ((regset));
  static void life_analysis_1		PARAMS ((rtx, int, int));
  static void calculate_global_regs_live	PARAMS ((sbitmap, sbitmap, int));
*************** record_volatile_insns (f)
*** 2788,2799 ****
  /* Mark a register in SET.  Hard registers in large modes get all
     of their component registers set as well.  */
  static void
! mark_reg (set, reg)
!      regset set;
       rtx reg;
  {
    int regno = REGNO (reg);
  
    SET_REGNO_REG_SET (set, regno);
    if (regno < FIRST_PSEUDO_REGISTER)
      {
--- 2788,2803 ----
  /* Mark a register in SET.  Hard registers in large modes get all
     of their component registers set as well.  */
  static void
! mark_reg (reg, xset)
       rtx reg;
+      void *xset;
  {
+   regset set = (regset) xset;
    int regno = REGNO (reg);
  
+   if (GET_MODE (reg) == BLKmode)
+     abort ();
+ 
    SET_REGNO_REG_SET (set, regno);
    if (regno < FIRST_PSEUDO_REGISTER)
      {
*************** mark_regs_live_at_end (set)
*** 2867,2910 ****
      }
  
    /* Mark function return value.  */
! 
!   result = DECL_RESULT (current_function_decl);
!   type = TREE_TYPE (result);
!   if (type != void_type_node)
!     {
!       rtx outgoing;
! 
!       /* ??? Share this code with expand_function_end.  */
! #ifdef FUNCTION_OUTGOING_VALUE
!       outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
! #else
!       outgoing = FUNCTION_VALUE (type, current_function_decl);
! #endif
!       /* If this is a BLKmode structure being returned in registers,
! 	 then use the mode computed in expand_return.  */
!       if (GET_MODE (outgoing) == BLKmode)
! 	PUT_MODE (outgoing, GET_MODE (DECL_RTL (result)));
! 
!       if (GET_CODE (outgoing) == REG)
! 	mark_reg (set, outgoing);
!       else if (GET_CODE (outgoing) == PARALLEL)
! 	{
! 	  int len = XVECLEN (outgoing, 0);
! 
! 	  /* Check for a NULL entry, used to indicate that the parameter
! 	     goes on the stack and in registers.  */
! 	  i = (XEXP (XVECEXP (outgoing, 0, 0), 0) ? 0 : 1);
! 
! 	  for ( ; i < len; ++i)
! 	    {
! 	      rtx r = XVECEXP (outgoing, 0, i);
! 	      if (GET_CODE (r) == REG)
! 		mark_reg (set, r);
! 	    }
! 	}
!       else
! 	abort ();
!     }
  }
  
  /* Determine which registers are live at the start of each
--- 2871,2877 ----
      }
  
    /* Mark function return value.  */
!   diddle_return_value (mark_reg, set);
  }
  
  /* Determine which registers are live at the start of each
Index: function.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.c,v
retrieving revision 1.153
diff -c -p -d -r1.153 function.c
*** function.c	2000/01/28 22:22:49	1.153
--- function.c	2000/02/04 21:24:12
*************** static void mark_temp_slot PARAMS ((stru
*** 286,292 ****
  static void mark_function_status PARAMS ((struct function *));
  static void mark_function_chain PARAMS ((void *));
  static void prepare_function_start PARAMS ((void));
! 
  
  /* Pointer to chain of `struct function' for containing functions.  */
  struct function *outer_function_chain;
--- 286,293 ----
  static void mark_function_status PARAMS ((struct function *));
  static void mark_function_chain PARAMS ((void *));
  static void prepare_function_start PARAMS ((void));
! static void do_clobber_return_reg PARAMS ((rtx, void *));
! static void do_use_return_reg PARAMS ((rtx, void *));
  
  /* Pointer to chain of `struct function' for containing functions.  */
  struct function *outer_function_chain;
*************** expand_dummy_function_end ()
*** 6120,6163 ****
    cfun = 0;
  }
  
! /* Emit CODE for each register of the return value.  Useful values for
!    code are USE and CLOBBER.  */
  
  void
! diddle_return_value (code)
!      enum rtx_code code;
  {
!   tree decl_result = DECL_RESULT (current_function_decl);
!   rtx return_reg = DECL_RTL (decl_result);
  
!   if (return_reg)
      {
!       if (GET_CODE (return_reg) == REG
! 	  && REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
! 	{
! 	  /* Use hard_function_value to avoid creating a reference to a BLKmode 
! 	     register in the USE/CLOBBER insn.  */
! 	  return_reg = hard_function_value (TREE_TYPE (decl_result),
! 					    current_function_decl, 1);
! 	  REG_FUNCTION_VALUE_P (return_reg) = 1;
! 	  emit_insn (gen_rtx_fmt_e (code, VOIDmode, return_reg));
! 	}
!       else if (GET_CODE (return_reg) == PARALLEL)
! 	{
! 	  int i;
  
! 	  for (i = 0; i < XVECLEN (return_reg, 0); i++)
! 	    {
! 	      rtx x = XEXP (XVECEXP (return_reg, 0, i), 0);
  
! 	      if (GET_CODE (x) == REG
! 		  && REGNO (x) < FIRST_PSEUDO_REGISTER)
! 		emit_insn (gen_rtx_fmt_e (code, VOIDmode, x));
! 	    }
  	}
      }
  }
  
  /* Generate RTL for the end of the current function.
     FILENAME and LINE are the current position in the source file. 
  
--- 6121,6199 ----
    cfun = 0;
  }
  
! /* Call DOIT for each hard register used as a return value from
!    the current function.  */
  
  void
! diddle_return_value (doit, arg)
!      void (*doit) PARAMS ((rtx, void *));
!      void *arg;
  {
!   rtx outgoing = current_function_return_rtx;
  
!   if (! outgoing)
!     return;
! 
!   if (GET_CODE (outgoing) == REG
!       && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
      {
!       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
! #ifdef FUNCTION_OUTGOING_VALUE
!       outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
! #else
!       outgoing = FUNCTION_VALUE (type, current_function_decl);
! #endif
!       /* If this is a BLKmode structure being returned in registers, then use
! 	 the mode computed in expand_return.  */
!       if (GET_MODE (outgoing) == BLKmode)
! 	PUT_MODE (outgoing,
! 		  GET_MODE (DECL_RTL (DECL_RESULT (current_function_decl))));
!     }
  
!   if (GET_CODE (outgoing) == REG)
!     (*doit) (outgoing, arg);
!   else if (GET_CODE (outgoing) == PARALLEL)
!     {
!       int i;
  
!       for (i = 0; i < XVECLEN (outgoing, 0); i++)
! 	{
! 	  rtx x = XEXP (XVECEXP (outgoing, 0, i), 0);
! 
! 	  if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
! 	    (*doit) (x, arg);
  	}
      }
  }
  
+ static void
+ do_clobber_return_reg (reg, arg)
+      rtx reg;
+      void *arg ATTRIBUTE_UNUSED;
+ {
+   emit_insn (gen_rtx_CLOBBER (VOIDmode, reg));
+ }
+ 
+ void
+ clobber_return_register ()
+ {
+   diddle_return_value (do_clobber_return_reg, NULL);
+ }
+ 
+ static void
+ do_use_return_reg (reg, arg)
+      rtx reg;
+      void *arg ATTRIBUTE_UNUSED;
+ {
+   emit_insn (gen_rtx_USE (VOIDmode, reg));
+ }
+ 
+ void
+ use_return_register ()
+ {
+   diddle_return_value (do_use_return_reg, NULL);
+ }
+ 
  /* Generate RTL for the end of the current function.
     FILENAME and LINE are the current position in the source file. 
  
*************** expand_function_end (filename, line, end
*** 6324,6330 ****
  	 can only happen with functions that drop through; if there had
  	 been a return statement, there would have either been a return
  	 rtx, or a jump to the return label.  */
!       diddle_return_value (CLOBBER);
  
        emit_label (return_label);
      }
--- 6360,6366 ----
  	 can only happen with functions that drop through; if there had
  	 been a return statement, there would have either been a return
  	 rtx, or a jump to the return label.  */
!       clobber_return_register ();
  
        emit_label (return_label);
      }
*************** expand_function_end (filename, line, end
*** 6443,6448 ****
--- 6479,6490 ----
  
        emit_move_insn (outgoing, value_address);
      }
+ 
+   /* ??? This should no longer be necessary since stupid is no longer with
+      us, but there are some parts of the compiler (eg reload_combine, and
+      sh mach_dep_reorg) that still try and compute their own lifetime info
+      instead of using the general framework.  */
+   use_return_register ();
  
    /* If this is an implementation of __throw, do what's necessary to 
       communicate between __builtin_eh_return and the epilogue.  */
Index: function.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.h,v
retrieving revision 1.42
diff -c -p -d -r1.42 function.h
*** function.h	2000/01/14 17:14:43	1.42
--- function.h	2000/02/04 21:24:12
*************** extern void free_expr_status		PARAMS ((s
*** 585,591 ****
  extern rtx get_first_block_beg		PARAMS ((void));
  
  #ifdef RTX_CODE
! extern void diddle_return_value		PARAMS ((enum rtx_code));
  #endif
  
  extern void init_virtual_regs		PARAMS ((struct emit_status *));
--- 585,593 ----
  extern rtx get_first_block_beg		PARAMS ((void));
  
  #ifdef RTX_CODE
! extern void diddle_return_value		PARAMS ((void (*)(rtx, void*), void*));
! extern void clobber_return_register	PARAMS ((void));
! extern void use_return_register		PARAMS ((void));
  #endif
  
  extern void init_virtual_regs		PARAMS ((struct emit_status *));
Index: integrate.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/integrate.c,v
retrieving revision 1.88
diff -c -p -d -r1.88 integrate.c
*** integrate.c	2000/01/19 09:42:10	1.88
--- integrate.c	2000/02/04 21:24:12
*************** expand_inline_function (fndecl, parms, t
*** 1099,1104 ****
--- 1099,1111 ----
  	  pattern = PATTERN (insn);
  	  set = single_set (insn);
  	  copy = 0;
+ 	  if (GET_CODE (pattern) == USE
+ 	      && GET_CODE (XEXP (pattern, 0)) == REG
+ 	      && REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
+ 	    /* The (USE (REG n)) at return from the function should
+ 	       be ignored since we are changing (REG n) into
+ 	       inline_target.  */
+ 	    break;
  
  	  /* If the inline fn needs eh context, make sure that
  	     the current fn has one. */
Index: stmt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/stmt.c,v
retrieving revision 1.118
diff -c -p -d -r1.118 stmt.c
*** stmt.c	2000/01/19 09:42:11	1.118
--- stmt.c	2000/02/04 21:24:13
*************** expand_null_return ()
*** 2676,2686 ****
    /* If this function was declared to return a value, but we 
       didn't, clobber the return registers so that they are not
       propogated live to the rest of the function.  */
! 
!   diddle_return_value (CLOBBER);
  
    /* Does any pending block have cleanups?  */
- 
    while (block && block->data.block.cleanups == 0)
      block = block->next;
  
--- 2676,2684 ----
    /* If this function was declared to return a value, but we 
       didn't, clobber the return registers so that they are not
       propogated live to the rest of the function.  */
!   clobber_return_register ();
  
    /* Does any pending block have cleanups?  */
    while (block && block->data.block.cleanups == 0)
      block = block->next;
  


More information about the Gcc-bugs mailing list