explow.c (optimize_save_area_alloca): New function for targets where SETJMP_VIA_SAVE_...
authorDavid S. Miller <davem@tanya.rutgers.edu>
Sat, 17 Jan 1998 22:39:10 +0000 (22:39 +0000)
committerJeff Law <law@gcc.gnu.org>
Sat, 17 Jan 1998 22:39:10 +0000 (15:39 -0700)
        * 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.
CVS ----------------------------------------------------------------------

From-SVN: r17402

gcc/ChangeLog
gcc/explow.c
gcc/toplev.c

index 7fe459942355ad7395a83e249486ab5dad6999e4..b77d6688ce39224843137102c82d23e7f3eccb98 100644 (file)
@@ -1,3 +1,14 @@
+Sat Jan 17 23:41:36 1998  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.
+
 Sat Jan 17 23:22:59 1998  John Wehle  (john@feith.com)
 
        * i386.md: Remove redundant integer push patterns.
index e38c1e43f8b064cd986ec00cb2d7c2ccf34bb5da..0fcc547ff56d77a8fe4f428718e71bd06fc32118 100644 (file)
@@ -1004,6 +1004,86 @@ emit_stack_restore (save_level, sa, after)
     emit_insn (fcn (stack_pointer_rtx, sa));
 }
 \f
+#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. 
+
+                Note, one way this could happen if if SETJMP_VIA_SAVE_AREA
+                was defined on a machine where stacks grow towards higher
+                addresses.
+
+                Right now only supported port with stack that grow upward
+                is the HPPA and it does not define SETJMP_VIA_SAVE_AREA.  */
+             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.
@@ -1021,6 +1101,10 @@ allocate_dynamic_stack_space (size, target, known_align)
      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.  */
@@ -1074,6 +1158,45 @@ allocate_dynamic_stack_space (size, target, known_align)
     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);
   }
@@ -1145,6 +1268,16 @@ allocate_dynamic_stack_space (size, target, known_align)
 #endif
       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
   emit_move_insn (target, virtual_stack_dynamic_rtx);
 #endif
index b0ffcd713e82264b3e261b1f70aa77668f919e4b..86a6c63f7fe904467d249bd398d190db0ced18b1 100644 (file)
@@ -3242,6 +3242,12 @@ rest_of_compilation (decl)
 
   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 ());