OSDN Git Service

* expr.c (move_block_from_reg): Try using an integral mov operation first.
[pf3gnuchains/gcc-fork.git] / gcc / integrate.c
index 28707de..693304a 100644 (file)
@@ -1,5 +1,5 @@
 /* Procedure integration for GNU CC.
-   Copyright (C) 1988, 91, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1988, 91, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "integrate.h"
 #include "real.h"
+#include "except.h"
 #include "function.h"
 #include "bytecode.h"
 
@@ -90,6 +91,7 @@ function_cannot_inline_p (fndecl)
   int max_insns = INTEGRATE_THRESHOLD (fndecl);
   register int ninsns = 0;
   register tree parms;
+  rtx result;
 
   /* No inlines with varargs.  `grokdeclarator' gives a warning
      message about that if `inline' is specified.  This code
@@ -170,6 +172,24 @@ function_cannot_inline_p (fndecl)
   if (current_function_has_nonlocal_goto)
     return "function with nonlocal goto cannot be inline";
 
+  /* This is a hack, until the inliner is taught about eh regions at
+     the start of the function.  */
+  for (insn = get_insns ();
+       insn &&
+         ! (GET_CODE (insn) == NOTE
+           && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG);
+       insn = NEXT_INSN (insn))
+    {
+      if (insn && GET_CODE (insn) == NOTE
+         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+       return "function with complex parameters cannot be inline";
+    }
+
+  /* We can't inline functions that return a PARALLEL rtx.  */
+  result = DECL_RTL (DECL_RESULT (fndecl));
+  if (result && GET_CODE (result) == PARALLEL)
+    return "inline functions not supported for this return value type";
+
   return 0;
 }
 \f
@@ -309,6 +329,7 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
      the size of the incoming stack area for parameters,
      the number of bytes popped on return,
      the stack slot list,
+     the labels that are forced to exist,
      some flags that are used to restore compiler globals,
      the value of current_function_outgoing_args_size,
      the original argument vector,
@@ -335,7 +356,7 @@ finish_inline (fndecl, head)
      tree fndecl;
      rtx head;
 {
-  NEXT_INSN (head) = get_first_nonparm_insn ();
+  FIRST_FUNCTION_INSN (head) = get_first_nonparm_insn ();
   FIRST_PARM_INSN (head) = get_insns ();
   DECL_SAVED_INSNS (fndecl) = head;
   DECL_FRAME_SIZE (fndecl) = get_frame_size ();
@@ -394,7 +415,7 @@ save_for_inline_copying (fndecl)
   char *new, *new1;
 
   /* Make and emit a return-label if we have not already done so. 
-     Do this before recording the bounds on label numbers. */
+     Do this before recording the bounds on label numbers.  */
 
   if (return_label == 0)
     {
@@ -565,6 +586,15 @@ save_for_inline_copying (fndecl)
              NOTE_SOURCE_FILE (insn) = (char *) copy;
              NOTE_SOURCE_FILE (copy) = 0;
            }
+         if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
+             || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END)
+           {
+             /* We have to forward these both to match the new exception
+                region.  */
+             NOTE_BLOCK_NUMBER (copy)
+               = CODE_LABEL_NUMBER (label_map[NOTE_BLOCK_NUMBER (copy)]);
+             
+           }
          RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);
          break;
 
@@ -812,8 +842,8 @@ save_for_inline_nocopy (fndecl)
    pool.  Replace each with a CONST that has the mode of the original
    constant, contains the constant, and has RTX_INTEGRATED_P set.
    Similarly, constant pool addresses not enclosed in a MEM are replaced
-   with an ADDRESS rtx which also gives the constant, mode, and has
-   RTX_INTEGRATED_P set.  */
+   with an ADDRESS and CONST rtx which also gives the constant, its
+   mode, the mode of the address, and has RTX_INTEGRATED_P set.  */
 
 static void
 save_constants (px)
@@ -852,7 +882,9 @@ save_constants (px)
   else if (GET_CODE (x) == SYMBOL_REF
           && CONSTANT_POOL_ADDRESS_P (x))
     {
-      *px = gen_rtx (ADDRESS, get_pool_mode (x), get_pool_constant (x));
+      *px = gen_rtx (ADDRESS, GET_MODE (x),
+                    gen_rtx (CONST, get_pool_mode (x),
+                             get_pool_constant (x)));
       save_constants (&XEXP (*px, 0));
       RTX_INTEGRATED_P (*px) = 1;
     }
@@ -919,6 +951,7 @@ copy_for_inline (orig)
      rtx orig;
 {
   register rtx x = orig;
+  register rtx new;
   register int i;
   register enum rtx_code code;
   register char *format_ptr;
@@ -964,9 +997,8 @@ copy_for_inline (orig)
       /* Get constant pool entry, but access in different mode.  */
       if (RTX_INTEGRATED_P (x))
        {
-         rtx new
-           = force_const_mem (GET_MODE (SUBREG_REG (x)),
-                              copy_for_inline (XEXP (SUBREG_REG (x), 0)));
+         new = force_const_mem (GET_MODE (SUBREG_REG (x)),
+                                copy_for_inline (XEXP (SUBREG_REG (x), 0)));
 
          PUT_MODE (new, GET_MODE (x));
          return validize_mem (new);
@@ -979,8 +1011,16 @@ copy_for_inline (orig)
       if (! RTX_INTEGRATED_P (x))
        abort ();
 
-      return XEXP (force_const_mem (GET_MODE (x),
-                                   copy_for_inline (XEXP (x, 0))), 0);
+      new = force_const_mem (GET_MODE (XEXP (x, 0)),
+                            copy_for_inline (XEXP (XEXP (x, 0), 0)));
+      new = XEXP (new, 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      if (GET_MODE (new) != GET_MODE (x))
+       new = convert_memory_address (GET_MODE (x), new);
+#endif
+
+      return new;
 
     case ASM_OPERANDS:
       /* If a single asm insn contains multiple output operands
@@ -1124,7 +1164,7 @@ copy_for_inline (orig)
            {
              register int j;
 
-             XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0));
+             XVEC (x, i) = gen_rtvec_vv (XVECLEN (x, i), XVEC (x, i)->elem);
              for (j = 0; j < XVECLEN (x, i); j++)
                XVECEXP (x, i, j)
                  = copy_for_inline (XVECEXP (x, i, j));
@@ -1466,7 +1506,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
             that flag set if it is a register.
 
             Also, don't allow hard registers here; they might not be valid
-            when substituted into insns. */
+            when substituted into insns.  */
 
          if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)
              || (GET_CODE (copy) == REG && REG_USERVAR_P (loc)
@@ -1497,7 +1537,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
             that flag set if it is a register.
 
             Also, don't allow hard registers here; they might not be valid
-            when substituted into insns. */
+            when substituted into insns.  */
          rtx locreal = gen_realpart (GET_MODE (XEXP (loc, 0)), loc);
          rtx locimag = gen_imagpart (GET_MODE (XEXP (loc, 0)), loc);
          rtx copyreal = gen_realpart (GET_MODE (locreal), copy);
@@ -1649,7 +1689,21 @@ expand_inline_function (fndecl, parms, target, ignore, type,
         avoid machine mode mismatch when we substitute INLINE_TARGET.
         But TARGET is what we will return to the caller.  */
       if (arriving_mode != departing_mode)
-       reg_to_map = gen_rtx (SUBREG, arriving_mode, target, 0);
+       {
+         /* Avoid creating a paradoxical subreg wider than
+            BITS_PER_WORD, since that is illegal.  */
+         if (GET_MODE_BITSIZE (arriving_mode) > BITS_PER_WORD)
+           {
+             if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (departing_mode),
+                                         GET_MODE_BITSIZE (arriving_mode)))
+               /* Maybe could be handled by using convert_move () ?  */
+               abort ();
+             reg_to_map = gen_reg_rtx (arriving_mode);
+             target = gen_lowpart (departing_mode, reg_to_map);
+           }
+         else
+           reg_to_map = gen_rtx (SUBREG, arriving_mode, target, 0);
+       }
       else
        reg_to_map = target;
 
@@ -1660,6 +1714,8 @@ expand_inline_function (fndecl, parms, target, ignore, type,
       else
        map->reg_map[REGNO (loc)] = reg_to_map;
     }
+  else
+    abort ();
 
   /* Make new label equivalences for the labels in the called function.  */
   for (i = min_labelno; i < max_labelno; i++)
@@ -1791,7 +1847,9 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          break;
 
        case JUMP_INSN:
-         if (GET_CODE (PATTERN (insn)) == RETURN)
+         if (GET_CODE (PATTERN (insn)) == RETURN
+             || (GET_CODE (PATTERN (insn)) == PARALLEL
+                 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == RETURN))
            {
              if (local_return_label == 0)
                local_return_label = gen_label_rtx ();
@@ -1872,7 +1930,18 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
-           copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
+           {
+             copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
+             if (copy && (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
+                          || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END))
+               {
+                 rtx label = map->label_map[NOTE_BLOCK_NUMBER (copy)];
+
+                 /* We have to forward these both to match the new exception
+                    region.  */
+                 NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label);
+               }
+           }
          else
            copy = 0;
          break;
@@ -1930,6 +1999,16 @@ expand_inline_function (fndecl, parms, target, ignore, type,
   BLOCK_ABSTRACT_ORIGIN (block) = (DECL_ABSTRACT_ORIGIN (fndecl) == NULL
                                   ? fndecl : DECL_ABSTRACT_ORIGIN (fndecl));
   poplevel (0, 0, 0);
+
+  /* Must mark the line number note after inlined functions as a repeat, so
+     that the test coverage code can avoid counting the call twice.  This
+     just tells the code to ignore the immediately following line note, since
+     there already exists a copy of this note before the expanded inline call.
+     This line number note is still needed for debugging though, so we can't
+     delete it.  */
+  if (flag_test_coverage)
+    emit_note (0, NOTE_REPEATED_LINE_NUMBER);
+
   emit_line_note (input_filename, lineno);
 
   if (structure_value_addr)
@@ -2117,18 +2196,22 @@ copy_rtx_and_substitute (orig, map)
            {
              rtx loc, seq;
              int size = DECL_FRAME_SIZE (map->fndecl);
-             int rounded;
 
+#ifdef FRAME_GROWS_DOWNWARD
+             /* In this case, virtual_stack_vars_rtx points to one byte
+                higher than the top of the frame area.  So make sure we
+                allocate a big enough chunk to keep the frame pointer
+                aligned like a real one.  */
+             size = CEIL_ROUND (size, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+#endif
              start_sequence ();
              loc = assign_stack_temp (BLKmode, size, 1);
              loc = XEXP (loc, 0);
 #ifdef FRAME_GROWS_DOWNWARD
              /* In this case, virtual_stack_vars_rtx points to one byte
                 higher than the top of the frame area.  So compute the offset
-                to one byte higher than our substitute frame.
-                Keep the fake frame pointer aligned like a real one.  */
-             rounded = CEIL_ROUND (size, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
-             loc = plus_constant (loc, rounded);
+                to one byte higher than our substitute frame.  */
+             loc = plus_constant (loc, size);
 #endif
              map->reg_map[regno] = temp
                = force_reg (Pmode, force_operand (loc, NULL_RTX));
@@ -2152,7 +2235,7 @@ copy_rtx_and_substitute (orig, map)
          else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
            {
              /* Do the same for a block to contain any arguments referenced
-                in memory. */
+                in memory.  */
              rtx loc, seq;
              int size = FUNCTION_ARGS_SIZE (DECL_SAVED_INSNS (map->fndecl));
 
@@ -2161,7 +2244,7 @@ copy_rtx_and_substitute (orig, map)
              loc = XEXP (loc, 0);
              /* 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. */
+                so the remapped location better do the same.  */
 #ifdef ARGS_GROW_DOWNWARD
              loc = plus_constant (loc, size);
 #endif
@@ -2278,7 +2361,7 @@ copy_rtx_and_substitute (orig, map)
        {
          rtx constant = get_pool_constant (orig);
          if (GET_CODE (constant) == LABEL_REF)
-           return XEXP (force_const_mem (Pmode, 
+           return XEXP (force_const_mem (GET_MODE (orig),
                                          copy_rtx_and_substitute (constant,
                                                                   map)),
                         0);
@@ -2325,8 +2408,10 @@ copy_rtx_and_substitute (orig, map)
       if (! RTX_INTEGRATED_P (orig))
        abort ();
 
-      temp = force_const_mem (GET_MODE (orig),
-                             copy_rtx_and_substitute (XEXP (orig, 0), map));
+      temp
+       = force_const_mem (GET_MODE (XEXP (orig, 0)),
+                          copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0),
+                                                   map));
 
 #if 0
       /* Legitimizing the address here is incorrect.
@@ -2345,13 +2430,20 @@ copy_rtx_and_substitute (orig, map)
         will not have valid reg_map entries.  This can cause try_constants()
         to fail because assumes that all registers in the rtx have valid
         reg_map entries, and it may end up replacing one of these new
-        registers with junk. */
+        registers with junk.  */
 
       if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0)))
        temp = change_address (temp, GET_MODE (temp), XEXP (temp, 0));
 #endif
 
-      return XEXP (temp, 0);
+      temp = XEXP (temp, 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      if (GET_MODE (temp) != GET_MODE (orig))
+       temp = convert_memory_address (GET_MODE (orig), temp);
+#endif
+
+      return temp;
 
     case ASM_OPERANDS:
       /* If a single asm insn contains multiple output operands
@@ -2889,8 +2981,16 @@ restore_constants (px)
     }
   else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == ADDRESS)
     {
-      restore_constants (&XEXP (x, 0));
-      *px = XEXP (force_const_mem (GET_MODE (x), XEXP (x, 0)), 0);
+      rtx new = XEXP (force_const_mem (GET_MODE (XEXP (x, 0)),
+                                      XEXP (XEXP (x, 0), 0)),
+                     0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      if (GET_MODE (new) != GET_MODE (x))
+       new = convert_memory_address (GET_MODE (x), new);
+#endif
+
+      *px = new;
     }
   else
     {