OSDN Git Service

(emit_cmp_insn): Likewise for memcmp and bcmp.
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index a7279be..b62a284 100644 (file)
@@ -367,6 +367,12 @@ struct temp_slot
   int level;
   /* Non-zero if this should survive a call to free_temp_slots.  */
   int keep;
+  /* The offset of the slot from the frame_pointer, including extra space
+     for alignment.  This info is for combine_temp_slots.  */
+  int base_offset;
+  /* The size of the slot, including extra space for alignment.  This
+     info is for combine_temp_slots.  */
+  int full_size;
 };
 
 /* List of all temporaries allocated, both available and in use.  */
@@ -418,7 +424,8 @@ struct fixup_replacement
 
 static struct temp_slot *find_temp_slot_from_address  PROTO((rtx));
 static void put_reg_into_stack PROTO((struct function *, rtx, tree,
-                                      enum machine_mode, enum machine_mode));
+                                      enum machine_mode, enum machine_mode,
+                                      int));
 static void fixup_var_refs     PROTO((rtx, enum machine_mode, int));
 static struct fixup_replacement
   *find_fixup_replacement      PROTO((struct fixup_replacement **, rtx));
@@ -841,6 +848,8 @@ assign_stack_temp (mode, size, keep)
              p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
              p->in_use = p->addr_taken = 0;
              p->size = best_p->size - rounded_size;
+             p->base_offset = best_p->base_offset + rounded_size;
+             p->full_size = best_p->full_size - rounded_size;
              p->slot = gen_rtx (MEM, BLKmode,
                                 plus_constant (XEXP (best_p->slot, 0),
                                                rounded_size));
@@ -853,6 +862,7 @@ assign_stack_temp (mode, size, keep)
                                         stack_slot_list);
 
              best_p->size = rounded_size;
+             best_p->full_size = rounded_size;
            }
        }
 
@@ -870,12 +880,22 @@ assign_stack_temp (mode, size, keep)
       /* The following slot size computation is necessary because we don't
         know the actual size of the temporary slot until assign_stack_local
         has performed all the frame alignment and size rounding for the
-        requested temporary.  Otherwise combine_temp_slots won't think that
-        adjacent slots really are adjacent.  */
+        requested temporary.  Note that extra space added for alignment
+        can be either above or below this stack slot depending on which
+        way the frame grows.  We include the extra space if and only if it
+        is above this slot.  */
 #ifdef FRAME_GROWS_DOWNWARD
       p->size = frame_offset_old - frame_offset;
 #else
-      p->size = frame_offset - frame_offset_old;
+      p->size = size;
+#endif
+      /* Now define the fields used by combine_temp_slots.  */
+#ifdef FRAME_GROWS_DOWNWARD
+      p->base_offset = frame_offset;
+      p->full_size = frame_offset_old - frame_offset;
+#else
+      p->base_offset = frame_offset_old;
+      p->full_size = frame_offset - frame_offset_old;
 #endif
       p->address = 0;
       p->next = temp_slots;
@@ -922,18 +942,18 @@ combine_temp_slots ()
            int delete_q = 0;
            if (! q->in_use && GET_MODE (q->slot) == BLKmode)
              {
-               if (rtx_equal_p (plus_constant (XEXP (p->slot, 0), p->size),
-                                XEXP (q->slot, 0)))
+               if (p->base_offset + p->full_size == q->base_offset)
                  {
                    /* Q comes after P; combine Q into P.  */
                    p->size += q->size;
+                   p->full_size += q->full_size;
                    delete_q = 1;
                  }
-               else if (rtx_equal_p (plus_constant (XEXP (q->slot, 0), q->size),
-                                     XEXP (p->slot, 0)))
+               else if (q->base_offset + q->full_size == p->base_offset)
                  {
                    /* P comes after Q; combine P into Q.  */
                    q->size += p->size;
+                   q->full_size += p->full_size;
                    delete_p = 1;
                    break;
                  }
@@ -1187,6 +1207,17 @@ pop_temp_slots ()
 
   temp_slot_level--;
 }
+
+/* Initialize temporary slots.  */
+
+void
+init_temp_slots ()
+{
+  /* We have not allocated any temporaries yet.  */
+  temp_slots = 0;
+  temp_slot_level = 0;
+  target_temp_slot_level = 0;
+}
 \f
 /* Retroactively move an auto variable from a register to a stack slot.
    This is done when an address-reference to the variable is seen.  */
@@ -1242,28 +1273,30 @@ put_var_into_stack (decl)
 
   if (GET_CODE (reg) == REG)
     put_reg_into_stack (function, reg, TREE_TYPE (decl),
-                       promoted_mode, decl_mode);
+                       promoted_mode, decl_mode, TREE_SIDE_EFFECTS (decl));
   else if (GET_CODE (reg) == CONCAT)
     {
       /* A CONCAT contains two pseudos; put them both in the stack.
         We do it so they end up consecutive.  */
       enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));
       tree part_type = TREE_TYPE (TREE_TYPE (decl));
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef FRAME_GROWS_DOWNWARD
       /* Since part 0 should have a lower address, do it second.  */
-      put_reg_into_stack (function, XEXP (reg, 1),
-                         part_type, part_mode, part_mode);
-      put_reg_into_stack (function, XEXP (reg, 0),
-                         part_type, part_mode, part_mode);
+      put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
+                         part_mode, TREE_SIDE_EFFECTS (decl));
+      put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
+                         part_mode, TREE_SIDE_EFFECTS (decl));
 #else
-      put_reg_into_stack (function, XEXP (reg, 0),
-                         part_type, part_mode, part_mode);
-      put_reg_into_stack (function, XEXP (reg, 1),
-                         part_type, part_mode, part_mode);
+      put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
+                         part_mode, TREE_SIDE_EFFECTS (decl));
+      put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
+                         part_mode, TREE_SIDE_EFFECTS (decl));
 #endif
 
       /* Change the CONCAT into a combined MEM for both parts.  */
       PUT_CODE (reg, MEM);
+      MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (XEXP (reg, 0));
+
       /* The two parts are in memory order already.
         Use the lower parts address as ours.  */
       XEXP (reg, 0) = XEXP (XEXP (reg, 0), 0);
@@ -1276,14 +1309,16 @@ put_var_into_stack (decl)
 /* Subroutine of put_var_into_stack.  This puts a single pseudo reg REG
    into the stack frame of FUNCTION (0 means the current function).
    DECL_MODE is the machine mode of the user-level data type.
-   PROMOTED_MODE is the machine mode of the register.  */
+   PROMOTED_MODE is the machine mode of the register.
+   VOLATILE_P is nonzero if this is for a "volatile" decl.  */
 
 static void
-put_reg_into_stack (function, reg, type, promoted_mode, decl_mode)
+put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p)
      struct function *function;
      rtx reg;
      tree type;
      enum machine_mode promoted_mode, decl_mode;
+     int volatile_p;
 {
   rtx new = 0;
 
@@ -1303,11 +1338,11 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode)
        new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0);
     }
 
+  PUT_MODE (reg, decl_mode);
   XEXP (reg, 0) = XEXP (new, 0);
   /* `volatil' bit means one thing for MEMs, another entirely for REGs.  */
-  REG_USERVAR_P (reg) = 0;
+  MEM_VOLATILE_P (reg) = volatile_p;
   PUT_CODE (reg, MEM);
-  PUT_MODE (reg, decl_mode);
 
   /* If this is a memory ref that contains aggregate components,
      mark it as such for cse and loop optimize.  */
@@ -1429,7 +1464,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
 
             If it has a REG_LIBCALL note, delete the REG_LIBCALL
             and REG_RETVAL notes too.  */
-         if (GET_CODE (PATTERN (insn)) == CLOBBER
+         if (GET_CODE (PATTERN (insn)) == CLOBBER
              && XEXP (PATTERN (insn), 0) == var)
            {
              if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)
@@ -1944,7 +1979,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            && (GET_CODE (SET_DEST (x)) == REG
                || (GET_CODE (SET_DEST (x)) == SUBREG
                    && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG))
-           && x == single_set (PATTERN (insn)))
+           && GET_MODE (var) == promoted_mode
+           && x == single_set (insn))
          {
            rtx pat;
 
@@ -1989,7 +2025,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            && (GET_CODE (SET_SRC (x)) == REG
                || (GET_CODE (SET_SRC (x)) == SUBREG
                    && GET_CODE (SUBREG_REG (SET_SRC (x))) == REG))
-           && x == single_set (PATTERN (insn)))
+           && GET_MODE (var) == promoted_mode
+           && x == single_set (insn))
          {
            rtx pat;
 
@@ -2035,13 +2072,14 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
              fixeddest = XEXP (fixeddest, 0);
            /* Convert (SUBREG (MEM)) to a MEM in a changed mode.  */
            if (GET_CODE (fixeddest) == SUBREG)
-             fixeddest = fixup_memory_subreg (fixeddest, insn, 0);
+             {
+               fixeddest = fixup_memory_subreg (fixeddest, insn, 0);
+               promoted_mode = GET_MODE (fixeddest);
+             }
            else
              fixeddest = fixup_stack_1 (fixeddest, insn);
 
-           temp = gen_reg_rtx (GET_MODE (SET_SRC (x)) == VOIDmode
-                               ? GET_MODE (fixeddest)
-                               : GET_MODE (SET_SRC (x)));
+           temp = gen_reg_rtx (promoted_mode);
 
            emit_insn_after (gen_move_insn (fixeddest,
                                            gen_lowpart (GET_MODE (fixeddest),
@@ -3438,7 +3476,7 @@ assign_parms (fndecl, second_time)
             ??? When MAYBE_REG_PARM_STACK_SPACE is defined, we can't tell
             whether this parameter already has a stack slot allocated,
             because an arg block exists only if current_function_args_size
-            is larger than some threshhold, and we haven't calculated that
+            is larger than some threshold, and we haven't calculated that
             yet.  So, for now, we just assume that stack slots never exist
             in this case.  */
          || REG_PARM_STACK_SPACE (fndecl) > 0
@@ -3689,7 +3727,8 @@ assign_parms (fndecl, second_time)
                   && FUNCTION_ARG_CALLEE_COPIES (args_so_far,
                                                  TYPE_MODE (DECL_ARG_TYPE (parm)),
                                                  DECL_ARG_TYPE (parm),
-                                                 ! last_named))
+                                                 ! last_named)
+                  && ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
            {
              rtx copy;
              tree type = DECL_ARG_TYPE (parm);
@@ -4506,33 +4545,34 @@ round_trampoline_addr (tramp)
    duplicate portions of the RTL code.  Call identify_blocks before
    changing the RTL, and call reorder_blocks after.  */
 
-/* Put all this function's BLOCK nodes into a vector, and return it.
+/* Put all this function's BLOCK nodes including those that are chained
+   onto the first block into a vector, and return it.
    Also store in each NOTE for the beginning or end of a block
    the index of that block in the vector.
-   The arguments are TOP_BLOCK, the top-level block of the function,
+   The arguments are BLOCK, the chain of top-level blocks of the function,
    and INSNS, the insn chain of the function.  */
 
 tree *
-identify_blocks (top_block, insns)
-     tree top_block;
+identify_blocks (block, insns)
+     tree block;
      rtx insns;
 {
   int n_blocks;
   tree *block_vector;
   int *block_stack;
   int depth = 0;
-  int next_block_number = 0;
-  int current_block_number = 0;
+  int next_block_number = 1;
+  int current_block_number = 1;
   rtx insn;
 
-  if (top_block == 0)
+  if (block == 0)
     return 0;
 
-  n_blocks = all_blocks (top_block, 0);
+  n_blocks = all_blocks (block, 0);
   block_vector = (tree *) xmalloc (n_blocks * sizeof (tree));
   block_stack = (int *) alloca (n_blocks * sizeof (int));
 
-  all_blocks (top_block, block_vector);
+  all_blocks (block, block_vector);
 
   for (insn = insns; insn; insn = NEXT_INSN (insn))
     if (GET_CODE (insn) == NOTE)
@@ -4550,6 +4590,9 @@ identify_blocks (top_block, insns)
          }
       }
 
+  if (n_blocks != next_block_number)
+    abort ();
+
   return block_vector;
 }
 
@@ -4560,19 +4603,20 @@ identify_blocks (top_block, insns)
    Returns the current top-level block.  */
 
 tree
-reorder_blocks (block_vector, top_block, insns)
+reorder_blocks (block_vector, block, insns)
      tree *block_vector;
-     tree top_block;
+     tree block;
      rtx insns;
 {
-  tree current_block = top_block;
+  tree current_block = block;
   rtx insn;
 
   if (block_vector == 0)
-    return top_block;
+    return block;
 
-  /* Prune the old tree away, so that it doesn't get in the way.  */
+  /* Prune the old trees away, so that it doesn't get in the way.  */
   BLOCK_SUBBLOCKS (current_block) = 0;
+  BLOCK_CHAIN (current_block) = 0;
 
   for (insn = insns; insn; insn = NEXT_INSN (insn))
     if (GET_CODE (insn) == NOTE)
@@ -4600,6 +4644,8 @@ reorder_blocks (block_vector, top_block, insns)
          }
       }
 
+  BLOCK_SUBBLOCKS (current_block)
+    = blocks_nreverse (BLOCK_SUBBLOCKS (current_block));
   return current_block;
 }
 
@@ -4620,26 +4666,32 @@ blocks_nreverse (t)
   return prev;
 }
 
-/* Count the subblocks of BLOCK, and list them all into the vector VECTOR.
-   Also clear TREE_ASM_WRITTEN in all blocks.  */
+/* Count the subblocks of the list starting with BLOCK, and list them
+   all into the vector VECTOR.  Also clear TREE_ASM_WRITTEN in all
+   blocks.  */
 
 static int
 all_blocks (block, vector)
      tree block;
      tree *vector;
 {
-  int n_blocks = 1;
-  tree subblocks; 
+  int n_blocks = 0;
 
-  TREE_ASM_WRITTEN (block) = 0;
-  /* Record this block.  */
-  if (vector)
-    vector[0] = block;
+  while (block)
+    {
+      TREE_ASM_WRITTEN (block) = 0;
 
-  /* Record the subblocks, and their subblocks.  */
-  for (subblocks = BLOCK_SUBBLOCKS (block);
-       subblocks; subblocks = BLOCK_CHAIN (subblocks))
-    n_blocks += all_blocks (subblocks, vector ? vector + n_blocks : 0);
+      /* Record this block.  */
+      if (vector)
+       vector[n_blocks] = block;
+
+      ++n_blocks;
+      
+      /* Record the subblocks, and their subblocks...  */
+      n_blocks += all_blocks (BLOCK_SUBBLOCKS (block),
+                             vector ? vector + n_blocks : 0);
+      block = BLOCK_CHAIN (block);
+    }
 
   return n_blocks;
 }
@@ -4787,10 +4839,8 @@ init_function_start (subr, filename, line)
   /* No RTL_EXPRs in this function yet.  */
   rtl_expr_chain = 0;
 
-  /* We have not allocated any temporaries yet.  */
-  temp_slots = 0;
-  temp_slot_level = 0;
-  target_temp_slot_level = 0;
+  /* Set up to allocate temporaries.  */
+  init_temp_slots ();
 
   /* Within function body, compute a type's size as soon it is laid out.  */
   immediate_size_expand++;
@@ -4803,9 +4853,6 @@ init_function_start (subr, filename, line)
 
   current_function_outgoing_args_size = 0;
 
-  /* Initialize the insn lengths.  */
-  init_insn_lengths ();
-
   /* Prevent ever trying to delete the first instruction of a function.
      Also tell final how to output a linenum before the function prologue.  */
   emit_line_note (filename, line);