OSDN Git Service

* pa.c (compute_movstrsi_length): Return length in bytes.
[pf3gnuchains/gcc-fork.git] / gcc / integrate.c
index 952a647..8fe1900 100644 (file)
@@ -1,5 +1,5 @@
 /* Procedure integration for GNU CC.
-   Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1991, 1993 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -68,14 +68,10 @@ static void copy_decl_rtls ();
 static tree copy_decl_tree ();
 static tree copy_decl_list ();
 
-/* Return the constant equivalent of a given rtx, or 0 if none.  */
-static rtx const_equiv ();
-
 static void integrate_parm_decls ();
 static void integrate_decl_tree ();
 
 static void subst_constants ();
-static rtx fold_out_const_cc0 ();
 \f
 /* Zero if the current function (whose FUNCTION_DECL is FNDECL)
    is safe and reasonable to integrate into other functions.
@@ -107,11 +103,6 @@ function_cannot_inline_p (fndecl)
   if (current_function_contains_functions)
     return "function with nested functions cannot be inline";
 
-  /* This restriction may be eliminated sometime soon.  But for now, don't
-     worry about remapping the static chain.  */
-  if (current_function_needs_context)
-    return "nested function cannot be inline";
-
   /* If its not even close, don't even look.  */
   if (!DECL_INLINE (fndecl) && get_max_uid () > 3 * max_insns)
     return "function too large to be inline";
@@ -1110,7 +1101,7 @@ rtx *global_const_equiv_map;
   (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
    && GET_CODE (XEXP (X, 0)) == REG                            \
    && REGNO (XEXP (X, 0)) >= FIRST_VIRTUAL_REGISTER            \
-   && REGNO (XEXP (X, 0)) < LAST_VIRTUAL_REGISTER)
+   && REGNO (XEXP (X, 0)) <= LAST_VIRTUAL_REGISTER)
 
 /* Integrate the procedure defined by FNDECL.  Note that this function
    may wind up calling itself.  Since the static variables are not
@@ -1151,6 +1142,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
   struct inline_remap *map;
   rtx cc0_insn = 0;
   rtvec arg_vector = ORIGINAL_ARG_VECTOR (header);
+  rtx static_chain_value = 0;
 
   /* Allow for equivalences of the pseudos we make for virtual fp and ap.  */
   max_regno = MAX_REGNUM (header) + 3;
@@ -1217,10 +1209,15 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
       /* Where parameter is located in the function.  */
       rtx copy;
 
-      rtx note = emit_note (DECL_SOURCE_FILE (formal),
-                           DECL_SOURCE_LINE (formal));
-      if (note)
-       RTX_INTEGRATED_P (note) = 1;
+      /* Make sure this formal has some correspondence in the users code
+       * before emitting any line notes for it.  */
+      if (DECL_SOURCE_LINE (formal))
+       {
+         rtx note = emit_note (DECL_SOURCE_FILE (formal),
+                               DECL_SOURCE_LINE (formal));
+         if (note)
+           RTX_INTEGRATED_P (note) = 1;
+       }
 
       arg_trees[i] = arg;
       loc = RTVEC_ELT (arg_vector, i);
@@ -1241,12 +1238,17 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
          arg_vals[i] = XEXP (stack_slot, 0);
        }
       else if (GET_CODE (loc) != MEM)
-       /* The mode if LOC and ARG can differ if LOC was a variable
-          that had its mode promoted via PROMOTED_MODE.  */
-       arg_vals[i] = convert_to_mode (GET_MODE (loc),
-                                      expand_expr (arg, NULL_RTX, mode,
-                                                   EXPAND_SUM),
-                                      TREE_UNSIGNED (TREE_TYPE (formal)));
+       {
+         if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg)))
+           /* The mode if LOC and ARG can differ if LOC was a variable
+              that had its mode promoted via PROMOTED_MODE.  */
+           arg_vals[i] = convert_to_mode (GET_MODE (loc),
+                                          expand_expr (arg, NULL_RTX, mode,
+                                                       EXPAND_SUM),
+                                          TREE_UNSIGNED (TREE_TYPE (formal)));
+         else
+           arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
+       }
       else
        arg_vals[i] = 0;
 
@@ -1263,7 +1265,11 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
                  && (GET_CODE (arg_vals[i]) == REG
                      || GET_CODE (arg_vals[i]) == SUBREG
                      || GET_CODE (arg_vals[i]) == MEM)
-                 && reg_overlap_mentioned_p (arg_vals[i], target))))
+                 && reg_overlap_mentioned_p (arg_vals[i], target))
+             /* ??? We must always copy a SUBREG into a REG, because it might
+                get substituted into an address, and not all ports correctly
+                handle SUBREGs in addresses.  */
+             || (GET_CODE (arg_vals[i]) == SUBREG)))
        arg_vals[i] = copy_to_mode_reg (GET_MODE (loc), arg_vals[i]);
     }
        
@@ -1283,6 +1289,8 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
   map->min_insnno = 0;
   map->max_insnno = INSN_UID (header);
 
+  map->integrating = 1;
+
   /* const_equiv_map maps pseudos in our routine to constants, so it needs to
      be large enough for all our pseudos.  This is the number we are currently
      using plus the number in the called routine, plus 15 for each arg,
@@ -1321,6 +1329,10 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
   if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE)
     current_function_uses_pic_offset_table = 1;
 
+  /* If this function needs a context, set it up.  */
+  if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_NEEDS_CONTEXT)
+    static_chain_value = lookup_static_chain (fndecl);
+
   /* Process each argument.  For each, set up things so that the function's
      reference to the argument will refer to the argument being passed.
      We only replace REG with REG here.  Any simplifications are done
@@ -1372,10 +1384,17 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
        {
          /* This is the good case where the parameter is in a register.
             If it is read-only and our argument is a constant, set up the
-            constant equivalence.  */
-         if (GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)
+            constant equivalence.
+
+            If LOC is REG_USERVAR_P, the usual case, COPY must also have
+            that flag set if it is a register.  */
+
+         if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)
+             || (GET_CODE (copy) == REG && REG_USERVAR_P (loc)
+                 && ! REG_USERVAR_P (copy)))
            {
              temp = copy_to_mode_reg (GET_MODE (loc), copy);
+             REG_USERVAR_P (temp) = REG_USERVAR_P (loc);
              if (CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy))
                {
                  map->const_equiv_map[REGNO (temp)] = copy;
@@ -1568,6 +1587,20 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
              else
                break;
            }
+         /* If this is setting the static chain pseudo, set it from
+            the value we want to give it instead.  */
+         else if (static_chain_value != 0
+                  && GET_CODE (pattern) == SET
+                  && rtx_equal_p (SET_SRC (pattern),
+                                  static_chain_incoming_rtx))
+           {
+             rtx newdest = copy_rtx_and_substitute (SET_DEST (pattern), map);
+
+             copy = emit_insn (gen_rtx (SET, VOIDmode, newdest,
+                                        static_chain_value));
+
+             static_chain_value = 0;
+           }
          else
            copy = emit_insn (copy_rtx_and_substitute (pattern, map));
          /* REG_NOTES will be copied later.  */
@@ -1693,12 +1726,22 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
       map->insn_map[INSN_UID (insn)] = copy;
     }
 
-  /* Now copy the REG_NOTES.  */
+  /* Now copy the REG_NOTES.  Increment const_age, so that only constants
+     from parameters can be substituted in.  These are the only ones that
+     are valid across the entire function.  */
+  map->const_age++;
   for (insn = insns; insn; insn = NEXT_INSN (insn))
     if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-       && map->insn_map[INSN_UID (insn)])
-      REG_NOTES (map->insn_map[INSN_UID (insn)])
-       = copy_rtx_and_substitute (REG_NOTES (insn), map);
+       && map->insn_map[INSN_UID (insn)]
+       && REG_NOTES (insn))
+      {
+       rtx tem = copy_rtx_and_substitute (REG_NOTES (insn), map);
+       /* We must also do subst_constants, in case one of our parameters
+          has const type and constant value.  */
+       subst_constants (&tem, NULL_RTX, map);
+       apply_change_group ();
+       REG_NOTES (map->insn_map[INSN_UID (insn)]) = tem;
+      }
 
   if (local_return_label)
     emit_label (local_return_label);
@@ -1724,8 +1767,11 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
   emit_line_note (input_filename, lineno);
 
   if (structure_value_addr)
-    return gen_rtx (MEM, TYPE_MODE (type),
-                   memory_address (TYPE_MODE (type), structure_value_addr));
+    {
+      target = gen_rtx (MEM, TYPE_MODE (type),
+                       memory_address (TYPE_MODE (type), structure_value_addr));
+      MEM_IN_STRUCT_P (target) = 1;
+    }
   return target;
 }
 \f
@@ -1748,6 +1794,10 @@ integrate_parm_decls (args, map, arg_vector)
       rtx new_decl_rtl
        = copy_rtx_and_substitute (RTVEC_ELT (arg_vector, i), map);
 
+      DECL_ARG_TYPE (decl) = DECL_ARG_TYPE (tail);
+      /* We really should be setting DECL_INCOMING_RTL to something reasonable
+        here, but that's going to require some more work.  */
+      /* DECL_INCOMING_RTL (decl) = ?; */
       /* These args would always appear unused, if not for this.  */
       TREE_USED (decl) = 1;
       /* Prevent warning for shadowing with these.  */
@@ -1944,7 +1994,7 @@ copy_rtx_and_substitute (orig, map)
                   reach here, so return the register unchanged.  */
                return orig;
              else if (mode != GET_MODE (map->inline_target))
-               return gen_rtx (SUBREG, mode, map->inline_target, 0);
+               return gen_lowpart (mode, map->inline_target);
              else
                return map->inline_target;
            }
@@ -1973,9 +2023,11 @@ copy_rtx_and_substitute (orig, map)
     case USE:
     case CLOBBER:
       /* USE and CLOBBER are ordinary, but we convert (use (subreg foo))
-        to (use foo).  */
+        to (use foo) if the original insn didn't have a subreg.
+        Removing the subreg distorts the VAX movstrhi pattern
+        by changing the mode of an operand.  */
       copy = copy_rtx_and_substitute (XEXP (orig, 0), map);
-      if (GET_CODE (copy) == SUBREG)
+      if (GET_CODE (copy) == SUBREG && GET_CODE (XEXP (orig, 0)) != SUBREG)
        copy = SUBREG_REG (copy);
       return gen_rtx (code, VOIDmode, copy);
 
@@ -2138,7 +2190,15 @@ copy_rtx_and_substitute (orig, map)
       XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (orig, 0), map);
       MEM_IN_STRUCT_P (copy) = MEM_IN_STRUCT_P (orig);
       MEM_VOLATILE_P (copy) = MEM_VOLATILE_P (orig);
-      RTX_UNCHANGING_P (copy) = RTX_UNCHANGING_P (orig);
+
+      /* If doing function inlining, this MEM might not be const in the
+        function that it is being inlined into, and thus may not be
+        unchanging after function inlining.  Constant pool references are
+        handled elsewhere, so this doesn't lose RTX_UNCHANGING_P bits
+        for them.  */
+      if (! map->integrating)
+       RTX_UNCHANGING_P (copy) = RTX_UNCHANGING_P (orig);
+
       return copy;
     }
 
@@ -2403,7 +2463,8 @@ subst_constants (loc, insn, map)
            && GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) <= UNITS_PER_WORD
            && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
                      <= GET_MODE_SIZE (GET_MODE (dest)))
-           && (tem = gen_lowpart_if_possible (GET_MODE (dest), src)))
+           && (tem = gen_lowpart_if_possible (GET_MODE (SUBREG_REG (dest)),
+                                              src)))
          src = tem, dest = SUBREG_REG (dest);
 
        /* If storing a recognizable value save it for later recording.  */
@@ -2529,11 +2590,29 @@ mark_stores (dest, x)
      rtx dest;
      rtx x;
 {
-  if (GET_CODE (dest) == SUBREG)
-    dest = SUBREG_REG (dest);
+  int regno = -1;
+  enum machine_mode mode;
+
+  /* DEST is always the innermost thing set, except in the case of
+     SUBREGs of hard registers.  */
 
   if (GET_CODE (dest) == REG)
-    global_const_equiv_map[REGNO (dest)] = 0;
+    regno = REGNO (dest), mode = GET_MODE (dest);
+  else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG)
+    {
+      regno = REGNO (SUBREG_REG (dest)) + SUBREG_WORD (dest);
+      mode = GET_MODE (SUBREG_REG (dest));
+    }
+
+  if (regno >= 0)
+    {
+      int last_reg = (regno >= FIRST_PSEUDO_REGISTER ? regno
+                     : regno + HARD_REGNO_NREGS (regno, mode) - 1);
+      int i;
+
+      for (i = regno; i <= last_reg; i++)
+       global_const_equiv_map[i] = 0;
+    }
 }
 \f
 /* If any CONST expressions with RTX_INTEGRATED_P are present in the rtx
@@ -2747,8 +2826,6 @@ output_inline_function (fndecl)
   rtx head = DECL_SAVED_INSNS (fndecl);
   rtx last;
 
-  temporary_allocation ();
-
   current_function_decl = fndecl;
 
   /* This call is only used to initialize global variables.  */
@@ -2832,6 +2909,4 @@ output_inline_function (fndecl)
   rest_of_compilation (fndecl);
 
   current_function_decl = 0;
-
-  permanent_allocation ();
 }