OSDN Git Service

(subst, case PLUS): Simplify (plus (comp A B) -1), etc.
[pf3gnuchains/gcc-fork.git] / gcc / integrate.c
index 424f9a6..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;
@@ -1192,7 +1184,12 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
   expand_start_bindings (0);
   if (GET_CODE (parm_insns) == NOTE
       && NOTE_LINE_NUMBER (parm_insns) > 0)
-    emit_note (NOTE_SOURCE_FILE (parm_insns), NOTE_LINE_NUMBER (parm_insns));
+    {
+      rtx note = emit_note (NOTE_SOURCE_FILE (parm_insns),
+                           NOTE_LINE_NUMBER (parm_insns));
+      if (note)
+       RTX_INTEGRATED_P (note) = 1;
+    }
 
   /* Expand the function arguments.  Do this first so that any
      new registers get created before we allocate the maps.  */
@@ -1212,7 +1209,15 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
       /* Where parameter is located in the function.  */
       rtx copy;
 
-      emit_note (DECL_SOURCE_FILE (formal), DECL_SOURCE_LINE (formal));
+      /* 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);
@@ -1224,15 +1229,26 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
       if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG
          && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)
        {
-         enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
-         rtx stack_slot = assign_stack_temp (mode, int_size_in_bytes (TREE_TYPE (arg)), 1);
+         rtx stack_slot
+           = assign_stack_temp (TYPE_MODE (TREE_TYPE (arg)),
+                                int_size_in_bytes (TREE_TYPE (arg)), 1);
 
          store_expr (arg, stack_slot, 0);
 
          arg_vals[i] = XEXP (stack_slot, 0);
        }
       else if (GET_CODE (loc) != MEM)
-       arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);
+       {
+         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;
 
@@ -1249,8 +1265,12 @@ 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))))
-       arg_vals[i] = copy_to_mode_reg (mode, arg_vals[i]);
+                 && 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]);
     }
        
   /* Allocate the structures we use to remap things.  */
@@ -1269,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,
@@ -1307,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
@@ -1358,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;
@@ -1392,7 +1425,10 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
          && ! (GET_CODE (XEXP (loc, 0)) == REG
                && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER))
        {
-         emit_note (DECL_SOURCE_FILE (formal), DECL_SOURCE_LINE (formal));
+         rtx note = emit_note (DECL_SOURCE_FILE (formal),
+                               DECL_SOURCE_LINE (formal));
+         if (note)
+           RTX_INTEGRATED_P (note) = 1;
 
          /* Compute the address in the area we reserved and store the
             value there.  */
@@ -1551,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.  */
@@ -1676,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);
@@ -1701,13 +1761,17 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
 
   expand_end_bindings (getdecls (), 1, 1);
   block = poplevel (1, 1, 0);
-  BLOCK_ABSTRACT_ORIGIN (block) = fndecl;
+  BLOCK_ABSTRACT_ORIGIN (block) = (DECL_ABSTRACT_ORIGIN (fndecl) == NULL
+                                  ? fndecl : DECL_ABSTRACT_ORIGIN (fndecl));
   poplevel (0, 0, 0);
   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
@@ -1730,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.  */
@@ -1880,7 +1948,8 @@ copy_rtx_and_substitute (orig, map)
              rounded = CEIL_ROUND (size, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
              loc = plus_constant (loc, rounded);
 #endif
-             map->reg_map[regno] = temp = force_operand (loc, NULL_RTX);
+             map->reg_map[regno] = temp
+               = force_reg (Pmode, force_operand (loc, NULL_RTX));
              map->const_equiv_map[REGNO (temp)] = loc;
              map->const_age_map[REGNO (temp)] = CONST_AGE_PARM;
 
@@ -1899,7 +1968,14 @@ copy_rtx_and_substitute (orig, map)
              start_sequence ();
              loc = assign_stack_temp (BLKmode, size, 1);
              loc = XEXP (loc, 0);
-             map->reg_map[regno] = temp = force_operand (loc, NULL_RTX);
+             /* When arguments grow downward, the virtual incoming 
+                args pointer points to the top of the argument block,
+                so the remapped location better do the same. */
+#ifdef ARGS_GROW_DOWNWARD
+             loc = plus_constant (loc, size);
+#endif
+             map->reg_map[regno] = temp
+               = force_reg (Pmode, force_operand (loc, NULL_RTX));
              map->const_equiv_map[REGNO (temp)] = loc;
              map->const_age_map[REGNO (temp)] = CONST_AGE_PARM;
 
@@ -1918,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;
            }
@@ -1947,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);
 
@@ -2112,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;
     }
 
@@ -2296,33 +2382,38 @@ subst_constants (loc, insn, map)
       }
 
     case SUBREG:
-      /* SUBREG is ordinary, but don't make nested SUBREGs and try to simplify
-        constants.  */
-      {
-       rtx inner = SUBREG_REG (x);
-       rtx new = 0;
+      /* SUBREG applied to something other than a reg
+        should be treated as ordinary, since that must
+        be a special hack and we don't know how to treat it specially.
+        Consider for example mulsidi3 in m68k.md.
+        Ordinary SUBREG of a REG needs this special treatment.  */
+      if (GET_CODE (SUBREG_REG (x)) == REG)
+       {
+         rtx inner = SUBREG_REG (x);
+         rtx new = 0;
 
-       /* We can't call subst_constants on &SUBREG_REG (x) because any
-          constant or SUBREG wouldn't be valid inside our SUBEG.  Instead,
-          see what is inside, try to form the new SUBREG and see if that is
-          valid.  We handle two cases: extracting a full word in an 
-          integral mode and extracting the low part.  */
-       subst_constants (&inner, NULL_RTX, map);
+         /* We can't call subst_constants on &SUBREG_REG (x) because any
+            constant or SUBREG wouldn't be valid inside our SUBEG.  Instead,
+            see what is inside, try to form the new SUBREG and see if that is
+            valid.  We handle two cases: extracting a full word in an 
+            integral mode and extracting the low part.  */
+         subst_constants (&inner, NULL_RTX, map);
 
-       if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
-           && GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD
-           && GET_MODE (SUBREG_REG (x)) != VOIDmode)
-         new = operand_subword (inner, SUBREG_WORD (x), 0,
-                                GET_MODE (SUBREG_REG (x)));
+         if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
+             && GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD
+             && GET_MODE (SUBREG_REG (x)) != VOIDmode)
+           new = operand_subword (inner, SUBREG_WORD (x), 0,
+                                  GET_MODE (SUBREG_REG (x)));
 
-       if (new == 0 && subreg_lowpart_p (x))
-         new = gen_lowpart_common (GET_MODE (x), inner);
+         if (new == 0 && subreg_lowpart_p (x))
+           new = gen_lowpart_common (GET_MODE (x), inner);
 
-       if (new)
-         validate_change (insn, loc, new, 1);
+         if (new)
+           validate_change (insn, loc, new, 1);
 
-       return;
-      }
+         return;
+       }
+      break;
 
     case MEM:
       subst_constants (&XEXP (x, 0), insn, map);
@@ -2372,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.  */
@@ -2498,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
@@ -2716,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.  */
@@ -2801,6 +2909,4 @@ output_inline_function (fndecl)
   rest_of_compilation (fndecl);
 
   current_function_decl = 0;
-
-  permanent_allocation ();
 }