Repost: alloca() optimization when SETJMP_VIA_SAVE_AREA

David S. Miller davem@jenolan.rutgers.edu
Thu Oct 2 11:35:00 GMT 1997


The REG_NOTE's were already added by Jeffrey Law, if there are any
problems with the way the following is performed then please tell me
so I can work on making it more suitable.

Thu Oct  2 14:28:30 1997  David S. Miller  <davem@tanya.rutgers.edu>

	* explow.c (optimize_save_area_alloca): New function for targets
	where SETJMP_VIA_SAVE_AREA is true.
	(allocate_dynamic_stack_space): On SETJMP_VIA_SAVE_AREA targets,
	compute the amount of stack space needed should we find later that
	setjmp is never called by this function, stuff rtl for this inside
	a REG_NOTE of the final SET of stack_pointer_rtx.
	* toplev.c (rest_of_compilation): If SETJMP_VIA_SAVE_AREA and
	current_function_calls_alloca, call optimize_save_area_alloca.

*** explow.c.~1~	Mon Aug 11 11:57:06 1997
--- explow.c	Thu Oct  2 14:28:02 1997
***************
*** 978,983 ****
--- 978,1056 ----
      emit_insn (fcn (stack_pointer_rtx, sa));
  }
  
+ #ifdef SETJMP_VIA_SAVE_AREA
+ /* Optimize RTL generated by allocate_dynamic_stack_space for targets
+    where SETJMP_VIA_SAVE_AREA is true.  The problem is that on these
+    platforms, the dynamic stack space used can corrupt the original
+    frame, thus causing a crash if a longjmp() unwinds to it.  */
+ 
+ void
+ optimize_save_area_alloca (insns)
+      rtx insns;
+ {
+   rtx insn;
+ 
+   for (insn = insns; insn; insn = NEXT_INSN(insn))
+     {
+       rtx note;
+ 
+       if (GET_CODE (insn) != INSN)
+ 	continue;
+ 
+       for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ 	{
+ 	  if (REG_NOTE_KIND (note) != REG_SAVE_AREA)
+ 	    continue;
+ 
+ 	  if (!current_function_calls_setjmp)
+ 	    {
+ 	      rtx pat = PATTERN (insn);
+ 
+ 	      /* If we do not see the note in a pattern matching
+ 		 these precise characteristics, we did something
+ 		 entirely wrong in allocate_dynamic_stack_space().  */
+ 	      if (GET_CODE (pat) != SET
+ 		  || SET_DEST (pat) != stack_pointer_rtx
+ 		  || GET_CODE (SET_SRC (pat)) != MINUS
+ 		  || XEXP (SET_SRC (pat), 0) != stack_pointer_rtx)
+ 		abort();
+ 
+ 	      /* This will now be transformed into a (set REG REG)
+ 		 so we can just blow away all the other notes.  */
+ 	      XEXP (SET_SRC (pat), 1) = XEXP (note, 0);
+ 	      REG_NOTES (insn) = NULL_RTX;
+ 	    }
+ 	  else
+ 	    {
+ 	      /* setjmp() was called, we must remove the REG_SAVE_AREA
+ 		 note so that later passes do not get confused by its
+ 		 presence.  */
+ 	      if (note == REG_NOTES (insn))
+ 		{
+ 		  REG_NOTES (insn) = XEXP (note, 1);
+ 		}
+ 	      else
+ 		{
+ 		  rtx srch;
+ 
+ 		  for (srch = REG_NOTES (insn); srch; srch = XEXP (srch, 1))
+ 		    if (XEXP (srch, 1) == note)
+ 		      break;
+ 
+ 		  if (srch == NULL_RTX)
+ 		    abort();
+ 
+ 		  XEXP (srch, 1) = XEXP (note, 1);
+ 		}
+ 	    }
+ 	  /* Once we've seen the note of interest, we need not look at
+ 	     the rest of them.  */
+ 	  break;
+ 	}
+     }
+ }
+ #endif /* SETJMP_VIA_SAVE_AREA */
+ 
  /* Return an rtx representing the address of an area of memory dynamically
     pushed on the stack.  This region of memory is always aligned to
     a multiple of BIGGEST_ALIGNMENT.
***************
*** 995,1000 ****
--- 1068,1077 ----
       rtx target;
       int known_align;
  {
+ #ifdef SETJMP_VIA_SAVE_AREA
+   rtx setjmpless_size = NULL_RTX;
+ #endif
+ 
    /* If we're asking for zero bytes, it doesn't matter what we point
       to since we can't dereference it.  But return a reasonable
       address anyway.  */
***************
*** 1048,1053 ****
--- 1125,1169 ----
      rtx dynamic_offset
        = expand_binop (Pmode, sub_optab, virtual_stack_dynamic_rtx,
  		      stack_pointer_rtx, NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ 
+     if (!current_function_calls_setjmp)
+       {
+ 	int align = STACK_BOUNDARY / BITS_PER_UNIT;
+ 
+ 	/* See optimize_save_area_alloca() to understand what is being
+ 	   set up here.  */
+ 
+ #if !defined(STACK_BOUNDARY) || !defined(MUST_ALIGN) || (STACK_BOUNDARY != BIGGEST_ALIGNMENT)
+ 	/* If anyone creates a target with these characteristics, let them
+ 	   know that our optimization cannot work correctly in such a case.  */
+ 	abort();
+ #endif
+ 
+ 	if (GET_CODE (size) == CONST_INT)
+ 	  {
+ 	    int new = INTVAL (size) / align * align;
+ 
+ 	    if (INTVAL (size) != new)
+ 	      setjmpless_size = GEN_INT (new);
+ 	    else
+ 	      setjmpless_size = size;
+ 	  }
+ 	else
+ 	  {
+ 	    /* Since we know overflow is not possible, we avoid using
+ 	       CEIL_DIV_EXPR and use TRUNC_DIV_EXPR instead.  */
+ 	    setjmpless_size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size,
+ 					     GEN_INT (align), NULL_RTX, 1);
+ 	    setjmpless_size = expand_mult (Pmode, setjmpless_size,
+ 					   GEN_INT (align), NULL_RTX, 1);
+ 	  }
+ 	/* Our optimization works based upon being able to perform a simple
+ 	   transformation of this RTL into a (set REG REG) so make sure things
+ 	   did in fact end up in a REG.  */
+ 	if (!arith_operand (setjmpless_size, Pmode))
+ 	  setjmpless_size = force_reg (Pmode, setjmpless_size);
+       }
+ 
      size = expand_binop (Pmode, add_optab, size, dynamic_offset,
  			 NULL_RTX, 1, OPTAB_LIB_WIDEN);
    }
***************
*** 1117,1122 ****
--- 1233,1247 ----
      {
        size = convert_modes (Pmode, ptr_mode, size, 1);
        anti_adjust_stack (size);
+ #ifdef SETJMP_VIA_SAVE_AREA
+       if (setjmpless_size != NULL_RTX)
+ 	{
+ 	  rtx note_target = get_last_insn ();
+ 
+ 	  REG_NOTES (note_target) = gen_rtx (EXPR_LIST, REG_SAVE_AREA,
+ 					     setjmpless_size, REG_NOTES (note_target));
+ 	}
+ #endif /* SETJMP_VIA_SAVE_AREA */
      }
  
  #ifdef STACK_GROWS_DOWNWARD
*** toplev.c.~1~	Mon Sep 15 22:07:28 1997
--- toplev.c	Thu Oct  2 14:28:24 1997
***************
*** 3152,3157 ****
--- 3152,3163 ----
  
    unshare_all_rtl (insns);
  
+ #ifdef SETJMP_VIA_SAVE_AREA
+   /* This must be performed before virutal register instantiation.  */
+   if (current_function_calls_alloca)
+     optimize_save_area_alloca (insns);
+ #endif
+ 
    /* Instantiate all virtual registers.  */
  
    instantiate_virtual_regs (current_function_decl, get_insns ());



More information about the Gcc mailing list