function.c (instantiate_decls): Remove valid_only argument.
authorRichard Henderson <rth@redhat.com>
Sat, 30 Apr 2005 03:17:53 +0000 (20:17 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Sat, 30 Apr 2005 03:17:53 +0000 (20:17 -0700)
        * function.c (instantiate_decls): Remove valid_only argument.
        (instantiate_decls_1, instantiate_decl): Likewise.
        (instantiate_virtual_regs_1): Delete.
        (instantiate_virtual_regs_lossage): Delete.
        (instantiate_virtual_regs_in_rtx): New.
        (safe_insn_predicate): New.
        (instantiate_virtual_regs_in_insn): New.
        (instantiate_virtual_regs): Update to match all that.  Only run
        instantiate_decls once.

From-SVN: r99032

gcc/ChangeLog
gcc/function.c

index 4c5843aba37667cc58a3de06c8f74867ff6cd826..7b5c62c85fefe33ebb2766a43a621379902df1e1 100644 (file)
@@ -1,3 +1,15 @@
+2005-04-29  Richard Henderson  <rth@redhat.com>
+
+       * function.c (instantiate_decls): Remove valid_only argument.
+       (instantiate_decls_1, instantiate_decl): Likewise.
+       (instantiate_virtual_regs_1): Delete.
+       (instantiate_virtual_regs_lossage): Delete.
+       (instantiate_virtual_regs_in_rtx): New.
+       (safe_insn_predicate): New.
+       (instantiate_virtual_regs_in_insn): New.
+       (instantiate_virtual_regs): Update to match all that.  Only run
+       instantiate_decls once.
+
 2005-04-29  Richard Henderson  <rth@redhat.com>
            Daniel Jacobowitz  <dan@codesourcery.com>
 
index a092d6c62e0d6dbab1b545fa2744475c6de043e6..156dc3bca71554848632a87650a7be5c7b48fdc5 100644 (file)
@@ -189,11 +189,6 @@ struct temp_slot GTY(())
 static rtx assign_stack_local_1 (enum machine_mode, HOST_WIDE_INT, int,
                                 struct function *);
 static struct temp_slot *find_temp_slot_from_address (rtx);
-static void instantiate_decls (tree, int);
-static void instantiate_decls_1 (tree, int);
-static void instantiate_decl (rtx, HOST_WIDE_INT, int);
-static rtx instantiate_new_reg (rtx, HOST_WIDE_INT *);
-static int instantiate_virtual_regs_1 (rtx *, rtx, int);
 static void pad_to_arg_alignment (struct args_size *, int, struct args_size *);
 static void pad_below (struct args_size *, enum machine_mode, tree);
 static void reorder_blocks_1 (rtx, tree, varray_type *);
@@ -214,7 +209,6 @@ static rtx keep_stack_depressed (rtx);
 static void prepare_function_start (tree);
 static void do_clobber_return_reg (rtx, void *);
 static void do_use_return_reg (rtx, void *);
-static void instantiate_virtual_regs_lossage (rtx);
 static void set_insn_locators (rtx, int) ATTRIBUTE_UNUSED;
 \f
 /* Pointer to chain of `struct function' for containing functions.  */
@@ -1217,608 +1211,446 @@ static int cfa_offset;
 #endif
 
 \f
-/* Pass through the INSNS of function FNDECL and convert virtual register
-   references to hard register references.  */
+/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
+   is a virtual register, return the equivalent hard register and set the
+   offset indirectly through the pointer.  Otherwise, return 0.  */
 
-void
-instantiate_virtual_regs (void)
+static rtx
+instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
 {
-  rtx insn;
-
-  /* Compute the offsets to use for this function.  */
-  in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
-  var_offset = STARTING_FRAME_OFFSET;
-  dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
-  out_arg_offset = STACK_POINTER_OFFSET;
-  cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
-
-  /* Scan all variables and parameters of this function.  For each that is
-     in memory, instantiate all virtual registers if the result is a valid
-     address.  If not, we do it later.  That will handle most uses of virtual
-     regs on many machines.  */
-  instantiate_decls (current_function_decl, 1);
-
-  /* Initialize recognition, indicating that volatile is OK.  */
-  init_recog ();
-
-  /* Scan through all the insns, instantiating every virtual register still
-     present.  */
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      {
-       instantiate_virtual_regs_1 (&PATTERN (insn), insn, 1);
-       if (INSN_DELETED_P (insn))
-         continue;
-       instantiate_virtual_regs_1 (&REG_NOTES (insn), NULL_RTX, 0);
-       /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE.  */
-       if (CALL_P (insn))
-         instantiate_virtual_regs_1 (&CALL_INSN_FUNCTION_USAGE (insn),
-                                     NULL_RTX, 0);
-
-       /* Past this point all ASM statements should match.  Verify that
-          to avoid failures later in the compilation process.  */
-        if (asm_noperands (PATTERN (insn)) >= 0
-           && ! check_asm_operands (PATTERN (insn)))
-          instantiate_virtual_regs_lossage (insn);
-      }
+  rtx new;
+  HOST_WIDE_INT offset;
 
-  /* Now instantiate the remaining register equivalences for debugging info.
-     These will not be valid addresses.  */
-  instantiate_decls (current_function_decl, 0);
+  if (x == virtual_incoming_args_rtx)
+    new = arg_pointer_rtx, offset = in_arg_offset;
+  else if (x == virtual_stack_vars_rtx)
+    new = frame_pointer_rtx, offset = var_offset;
+  else if (x == virtual_stack_dynamic_rtx)
+    new = stack_pointer_rtx, offset = dynamic_offset;
+  else if (x == virtual_outgoing_args_rtx)
+    new = stack_pointer_rtx, offset = out_arg_offset;
+  else if (x == virtual_cfa_rtx)
+    new = arg_pointer_rtx, offset = cfa_offset;
+  else
+    return NULL_RTX;
 
-  /* Indicate that, from now on, assign_stack_local should use
-     frame_pointer_rtx.  */
-  virtuals_instantiated = 1;
+  *poffset = offset;
+  return new;
 }
 
-/* Scan all decls in FNDECL (both variables and parameters) and instantiate
-   all virtual registers in their DECL_RTL's.
+/* A subroutine of instantiate_virtual_regs, called via for_each_rtx.
+   Instantiate any virtual registers present inside of *LOC.  The expression
+   is simplified, as much as possible, but is not to be considered "valid"
+   in any sense implied by the target.  If any change is made, set CHANGED
+   to true.  */
 
-   If VALID_ONLY, do this only if the resulting address is still valid.
-   Otherwise, always do it.  */
-
-static void
-instantiate_decls (tree fndecl, int valid_only)
+static int
+instantiate_virtual_regs_in_rtx (rtx *loc, void *data)
 {
-  tree decl;
+  HOST_WIDE_INT offset;
+  bool *changed = (bool *) data;
+  rtx x, new;
 
-  /* Process all parameters of the function.  */
-  for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
+  x = *loc;
+  if (x == 0)
+    return 0;
+
+  switch (GET_CODE (x))
     {
-      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
-      HOST_WIDE_INT size_rtl;
+    case REG:
+      new = instantiate_new_reg (x, &offset);
+      if (new)
+       {
+         *loc = plus_constant (new, offset);
+         if (changed)
+           *changed = true;
+       }
+      return -1;
+
+    case PLUS:
+      new = instantiate_new_reg (XEXP (x, 0), &offset);
+      if (new)
+       {
+         new = plus_constant (new, offset);
+         *loc = simplify_gen_binary (PLUS, GET_MODE (x), new, XEXP (x, 1));
+         if (changed)
+           *changed = true;
+         return -1;
+       }
 
-      instantiate_decl (DECL_RTL (decl), size, valid_only);
+      /* FIXME -- from old code */
+         /* If we have (plus (subreg (virtual-reg)) (const_int)), we know
+            we can commute the PLUS and SUBREG because pointers into the
+            frame are well-behaved.  */
+      break;
 
-      /* If the parameter was promoted, then the incoming RTL mode may be
-        larger than the declared type size.  We must use the larger of
-        the two sizes.  */
-      size_rtl = GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl)));
-      size = MAX (size_rtl, size);
-      instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only);
+    default:
+      break;
     }
 
-  /* Now process all variables defined in the function or its subblocks.  */
-  instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
+  return 0;
 }
 
-/* Subroutine of instantiate_decls: Process all decls in the given
-   BLOCK node and all its subblocks.  */
+/* A subroutine of instantiate_virtual_regs_in_insn.  Return true if X
+   matches the predicate for insn CODE operand OPERAND.  */
 
-static void
-instantiate_decls_1 (tree let, int valid_only)
+static int
+safe_insn_predicate (int code, int operand, rtx x)
 {
-  tree t;
+  const struct insn_operand_data *op_data;
 
-  for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
-    if (DECL_RTL_SET_P (t))
-      instantiate_decl (DECL_RTL (t),
-                       int_size_in_bytes (TREE_TYPE (t)),
-                       valid_only);
+  if (code < 0)
+    return true;
 
-  /* Process all subblocks.  */
-  for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
-    instantiate_decls_1 (t, valid_only);
-}
+  op_data = &insn_data[code].operand[operand];
+  if (op_data->predicate == NULL)
+    return true;
 
-/* Subroutine of the preceding procedures: Given RTL representing a
-   decl and the size of the object, do any instantiation required.
+  return op_data->predicate (x, op_data->mode);
+}
 
-   If VALID_ONLY is nonzero, it means that the RTL should only be
-   changed if the new address is valid.  */
+/* A subroutine of instantiate_virtual_regs.  Instantiate any virtual
+   registers present inside of insn.  The result will be a valid insn.  */
 
 static void
-instantiate_decl (rtx x, HOST_WIDE_INT size, int valid_only)
+instantiate_virtual_regs_in_insn (rtx insn)
 {
-  enum machine_mode mode;
-  rtx addr;
-
-  if (x == 0)
-    return;
+  HOST_WIDE_INT offset;
+  int insn_code, i;
+  bool any_change;
+  rtx set, new, x, seq;
 
-  /* If this is a CONCAT, recurse for the pieces.  */
-  if (GET_CODE (x) == CONCAT)
+  /* There are some special cases to be handled first.  */
+  set = single_set (insn);
+  if (set)
     {
-      instantiate_decl (XEXP (x, 0), size / 2, valid_only);
-      instantiate_decl (XEXP (x, 1), size / 2, valid_only);
-      return;
-    }
-
-  /* If this is not a MEM, no need to do anything.  Similarly if the
-     address is a constant or a register that is not a virtual register.  */
-  if (!MEM_P (x))
-    return;
+      /* We're allowed to assign to a virtual register.  This is interpreted
+        to mean that the underlying register gets assigned the inverse
+        transformation.  This is used, for example, in the handling of
+        non-local gotos.  */
+      new = instantiate_new_reg (SET_DEST (set), &offset);
+      if (new)
+       {
+         start_sequence ();
 
-  addr = XEXP (x, 0);
-  if (CONSTANT_P (addr)
-      || (REG_P (addr)
-         && (REGNO (addr) < FIRST_VIRTUAL_REGISTER
-             || REGNO (addr) > LAST_VIRTUAL_REGISTER)))
-    return;
+         for_each_rtx (&SET_SRC (set), instantiate_virtual_regs_in_rtx, NULL);
+         x = simplify_gen_binary (PLUS, GET_MODE (new), SET_SRC (set),
+                                  GEN_INT (-offset));
+         x = force_operand (x, new);
+         if (x != new)
+           emit_move_insn (new, x);
 
-  /* If we should only do this if the address is valid, copy the address.
-     We need to do this so we can undo any changes that might make the
-     address invalid.  This copy is unfortunate, but probably can't be
-     avoided.  */
+         seq = get_insns ();
+         end_sequence ();
 
-  if (valid_only)
-    addr = copy_rtx (addr);
+         emit_insn_before (seq, insn);
+         delete_insn (insn);
+         return;
+       }
 
-  instantiate_virtual_regs_1 (&addr, NULL_RTX, 0);
+      /* Handle a straight copy from a virtual register by generating a
+        new add insn.  The difference between this and falling through
+        to the generic case is avoiding a new pseudo and eliminating a
+        move insn in the initial rtl stream.  */
+      new = instantiate_new_reg (SET_SRC (set), &offset);
+      if (new && offset != 0
+         && REG_P (SET_DEST (set))
+         && REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER)
+       {
+         start_sequence ();
 
-  if (valid_only && size >= 0)
-    {
-      unsigned HOST_WIDE_INT decl_size = size;
+         x = expand_simple_binop (GET_MODE (SET_DEST (set)), PLUS,
+                                  new, GEN_INT (offset), SET_DEST (set),
+                                  1, OPTAB_LIB_WIDEN);
+         if (x != SET_DEST (set))
+           emit_move_insn (SET_DEST (set), x);
 
-      /* Now verify that the resulting address is valid for every integer or
-        floating-point mode up to and including SIZE bytes long.  We do this
-        since the object might be accessed in any mode and frame addresses
-        are shared.  */
+         seq = get_insns ();
+         end_sequence ();
 
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-          mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size;
-          mode = GET_MODE_WIDER_MODE (mode))
-       if (! memory_address_p (mode, addr))
+         emit_insn_before (seq, insn);
+         delete_insn (insn);
          return;
+       }
 
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
-          mode != VOIDmode && GET_MODE_SIZE (mode) <= decl_size;
-          mode = GET_MODE_WIDER_MODE (mode))
-       if (! memory_address_p (mode, addr))
-         return;
-    }
+      extract_insn (insn);
 
-  /* Put back the address now that we have updated it and we either know
-     it is valid or we don't care whether it is valid.  */
+      /* Handle a plus involving a virtual register by determining if the
+        operands remain valid if they're modified in place.  */
+      if (GET_CODE (SET_SRC (set)) == PLUS
+         && recog_data.n_operands >= 3
+         && recog_data.operand_loc[1] == &XEXP (SET_SRC (set), 0)
+         && recog_data.operand_loc[2] == &XEXP (SET_SRC (set), 1)
+         && GET_CODE (recog_data.operand[2]) == CONST_INT
+         && (new = instantiate_new_reg (recog_data.operand[1], &offset)))
+       {
+         offset += INTVAL (recog_data.operand[2]);
 
-  XEXP (x, 0) = addr;
-}
-\f
-/* Given a piece of RTX and a pointer to a HOST_WIDE_INT, if the RTX
-   is a virtual register, return the equivalent hard register and set the
-   offset indirectly through the pointer.  Otherwise, return 0.  */
+         /* If the sum is zero, then replace with a plain move.  */
+         if (offset == 0)
+           {
+             start_sequence ();
+             emit_move_insn (SET_DEST (set), new);
+             seq = get_insns ();
+             end_sequence ();
 
-static rtx
-instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
-{
-  rtx new;
-  HOST_WIDE_INT offset;
+             emit_insn_before (seq, insn);
+             delete_insn (insn);
+             return;
+           }
 
-  if (x == virtual_incoming_args_rtx)
-    new = arg_pointer_rtx, offset = in_arg_offset;
-  else if (x == virtual_stack_vars_rtx)
-    new = frame_pointer_rtx, offset = var_offset;
-  else if (x == virtual_stack_dynamic_rtx)
-    new = stack_pointer_rtx, offset = dynamic_offset;
-  else if (x == virtual_outgoing_args_rtx)
-    new = stack_pointer_rtx, offset = out_arg_offset;
-  else if (x == virtual_cfa_rtx)
-    new = arg_pointer_rtx, offset = cfa_offset;
+         x = gen_int_mode (offset, recog_data.operand_mode[2]);
+         insn_code = INSN_CODE (insn);
+
+         /* Using validate_change and apply_change_group here leaves
+            recog_data in an invalid state.  Since we know exactly what
+            we want to check, do those two by hand.  */
+         if (safe_insn_predicate (insn_code, 1, new)
+             && safe_insn_predicate (insn_code, 2, x))
+           {
+             *recog_data.operand_loc[1] = recog_data.operand[1] = new;
+             *recog_data.operand_loc[2] = recog_data.operand[2] = x;
+             any_change = true;
+             goto verify;
+           }
+       }
+    }
   else
-    return 0;
+    extract_insn (insn);
 
-  *poffset = offset;
-  return new;
-}
-\f
+  insn_code = INSN_CODE (insn);
+  any_change = false;
 
-/* Called when instantiate_virtual_regs has failed to update the instruction.
-   Usually this means that non-matching instruction has been emit, however for
-   asm statements it may be the problem in the constraints.  */
-static void
-instantiate_virtual_regs_lossage (rtx insn)
-{
-  gcc_assert (asm_noperands (PATTERN (insn)) >= 0);
-  error_for_asm (insn, "impossible constraint in %<asm%>");
-  delete_insn (insn);
-}
-/* Given a pointer to a piece of rtx and an optional pointer to the
-   containing object, instantiate any virtual registers present in it.
+  /* In the general case, we expect virtual registers to appear only in
+     operands, and then only as either bare registers or inside memories.  */
+  for (i = 0; i < recog_data.n_operands; ++i)
+    {
+      x = recog_data.operand[i];
+      switch (GET_CODE (x))
+       {
+       case MEM:
+         {
+           rtx addr = XEXP (x, 0);
+           bool changed = false;
 
-   If EXTRA_INSNS, we always do the replacement and generate
-   any extra insns before OBJECT.  If it zero, we do nothing if replacement
-   is not valid.
+           for_each_rtx (&addr, instantiate_virtual_regs_in_rtx, &changed);
+           if (!changed)
+             continue;
 
-   Return 1 if we either had nothing to do or if we were able to do the
-   needed replacement.  Return 0 otherwise; we only return zero if
-   EXTRA_INSNS is zero.
+           start_sequence ();
+           x = replace_equiv_address (x, addr);
+           seq = get_insns ();
+           end_sequence ();
+           if (seq)
+             emit_insn_before (seq, insn);
+         }
+         break;
 
-   We first try some simple transformations to avoid the creation of extra
-   pseudos.  */
+       case REG:
+         new = instantiate_new_reg (x, &offset);
+         if (new == NULL)
+           continue;
+         if (offset == 0)
+           x = new;
+         else
+           {
+             start_sequence ();
 
-static int
-instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns)
-{
-  rtx x;
-  RTX_CODE code;
-  rtx new = 0;
-  HOST_WIDE_INT offset = 0;
-  rtx temp;
-  rtx seq;
-  int i, j;
-  const char *fmt;
+             /* Careful, special mode predicates may have stuff in
+                insn_data[insn_code].operand[i].mode that isn't useful
+                to us for computing a new value.  */
+             /* ??? Recognize address_operand and/or "p" constraints
+                to see if (plus new offset) is a valid before we put
+                this through expand_simple_binop.  */
+             x = expand_simple_binop (GET_MODE (x), PLUS, new,
+                                      GEN_INT (offset), NULL_RTX,
+                                      1, OPTAB_LIB_WIDEN);
+             seq = get_insns ();
+             end_sequence ();
+             emit_insn_before (seq, insn);
+           }
+         break;
 
-  /* Re-start here to avoid recursion in common cases.  */
- restart:
+       case SUBREG:
+         new = instantiate_new_reg (SUBREG_REG (x), &offset);
+         if (new == NULL)
+           continue;
+         if (offset != 0)
+           {
+             start_sequence ();
+             new = expand_simple_binop (GET_MODE (new), PLUS, new,
+                                        GEN_INT (offset), NULL_RTX,
+                                        1, OPTAB_LIB_WIDEN);
+             seq = get_insns ();
+             end_sequence ();
+             emit_insn_before (seq, insn);
+           }
+         x = simplify_gen_subreg (insn_data[insn_code].operand[i].mode,
+                                  new, GET_MODE (new), SUBREG_BYTE (x));
+         break;
 
-  x = *loc;
-  if (x == 0)
-    return 1;
+       default:
+         continue;
+       }
 
-  /* We may have detected and deleted invalid asm statements.  */
-  if (object && INSN_P (object) && INSN_DELETED_P (object))
-    return 1;
+      /* At this point, X contains the new value for the operand.
+        Validate the new value vs the insn predicate.  Note that
+        asm insns will have insn_code -1 here.  */
+      if (!safe_insn_predicate (insn_code, i, x))
+       x = force_reg (insn_data[insn_code].operand[i].mode, x);
 
-  code = GET_CODE (x);
+      *recog_data.operand_loc[i] = recog_data.operand[i] = x;
+      any_change = true;
+    }
 
-  /* Check for some special cases.  */
-  switch (code)
+ verify:
+  if (any_change)
     {
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_VECTOR:
-    case CONST:
-    case SYMBOL_REF:
-    case CODE_LABEL:
-    case PC:
-    case CC0:
-    case ASM_INPUT:
-    case ADDR_VEC:
-    case ADDR_DIFF_VEC:
-    case RETURN:
-      return 1;
+      /* Propagate operand changes into the duplicates.  */
+      for (i = 0; i < recog_data.n_dups; ++i)
+       *recog_data.dup_loc[i]
+         = recog_data.operand[(unsigned)recog_data.dup_num[i]];
 
-    case SET:
-      /* We are allowed to set the virtual registers.  This means that
-        the actual register should receive the source minus the
-        appropriate offset.  This is used, for example, in the handling
-        of non-local gotos.  */
-      if ((new = instantiate_new_reg (SET_DEST (x), &offset)) != 0)
+      /* Force re-recognition of the instruction for validation.  */
+      INSN_CODE (insn) = -1;
+    }
+
+  if (asm_noperands (PATTERN (insn)) >= 0)
+    {
+      if (!check_asm_operands (PATTERN (insn)))
        {
-         rtx src = SET_SRC (x);
+         error_for_asm (insn, "impossible constraint in %<asm%>");
+         delete_insn (insn);
+       }
+    }
+  else
+    {
+      if (recog_memoized (insn) < 0)
+       fatal_insn_not_found (insn);
+    }
+}
 
-         /* We are setting the register, not using it, so the relevant
-            offset is the negative of the offset to use were we using
-            the register.  */
-         offset = - offset;
-         instantiate_virtual_regs_1 (&src, NULL_RTX, 0);
+/* Subroutine of instantiate_decls.  Given RTL representing a decl,
+   do any instantiation required.  */
 
-         /* The only valid sources here are PLUS or REG.  Just do
-            the simplest possible thing to handle them.  */
-         if (!REG_P (src) && GET_CODE (src) != PLUS)
-           {
-             instantiate_virtual_regs_lossage (object);
-             return 1;
-           }
+static void
+instantiate_decl (rtx x)
+{
+  rtx addr;
 
-         start_sequence ();
-         if (!REG_P (src))
-           temp = force_operand (src, NULL_RTX);
-         else
-           temp = src;
-         temp = force_operand (plus_constant (temp, offset), NULL_RTX);
-         seq = get_insns ();
-         end_sequence ();
+  if (x == 0)
+    return;
 
-         emit_insn_before (seq, object);
-         SET_DEST (x) = new;
+  /* If this is a CONCAT, recurse for the pieces.  */
+  if (GET_CODE (x) == CONCAT)
+    {
+      instantiate_decl (XEXP (x, 0));
+      instantiate_decl (XEXP (x, 1));
+      return;
+    }
 
-         if (! validate_change (object, &SET_SRC (x), temp, 0)
-             || ! extra_insns)
-           instantiate_virtual_regs_lossage (object);
+  /* If this is not a MEM, no need to do anything.  Similarly if the
+     address is a constant or a register that is not a virtual register.  */
+  if (!MEM_P (x))
+    return;
 
-         return 1;
-       }
+  addr = XEXP (x, 0);
+  if (CONSTANT_P (addr)
+      || (REG_P (addr)
+         && (REGNO (addr) < FIRST_VIRTUAL_REGISTER
+             || REGNO (addr) > LAST_VIRTUAL_REGISTER)))
+    return;
 
-      instantiate_virtual_regs_1 (&SET_DEST (x), object, extra_insns);
-      loc = &SET_SRC (x);
-      goto restart;
+  for_each_rtx (&XEXP (x, 0), instantiate_virtual_regs_in_rtx, NULL);
+}
 
-    case PLUS:
-      /* Handle special case of virtual register plus constant.  */
-      if (CONSTANT_P (XEXP (x, 1)))
-       {
-         rtx old, new_offset;
+/* Subroutine of instantiate_decls: Process all decls in the given
+   BLOCK node and all its subblocks.  */
 
-         /* Check for (plus (plus VIRT foo) (const_int)) first.  */
-         if (GET_CODE (XEXP (x, 0)) == PLUS)
-           {
-             if ((new = instantiate_new_reg (XEXP (XEXP (x, 0), 0), &offset)))
-               {
-                 instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
-                                             extra_insns);
-                 new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
-               }
-             else
-               {
-                 loc = &XEXP (x, 0);
-                 goto restart;
-               }
-           }
+static void
+instantiate_decls_1 (tree let)
+{
+  tree t;
 
-#ifdef POINTERS_EXTEND_UNSIGNED
-         /* If we have (plus (subreg (virtual-reg)) (const_int)), we know
-            we can commute the PLUS and SUBREG because pointers into the
-            frame are well-behaved.  */
-         else if (GET_CODE (XEXP (x, 0)) == SUBREG && GET_MODE (x) == ptr_mode
-                  && GET_CODE (XEXP (x, 1)) == CONST_INT
-                  && 0 != (new
-                           = instantiate_new_reg (SUBREG_REG (XEXP (x, 0)),
-                                                  &offset))
-                  && validate_change (object, loc,
-                                      plus_constant (gen_lowpart (ptr_mode,
-                                                                  new),
-                                                     offset
-                                                     + INTVAL (XEXP (x, 1))),
-                                      0))
-               return 1;
-#endif
-         else if ((new = instantiate_new_reg (XEXP (x, 0), &offset)) == 0)
-           {
-             /* We know the second operand is a constant.  Unless the
-                first operand is a REG (which has been already checked),
-                it needs to be checked.  */
-             if (!REG_P (XEXP (x, 0)))
-               {
-                 loc = &XEXP (x, 0);
-                 goto restart;
-               }
-             return 1;
-           }
+  for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
+    if (DECL_RTL_SET_P (t))
+      instantiate_decl (DECL_RTL (t));
 
-         new_offset = plus_constant (XEXP (x, 1), offset);
-
-         /* If the new constant is zero, try to replace the sum with just
-            the register.  */
-         if (new_offset == const0_rtx
-             && validate_change (object, loc, new, 0))
-           return 1;
-
-         /* Next try to replace the register and new offset.
-            There are two changes to validate here and we can't assume that
-            in the case of old offset equals new just changing the register
-            will yield a valid insn.  In the interests of a little efficiency,
-            however, we only call validate change once (we don't queue up the
-            changes and then call apply_change_group).  */
-
-         old = XEXP (x, 0);
-         if (offset == 0
-             ? ! validate_change (object, &XEXP (x, 0), new, 0)
-             : (XEXP (x, 0) = new,
-                ! validate_change (object, &XEXP (x, 1), new_offset, 0)))
-           {
-             if (! extra_insns)
-               {
-                 XEXP (x, 0) = old;
-                 return 0;
-               }
+  /* Process all subblocks.  */
+  for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
+    instantiate_decls_1 (t);
+}
 
-             /* Otherwise copy the new constant into a register and replace
-                constant with that register.  */
-             temp = gen_reg_rtx (Pmode);
-             XEXP (x, 0) = new;
-             if (validate_change (object, &XEXP (x, 1), temp, 0))
-               emit_insn_before (gen_move_insn (temp, new_offset), object);
-             else
-               {
-                 /* If that didn't work, replace this expression with a
-                    register containing the sum.  */
+/* Scan all decls in FNDECL (both variables and parameters) and instantiate
+   all virtual registers in their DECL_RTL's.  */
 
-                 XEXP (x, 0) = old;
-                 new = gen_rtx_PLUS (Pmode, new, new_offset);
+static void
+instantiate_decls (tree fndecl)
+{
+  tree decl;
 
-                 start_sequence ();
-                 temp = force_operand (new, NULL_RTX);
-                 seq = get_insns ();
-                 end_sequence ();
+  /* Process all parameters of the function.  */
+  for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
+    {
+      instantiate_decl (DECL_RTL (decl));
+      instantiate_decl (DECL_INCOMING_RTL (decl));
+    }
 
-                 emit_insn_before (seq, object);
-                 if (! validate_change (object, loc, temp, 0)
-                     && ! validate_replace_rtx (x, temp, object))
-                   {
-                     instantiate_virtual_regs_lossage (object);
-                     return 1;
-                   }
-               }
-           }
+  /* Now process all variables defined in the function or its subblocks.  */
+  instantiate_decls_1 (DECL_INITIAL (fndecl));
+}
 
-         return 1;
-       }
+/* Pass through the INSNS of function FNDECL and convert virtual register
+   references to hard register references.  */
 
-      /* Fall through to generic two-operand expression case.  */
-    case EXPR_LIST:
-    case CALL:
-    case COMPARE:
-    case MINUS:
-    case MULT:
-    case DIV:      case UDIV:
-    case MOD:      case UMOD:
-    case AND:      case IOR:      case XOR:
-    case ROTATERT: case ROTATE:
-    case ASHIFTRT: case LSHIFTRT: case ASHIFT:
-    case NE:       case EQ:
-    case GE:       case GT:       case GEU:    case GTU:
-    case LE:       case LT:       case LEU:    case LTU:
-      if (XEXP (x, 1) && ! CONSTANT_P (XEXP (x, 1)))
-       instantiate_virtual_regs_1 (&XEXP (x, 1), object, extra_insns);
-      loc = &XEXP (x, 0);
-      goto restart;
-
-    case MEM:
-      /* Most cases of MEM that convert to valid addresses have already been
-        handled by our scan of decls.  The only special handling we
-        need here is to make a copy of the rtx to ensure it isn't being
-        shared if we have to change it to a pseudo.
-
-        If the rtx is a simple reference to an address via a virtual register,
-        it can potentially be shared.  In such cases, first try to make it
-        a valid address, which can also be shared.  Otherwise, copy it and
-        proceed normally.
-
-        First check for common cases that need no processing.  These are
-        usually due to instantiation already being done on a previous instance
-        of a shared rtx.  */
-
-      temp = XEXP (x, 0);
-      if (CONSTANT_ADDRESS_P (temp)
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-         || temp == arg_pointer_rtx
-#endif
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-         || temp == hard_frame_pointer_rtx
-#endif
-         || temp == frame_pointer_rtx)
-       return 1;
-
-      if (GET_CODE (temp) == PLUS
-         && CONSTANT_ADDRESS_P (XEXP (temp, 1))
-         && (XEXP (temp, 0) == frame_pointer_rtx
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-             || XEXP (temp, 0) == hard_frame_pointer_rtx
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-             || XEXP (temp, 0) == arg_pointer_rtx
-#endif
-             ))
-       return 1;
-
-      if (temp == virtual_stack_vars_rtx
-         || temp == virtual_incoming_args_rtx
-         || (GET_CODE (temp) == PLUS
-             && CONSTANT_ADDRESS_P (XEXP (temp, 1))
-             && (XEXP (temp, 0) == virtual_stack_vars_rtx
-                 || XEXP (temp, 0) == virtual_incoming_args_rtx)))
-       {
-         /* This MEM may be shared.  If the substitution can be done without
-            the need to generate new pseudos, we want to do it in place
-            so all copies of the shared rtx benefit.  The call below will
-            only make substitutions if the resulting address is still
-            valid.
-
-            Note that we cannot pass X as the object in the recursive call
-            since the insn being processed may not allow all valid
-            addresses.  However, if we were not passed on object, we can
-            only modify X without copying it if X will have a valid
-            address.
-
-            ??? Also note that this can still lose if OBJECT is an insn that
-            has less restrictions on an address that some other insn.
-            In that case, we will modify the shared address.  This case
-            doesn't seem very likely, though.  One case where this could
-            happen is in the case of a USE or CLOBBER reference, but we
-            take care of that below.  */
-
-         if (instantiate_virtual_regs_1 (&XEXP (x, 0),
-                                         object ? object : x, 0))
-           return 1;
-
-         /* Otherwise make a copy and process that copy.  We copy the entire
-            RTL expression since it might be a PLUS which could also be
-            shared.  */
-         *loc = x = copy_rtx (x);
-       }
+void
+instantiate_virtual_regs (void)
+{
+  rtx insn;
 
-      /* Fall through to generic unary operation case.  */
-    case PREFETCH:
-    case SUBREG:
-    case STRICT_LOW_PART:
-    case NEG:          case NOT:
-    case PRE_DEC:      case PRE_INC:      case POST_DEC:    case POST_INC:
-    case SIGN_EXTEND:  case ZERO_EXTEND:
-    case TRUNCATE:     case FLOAT_EXTEND: case FLOAT_TRUNCATE:
-    case FLOAT:        case FIX:
-    case UNSIGNED_FIX: case UNSIGNED_FLOAT:
-    case ABS:
-    case SQRT:
-    case FFS:
-    case CLZ:          case CTZ:
-    case POPCOUNT:     case PARITY:
-      /* These case either have just one operand or we know that we need not
-        check the rest of the operands.  */
-      loc = &XEXP (x, 0);
-      goto restart;
-
-    case USE:
-    case CLOBBER:
-      /* If the operand is a MEM, see if the change is a valid MEM.  If not,
-        go ahead and make the invalid one, but do it to a copy.  For a REG,
-        just make the recursive call, since there's no chance of a problem.  */
-
-      if ((MEM_P (XEXP (x, 0))
-          && instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
-                                         0))
-         || (REG_P (XEXP (x, 0))
-             && instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0)))
-       return 1;
-
-      XEXP (x, 0) = copy_rtx (XEXP (x, 0));
-      loc = &XEXP (x, 0);
-      goto restart;
+  /* Compute the offsets to use for this function.  */
+  in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
+  var_offset = STARTING_FRAME_OFFSET;
+  dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
+  out_arg_offset = STACK_POINTER_OFFSET;
+  cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
 
-    case REG:
-      /* Try to replace with a PLUS.  If that doesn't work, compute the sum
-        in front of this insn and substitute the temporary.  */
-      if ((new = instantiate_new_reg (x, &offset)) != 0)
-       {
-         temp = plus_constant (new, offset);
-         if (!validate_change (object, loc, temp, 0))
-           {
-             if (! extra_insns)
-               return 0;
+  /* Initialize recognition, indicating that volatile is OK.  */
+  init_recog ();
 
-             start_sequence ();
-             temp = force_operand (temp, NULL_RTX);
-             seq = get_insns ();
-             end_sequence ();
+  /* Scan through all the insns, instantiating every virtual register still
+     present.  */
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      {
+       /* These patterns in the instruction stream can never be recognized.
+          Fortunately, they shouldn't contain virtual registers either.  */
+       if (GET_CODE (PATTERN (insn)) == USE
+           || GET_CODE (PATTERN (insn)) == CLOBBER
+           || GET_CODE (PATTERN (insn)) == ADDR_VEC
+           || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+           || GET_CODE (PATTERN (insn)) == ASM_INPUT)
+         continue;
 
-             emit_insn_before (seq, object);
-             if (! validate_change (object, loc, temp, 0)
-                 && ! validate_replace_rtx (x, temp, object))
-               instantiate_virtual_regs_lossage (object);
-           }
-       }
+       instantiate_virtual_regs_in_insn (insn);
 
-      return 1;
+       if (INSN_DELETED_P (insn))
+         continue;
 
-    default:
-      break;
-    }
+       for_each_rtx (&REG_NOTES (insn), instantiate_virtual_regs_in_rtx, NULL);
 
-  /* Scan all subexpressions.  */
-  fmt = GET_RTX_FORMAT (code);
-  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
-    if (*fmt == 'e')
-      {
-       if (!instantiate_virtual_regs_1 (&XEXP (x, i), object, extra_insns))
-         return 0;
+       /* Instantiate any virtual registers in CALL_INSN_FUNCTION_USAGE.  */
+       if (GET_CODE (insn) == CALL_INSN)
+         for_each_rtx (&CALL_INSN_FUNCTION_USAGE (insn),
+                       instantiate_virtual_regs_in_rtx, NULL);
       }
-    else if (*fmt == 'E')
-      for (j = 0; j < XVECLEN (x, i); j++)
-       if (! instantiate_virtual_regs_1 (&XVECEXP (x, i, j), object,
-                                         extra_insns))
-         return 0;
 
-  return 1;
+  /* Instantiate the virtual registers in the DECLs for debugging purposes.  */
+  instantiate_decls (current_function_decl);
+
+  /* Indicate that, from now on, assign_stack_local should use
+     frame_pointer_rtx.  */
+  virtuals_instantiated = 1;
 }
 \f
 /* Return 1 if EXP is an aggregate type (or a value with aggregate type).