OSDN Git Service

* config/alpha/vms.h (VMS_DEBUGGING_INFO): New macro.
[pf3gnuchains/gcc-fork.git] / gcc / explow.c
index aa1e8a6..4d12f00 100644 (file)
@@ -1,23 +1,23 @@
 /* Subroutines for manipulating rtx's in semantically interesting ways.
    Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 
 #include "config.h"
@@ -29,15 +29,11 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "function.h"
 #include "expr.h"
+#include "optabs.h"
 #include "hard-reg-set.h"
 #include "insn-config.h"
+#include "ggc.h"
 #include "recog.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
-
-#if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY
-#define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
-#endif
 
 static rtx break_out_memory_refs       PARAMS ((rtx));
 static void emit_stack_probe           PARAMS ((rtx));
@@ -56,28 +52,16 @@ trunc_int_for_mode (c, mode)
   if (mode == BImode)
     return c & 1 ? STORE_FLAG_VALUE : 0;
 
-  /* We clear out all bits that don't belong in MODE, unless they and our
-     sign bit are all one.  So we get either a reasonable negative
-     value or a reasonable unsigned value.  */
-
-  if (width < HOST_BITS_PER_WIDE_INT
-      && ((c & ((HOST_WIDE_INT) (-1) << (width - 1)))
-           != ((HOST_WIDE_INT) (-1) << (width - 1))))
-    c &= ((HOST_WIDE_INT) 1 << width) - 1;
+  /* Sign-extend for the requested mode.  */
 
-  /* If this would be an entire word for the target, but is not for
-     the host, then sign-extend on the host so that the number will look
-     the same way on the host that it would on the target.
-
-     For example, when building a 64 bit alpha hosted 32 bit sparc
-     targeted compiler, then we want the 32 bit unsigned value -1 to be
-     represented as a 64 bit value -1, and not as 0x00000000ffffffff.
-     The later confuses the sparc backend.  */
-
-  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
-      && BITS_PER_WORD == width
-      && (c & ((HOST_WIDE_INT) 1 << (width - 1))))
-    c |= ((HOST_WIDE_INT) (-1) << width);
+  if (width < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT sign = 1;
+      sign <<= width - 1;
+      c &= (sign << 1) - 1;
+      c ^= sign;
+      c -= sign;
+    }
 
   return c;
 }
@@ -88,12 +72,13 @@ trunc_int_for_mode (c, mode)
 
 rtx
 plus_constant_wide (x, c)
-     register rtx x;
-     register HOST_WIDE_INT c;
+     rtx x;
+     HOST_WIDE_INT c;
 {
-  register RTX_CODE code;
-  register enum machine_mode mode;
-  register rtx tem;
+  RTX_CODE code;
+  rtx y;
+  enum machine_mode mode;
+  rtx tem;
   int all_constant = 0;
 
   if (c == 0)
@@ -103,6 +88,8 @@ plus_constant_wide (x, c)
 
   code = GET_CODE (x);
   mode = GET_MODE (x);
+  y = x;
+
   switch (code)
     {
     case CONST_INT:
@@ -173,22 +160,24 @@ plus_constant_wide (x, c)
          x = XEXP (x, 0);
          goto restart;
        }
-      else if (CONSTANT_P (XEXP (x, 0)))
+      else if (CONSTANT_P (XEXP (x, 1)))
        {
-         x = gen_rtx_PLUS (mode,
-                           plus_constant (XEXP (x, 0), c),
-                           XEXP (x, 1));
+         x = gen_rtx_PLUS (mode, XEXP (x, 0), plus_constant (XEXP (x, 1), c));
          c = 0;
        }
-      else if (CONSTANT_P (XEXP (x, 1)))
+      else if (find_constant_term_loc (&y))
        {
-         x = gen_rtx_PLUS (mode,
-                           XEXP (x, 0),
-                           plus_constant (XEXP (x, 1), c));
+         /* We need to be careful since X may be shared and we can't
+            modify it in place.  */
+         rtx copy = copy_rtx (x);
+         rtx *const_loc = find_constant_term_loc (&copy);
+
+         *const_loc = plus_constant (*const_loc, c);
+         x = copy;
          c = 0;
        }
       break;
-      
+
     default:
       break;
     }
@@ -203,25 +192,6 @@ plus_constant_wide (x, c)
   else
     return x;
 }
-
-/* This is the same as `plus_constant', except that it handles LO_SUM.
-
-   This function should be used via the `plus_constant_for_output' macro.  */
-
-rtx
-plus_constant_for_output_wide (x, c)
-     register rtx x;
-     register HOST_WIDE_INT c;
-{
-  register enum machine_mode mode = GET_MODE (x);
-
-  if (GET_CODE (x) == LO_SUM)
-    return gen_rtx_LO_SUM (mode, XEXP (x, 0),
-                          plus_constant_for_output (XEXP (x, 1), c));
-
-  else
-    return plus_constant (x, c);
-}
 \f
 /* If X is a sum, return a new sum like X but lacking any constant terms.
    Add all the removed constant terms into *CONSTPTR.
@@ -233,7 +203,7 @@ eliminate_constant_term (x, constptr)
      rtx x;
      rtx *constptr;
 {
-  register rtx x0, x1;
+  rtx x0, x1;
   rtx tem;
 
   if (GET_CODE (x) != PLUS)
@@ -315,7 +285,13 @@ rtx
 expr_size (exp)
      tree exp;
 {
-  tree size = size_in_bytes (TREE_TYPE (exp));
+  tree size;
+
+  if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd'
+      && DECL_SIZE_UNIT (exp) != 0)
+    size = DECL_SIZE_UNIT (exp);
+  else
+    size = size_in_bytes (TREE_TYPE (exp));
 
   if (TREE_CODE (size) != INTEGER_CST
       && contains_placeholder_p (size))
@@ -343,7 +319,7 @@ expr_size (exp)
 
 static rtx
 break_out_memory_refs (x)
-     register rtx x;
+     rtx x;
 {
   if (GET_CODE (x) == MEM
       || (CONSTANT_P (x) && CONSTANT_ADDRESS_P (x)
@@ -352,8 +328,8 @@ break_out_memory_refs (x)
   else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
           || GET_CODE (x) == MULT)
     {
-      register rtx op0 = break_out_memory_refs (XEXP (x, 0));
-      register rtx op1 = break_out_memory_refs (XEXP (x, 1));
+      rtx op0 = break_out_memory_refs (XEXP (x, 0));
+      rtx op1 = break_out_memory_refs (XEXP (x, 1));
 
       if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
        x = gen_rtx_fmt_ee (GET_CODE (x), Pmode, op0, op1);
@@ -386,21 +362,38 @@ convert_memory_address (to_mode, x)
     case CONST_DOUBLE:
       return x;
 
+    case SUBREG:
+      if (POINTERS_EXTEND_UNSIGNED >= 0
+         && (SUBREG_PROMOTED_VAR_P (x) || REG_POINTER (SUBREG_REG (x)))
+         && GET_MODE (SUBREG_REG (x)) == to_mode)
+       return SUBREG_REG (x);
+      break;
+
     case LABEL_REF:
-      temp = gen_rtx_LABEL_REF (to_mode, XEXP (x, 0));
-      LABEL_REF_NONLOCAL_P (temp) = LABEL_REF_NONLOCAL_P (x);
-      return temp;
+      if (POINTERS_EXTEND_UNSIGNED >= 0)
+       {
+         temp = gen_rtx_LABEL_REF (to_mode, XEXP (x, 0));
+         LABEL_REF_NONLOCAL_P (temp) = LABEL_REF_NONLOCAL_P (x);
+         return temp;
+       }
+      break;
 
     case SYMBOL_REF:
-      temp = gen_rtx_SYMBOL_REF (to_mode, XSTR (x, 0));
-      SYMBOL_REF_FLAG (temp) = SYMBOL_REF_FLAG (x);
-      CONSTANT_POOL_ADDRESS_P (temp) = CONSTANT_POOL_ADDRESS_P (x);
-      STRING_POOL_ADDRESS_P (temp) = STRING_POOL_ADDRESS_P (x);
-      return temp;
+      if (POINTERS_EXTEND_UNSIGNED >= 0)
+       {
+         temp = gen_rtx_SYMBOL_REF (to_mode, XSTR (x, 0));
+         SYMBOL_REF_FLAG (temp) = SYMBOL_REF_FLAG (x);
+         CONSTANT_POOL_ADDRESS_P (temp) = CONSTANT_POOL_ADDRESS_P (x);
+         STRING_POOL_ADDRESS_P (temp) = STRING_POOL_ADDRESS_P (x);
+         return temp;
+       }
+      break;
 
     case CONST:
-      return gen_rtx_CONST (to_mode, 
-                           convert_memory_address (to_mode, XEXP (x, 0)));
+      if (POINTERS_EXTEND_UNSIGNED >= 0)
+        return gen_rtx_CONST (to_mode, 
+                             convert_memory_address (to_mode, XEXP (x, 0)));
+      break;
 
     case PLUS:
     case MULT:
@@ -408,10 +401,11 @@ convert_memory_address (to_mode, x)
         permute the conversion and addition operation.  We can always safely
         permute them if we are making the address narrower.  In addition,
         always permute the operations if this is a constant.  */
-      if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode)
-         || (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT
-             && (INTVAL (XEXP (x, 1)) + 20000 < 40000
-                 || CONSTANT_P (XEXP (x, 0)))))
+      if (POINTERS_EXTEND_UNSIGNED >= 0
+         && (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode)
+             || (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT
+                 && (INTVAL (XEXP (x, 1)) + 20000 < 40000
+                     || CONSTANT_P (XEXP (x, 0))))))
        return gen_rtx_fmt_ee (GET_CODE (x), to_mode, 
                               convert_memory_address (to_mode, XEXP (x, 0)),
                               convert_memory_address (to_mode, XEXP (x, 1)));
@@ -441,7 +435,7 @@ convert_memory_address (to_mode, x)
 
 rtx
 copy_all_regs (x)
-     register rtx x;
+     rtx x;
 {
   if (GET_CODE (x) == REG)
     {
@@ -457,8 +451,8 @@ copy_all_regs (x)
   else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
           || GET_CODE (x) == MULT)
     {
-      register rtx op0 = copy_all_regs (XEXP (x, 0));
-      register rtx op1 = copy_all_regs (XEXP (x, 1));
+      rtx op0 = copy_all_regs (XEXP (x, 0));
+      rtx op1 = copy_all_regs (XEXP (x, 1));
       if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
        x = gen_rtx_fmt_ee (GET_CODE (x), Pmode, op0, op1);
     }
@@ -472,15 +466,15 @@ copy_all_regs (x)
 rtx
 memory_address (mode, x)
      enum machine_mode mode;
-     register rtx x;
+     rtx x;
 {
-  register rtx oldx = x;
+  rtx oldx = x;
 
   if (GET_CODE (x) == ADDRESSOF)
     return x;
 
 #ifdef POINTERS_EXTEND_UNSIGNED
-  if (GET_MODE (x) == ptr_mode)
+  if (GET_MODE (x) != Pmode)
     x = convert_memory_address (Pmode, x);
 #endif
 
@@ -622,10 +616,12 @@ validize_mem (ref)
 {
   if (GET_CODE (ref) != MEM)
     return ref;
-  if (memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
+  if (! (flag_force_addr && CONSTANT_ADDRESS_P (XEXP (ref, 0)))
+      && memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
     return ref;
+
   /* Don't alter REF itself, since that is probably a stack slot.  */
-  return change_address (ref, GET_MODE (ref), XEXP (ref, 0));
+  return replace_equiv_address (ref, XEXP (ref, 0));
 }
 \f
 /* Given REF, either a MEM or a REG, and T, either the type of X or
@@ -648,72 +644,6 @@ maybe_set_unchanging (ref, t)
       || TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
     RTX_UNCHANGING_P (ref) = 1;
 }
-
-/* Given REF, a MEM, and T, either the type of X or the expression
-   corresponding to REF, set the memory attributes.  OBJECTP is nonzero
-   if we are making a new object of this type.  */
-
-void
-set_mem_attributes (ref, t, objectp)
-     rtx ref;
-     tree t;
-     int objectp;
-{
-  tree type;
-
-  /* It can happen that type_for_mode was given a mode for which there
-     is no language-level type.  In which case it returns NULL, which
-     we can see here.  */
-  if (t == NULL_TREE)
-    return;
-
-  type = TYPE_P (t) ? t : TREE_TYPE (t);
-
-  /* Get the alias set from the expression or type (perhaps using a
-     front-end routine) and then copy bits from the type.  */
-
-  /* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY (type)
-     here, because, in C and C++, the fact that a location is accessed
-     through a const expression does not mean that the value there can
-     never change.  */
-  MEM_ALIAS_SET (ref) = get_alias_set (t);
-  MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type);
-  MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);
-
-  /* If we are making an object of this type, we know that it is a scalar if
-     the type is not an aggregate. */
-  if (objectp && ! AGGREGATE_TYPE_P (type))
-    MEM_SCALAR_P (ref) = 1;
-
-  /* If T is a type, this is all we can do.  Otherwise, we may be able
-     to deduce some more information about the expression.  */
-  if (TYPE_P (t))
-    return;
-
-  maybe_set_unchanging (ref, t);
-  if (TREE_THIS_VOLATILE (t))
-    MEM_VOLATILE_P (ref) = 1;
-
-  /* Now see if we can say more about whether it's an aggregate or
-     scalar.  If we already know it's an aggregate, don't bother.  */
-  if (MEM_IN_STRUCT_P (ref))
-    return;
-
-  /* Now remove any NOPs: they don't change what the underlying object is.
-     Likewise for SAVE_EXPR.  */
-  while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
-        || TREE_CODE (t) == NON_LVALUE_EXPR || TREE_CODE (t) == SAVE_EXPR)
-    t = TREE_OPERAND (t, 0);
-
-  /* Since we already know the type isn't an aggregate, if this is a decl,
-     it must be a scalar.  Or if it is a reference into an aggregate,
-     this is part of an aggregate.   Otherwise we don't know.  */
-  if (DECL_P (t))
-    MEM_SCALAR_P (ref) = 1;
-  else if (TREE_CODE (t) == COMPONENT_REF || TREE_CODE (t) == ARRAY_REF
-          || TREE_CODE (t) == BIT_FIELD_REF)
-    MEM_IN_STRUCT_P (ref) = 1;
-}
 \f
 /* Return a modified copy of X with its memory address copied
    into a temporary register to protect it from side effects.
@@ -724,21 +654,13 @@ rtx
 stabilize (x)
      rtx x;
 {
-  register rtx addr;
 
-  if (GET_CODE (x) != MEM)
+  if (GET_CODE (x) != MEM
+      || ! rtx_unstable_p (XEXP (x, 0)))
     return x;
 
-  addr = XEXP (x, 0);
-  if (rtx_unstable_p (addr))
-    {
-      rtx temp = force_reg (Pmode, copy_all_regs (addr));
-      rtx mem = gen_rtx_MEM (GET_MODE (x), temp);
-
-      MEM_COPY_ATTRIBUTES (mem, x);
-      return mem;
-    }
-  return x;
+  return
+    replace_equiv_address (x, force_reg (Pmode, copy_all_regs (XEXP (x, 0))));
 }
 \f
 /* Copy the value or contents of X to a new temp reg and return that reg.  */
@@ -747,7 +669,7 @@ rtx
 copy_to_reg (x)
      rtx x;
 {
-  register rtx temp = gen_reg_rtx (GET_MODE (x));
+  rtx temp = gen_reg_rtx (GET_MODE (x));
  
   /* If not an operand, must be an address with PLUS and MULT so
      do the computation.  */ 
@@ -778,7 +700,7 @@ copy_to_mode_reg (mode, x)
      enum machine_mode mode;
      rtx x;
 {
-  register rtx temp = gen_reg_rtx (mode);
+  rtx temp = gen_reg_rtx (mode);
   
   /* If not an operand, must be an address with PLUS and MULT so
      do the computation.  */ 
@@ -805,7 +727,7 @@ force_reg (mode, x)
      enum machine_mode mode;
      rtx x;
 {
-  register rtx temp, insn, set;
+  rtx temp, insn, set;
 
   if (GET_CODE (x) == REG)
     return x;
@@ -823,14 +745,7 @@ force_reg (mode, x)
   if (CONSTANT_P (x)
       && (set = single_set (insn)) != 0
       && SET_DEST (set) == temp)
-    {
-      rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-
-      if (note)
-       XEXP (note, 0) = x;
-      else
-       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, x, REG_NOTES (insn));
-    }
+    set_unique_reg_note (insn, REG_EQUAL, x);
   return temp;
 }
 
@@ -841,7 +756,7 @@ rtx
 force_not_mem (x)
      rtx x;
 {
-  register rtx temp;
+  rtx temp;
 
   if (GET_CODE (x) != MEM || GET_MODE (x) == BLKmode)
     return x;
@@ -860,7 +775,7 @@ copy_to_suggested_reg (x, target, mode)
      rtx x, target;
      enum machine_mode mode;
 {
-  register rtx temp;
+  rtx temp;
 
   if (target && GET_CODE (target) == REG)
     temp = target;
@@ -986,7 +901,6 @@ rtx
 round_push (size)
      rtx size;
 {
-#ifdef PREFERRED_STACK_BOUNDARY
   int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
   if (align == 1)
     return size;
@@ -1007,7 +921,6 @@ round_push (size)
                            NULL_RTX, 1);
       size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1);
     }
-#endif /* PREFERRED_STACK_BOUNDARY */
   return size;
 }
 \f
@@ -1270,9 +1183,7 @@ allocate_dynamic_stack_space (size, target, known_align)
   /* We can't attempt to minimize alignment necessary, because we don't
      know the final value of preferred_stack_boundary yet while executing
      this code.  */
-#ifdef PREFERRED_STACK_BOUNDARY
   cfun->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
-#endif
 
   /* We will need to ensure that the address we return is aligned to
      BIGGEST_ALIGNMENT.  If STACK_DYNAMIC_OFFSET is defined, we don't
@@ -1287,22 +1198,17 @@ allocate_dynamic_stack_space (size, target, known_align)
      If we have to align, we must leave space in SIZE for the hole
      that might result from the alignment operation.  */
 
-#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || ! defined (PREFERRED_STACK_BOUNDARY)
+#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET)
 #define MUST_ALIGN 1
 #else
 #define MUST_ALIGN (PREFERRED_STACK_BOUNDARY < BIGGEST_ALIGNMENT)
 #endif
 
   if (MUST_ALIGN)
-    {
-      if (GET_CODE (size) == CONST_INT)
-       size = GEN_INT (INTVAL (size)
-                       + (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1));
-      else
-       size = expand_binop (Pmode, add_optab, size,
-                            GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1),
-                            NULL_RTX, 1, OPTAB_LIB_WIDEN);
-    }
+    size
+      = force_operand (plus_constant (size, 
+                                     BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1),
+                      NULL_RTX);
 
 #ifdef SETJMP_VIA_SAVE_AREA
   /* If setjmp restores regs from a save area in the stack frame,
@@ -1322,15 +1228,14 @@ allocate_dynamic_stack_space (size, target, known_align)
        /* See optimize_save_area_alloca to understand what is being
           set up here.  */
 
-#if !defined(PREFERRED_STACK_BOUNDARY) || !defined(MUST_ALIGN) || (PREFERRED_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
+       /* ??? Code below assumes that the save area needs maximal
+          alignment.  This constraint may be too strong.  */
+       if (PREFERRED_STACK_BOUNDARY != BIGGEST_ALIGNMENT)
+         abort ();
 
        if (GET_CODE (size) == CONST_INT)
          {
-           int new = INTVAL (size) / align * align;
+           HOST_WIDE_INT new = INTVAL (size) / align * align;
 
            if (INTVAL (size) != new)
              setjmpless_size = GEN_INT (new);
@@ -1372,32 +1277,29 @@ allocate_dynamic_stack_space (size, target, known_align)
      way of knowing which systems have this problem.  So we avoid even
      momentarily mis-aligning the stack.  */
 
-#ifdef PREFERRED_STACK_BOUNDARY
   /* If we added a variable amount to SIZE,
      we can no longer assume it is aligned.  */
 #if !defined (SETJMP_VIA_SAVE_AREA)
   if (MUST_ALIGN || known_align % PREFERRED_STACK_BOUNDARY != 0)
 #endif
     size = round_push (size);
-#endif
 
   do_pending_stack_adjust ();
 
  /* We ought to be called always on the toplevel and stack ought to be aligned
-    propertly.  */
-#ifdef PREFERRED_STACK_BOUNDARY
+    properly.  */
   if (stack_pointer_delta % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT))
     abort ();
-#endif
 
   /* If needed, check that we have the required amount of stack.  Take into
      account what has already been checked.  */
   if (flag_stack_check && ! STACK_CHECK_BUILTIN)
     probe_stack_range (STACK_CHECK_MAX_FRAME_SIZE + STACK_CHECK_PROTECT, size);
 
-  /* Don't use a TARGET that isn't a pseudo.  */
+  /* Don't use a TARGET that isn't a pseudo or is the wrong mode.  */
   if (target == 0 || GET_CODE (target) != REG
-      || REGNO (target) < FIRST_PSEUDO_REGISTER)
+      || REGNO (target) < FIRST_PSEUDO_REGISTER
+      || GET_MODE (target) != Pmode)
     target = gen_reg_rtx (Pmode);
 
   mark_reg_pointer (target, known_align);
@@ -1411,18 +1313,13 @@ allocate_dynamic_stack_space (size, target, known_align)
       enum machine_mode mode = STACK_SIZE_MODE;
       insn_operand_predicate_fn pred;
 
-      pred = insn_data[(int) CODE_FOR_allocate_stack].operand[0].predicate;
-      if (pred && ! ((*pred) (target, Pmode)))
-#ifdef POINTERS_EXTEND_UNSIGNED
-       target = convert_memory_address (Pmode, target);
-#else
-       target = copy_to_mode_reg (Pmode, target);
-#endif
-
+      /* We don't have to check against the predicate for operand 0 since
+        TARGET is known to be a pseudo of the proper mode, which must
+        be valid for the operand.  For operand 1, convert to the
+        proper mode and validate.  */
       if (mode == VOIDmode)
-       mode = Pmode;
+       mode = insn_data[(int) CODE_FOR_allocate_stack].operand[1].mode;
 
-      size = convert_modes (mode, ptr_mode, size, 1);
       pred = insn_data[(int) CODE_FOR_allocate_stack].operand[1].predicate;
       if (pred && ! ((*pred) (size, mode)))
        size = copy_to_mode_reg (mode, size);
@@ -1435,7 +1332,6 @@ allocate_dynamic_stack_space (size, target, known_align)
 #ifndef STACK_GROWS_DOWNWARD
       emit_move_insn (target, virtual_stack_dynamic_rtx);
 #endif
-      size = convert_modes (Pmode, ptr_mode, size, 1);
 
       /* Check stack bounds if necessary.  */
       if (current_function_limit_stack)
@@ -1452,7 +1348,7 @@ allocate_dynamic_stack_space (size, target, known_align)
                                    NULL_RTX, 1, OPTAB_WIDEN);
 #endif
          emit_cmp_and_jump_insns (available, size, GEU, NULL_RTX, Pmode, 1,
-                                  0, space_available);
+                                  space_available);
 #ifdef HAVE_trap
          if (HAVE_trap)
            emit_insn (gen_trap ());
@@ -1474,6 +1370,7 @@ allocate_dynamic_stack_space (size, target, known_align)
                                 REG_NOTES (note_target));
        }
 #endif /* SETJMP_VIA_SAVE_AREA */
+
 #ifdef STACK_GROWS_DOWNWARD
   emit_move_insn (target, virtual_stack_dynamic_rtx);
 #endif
@@ -1520,6 +1417,7 @@ set_stack_check_libfunc (libfunc)
      rtx libfunc;
 {
   stack_check_libfunc = libfunc;
+  ggc_add_rtx_root (&stack_check_libfunc, 1);
 }
 \f
 /* Emit one stack probe at ADDRESS, an address within the stack.  */
@@ -1555,7 +1453,11 @@ probe_stack_range (first, size)
      HOST_WIDE_INT first;
      rtx size;
 {
-  /* First see if the front end has set up a function for us to call to
+  /* First ensure SIZE is Pmode.  */
+  if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
+    size = convert_to_mode (Pmode, size, 1);
+
+  /* Next see if the front end has set up a function for us to call to
      check the stack.  */
   if (stack_check_libfunc != 0)
     {
@@ -1569,7 +1471,7 @@ probe_stack_range (first, size)
        addr = convert_memory_address (ptr_mode, addr);
 #endif
 
-      emit_library_call (stack_check_libfunc, 0, VOIDmode, 1, addr,
+      emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr,
                         ptr_mode);
     }
 
@@ -1639,13 +1541,13 @@ probe_stack_range (first, size)
          || REGNO (test_addr) < FIRST_PSEUDO_REGISTER)
        test_addr = force_reg (Pmode, test_addr);
 
-      emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG);
+      emit_note (NULL, NOTE_INSN_LOOP_BEG);
       emit_jump (test_lab);
 
       emit_label (loop_lab);
       emit_stack_probe (test_addr);
 
-      emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT);
+      emit_note (NULL, NOTE_INSN_LOOP_CONT);
 
 #ifdef STACK_GROWS_DOWNWARD
 #define CMP_OPCODE GTU
@@ -1662,9 +1564,9 @@ probe_stack_range (first, size)
 
       emit_label (test_lab);
       emit_cmp_and_jump_insns (test_addr, last_addr, CMP_OPCODE,
-                              NULL_RTX, Pmode, 1, 0, loop_lab);
+                              NULL_RTX, Pmode, 1, loop_lab);
       emit_jump (end_lab);
-      emit_note (NULL_PTR, NOTE_INSN_LOOP_END);
+      emit_note (NULL, NOTE_INSN_LOOP_END);
       emit_label (end_lab);
 
       emit_stack_probe (last_addr);
@@ -1678,7 +1580,7 @@ probe_stack_range (first, size)
    otherwise 0.
    OUTGOING is 1 if on a machine with register windows this function
    should return the register in which the function will put its result
-   and 0 otherwise. */
+   and 0 otherwise.  */
 
 rtx
 hard_function_value (valtype, func, outgoing)