OSDN Git Service

PR target/36684
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 77889cf..22c7979 100644 (file)
@@ -66,6 +66,16 @@ enum machine_mode word_mode; /* Mode whose width is BITS_PER_WORD.  */
 enum machine_mode double_mode; /* Mode whose width is DOUBLE_TYPE_SIZE.  */
 enum machine_mode ptr_mode;    /* Mode whose width is POINTER_SIZE.  */
 
+/* Datastructures maintained for currently processed function in RTL form.  */
+
+struct rtl_data x_rtl;
+
+/* Indexed by pseudo register number, gives the rtx for that pseudo.
+   Allocated in parallel with regno_pointer_align.  
+   FIXME: We could put it into emit_status struct, but gengtype is not able to deal
+   with length attribute nested in top level structures.  */
+
+rtx * regno_reg_rtx;
 
 /* This is *not* reset after each function.  It gives each CODE_LABEL
    in the entire compilation a unique label number.  */
@@ -162,11 +172,11 @@ static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
      htab_t const_fixed_htab;
 
-#define first_insn (cfun->emit->x_first_insn)
-#define last_insn (cfun->emit->x_last_insn)
-#define cur_insn_uid (cfun->emit->x_cur_insn_uid)
-#define last_location (cfun->emit->x_last_location)
-#define first_label_num (cfun->emit->x_first_label_num)
+#define first_insn (crtl->emit.x_first_insn)
+#define last_insn (crtl->emit.x_last_insn)
+#define cur_insn_uid (crtl->emit.x_cur_insn_uid)
+#define last_location (crtl->emit.x_last_location)
+#define first_label_num (crtl->emit.x_first_label_num)
 
 static rtx make_call_insn_raw (rtx);
 static rtx change_address_1 (rtx, enum machine_mode, rtx, int);
@@ -339,7 +349,7 @@ get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size,
       memcpy (*slot, &attrs, sizeof (mem_attrs));
     }
 
-  return *slot;
+  return (mem_attrs *) *slot;
 }
 
 /* Returns a hash code for X (which is a really a reg_attrs *).  */
@@ -388,7 +398,7 @@ get_reg_attrs (tree decl, int offset)
       memcpy (*slot, &attrs, sizeof (reg_attrs));
     }
 
-  return *slot;
+  return (reg_attrs *) *slot;
 }
 
 
@@ -668,7 +678,7 @@ gen_tmp_stack_mem (enum machine_mode mode, rtx addr)
 {
   rtx mem = gen_rtx_MEM (mode, addr);
   MEM_NOTRAP_P (mem) = 1;
-  if (!current_function_calls_alloca)
+  if (!cfun->calls_alloca)
     set_mem_alias_set (mem, get_frame_alias_set ());
   return mem;
 }
@@ -802,7 +812,7 @@ gen_rtvec (int n, ...)
   if (n == 0)
     return NULL_RTVEC;         /* Don't allocate an empty rtvec...     */
 
-  vector = alloca (n * sizeof (rtx));
+  vector = XALLOCAVEC (rtx, n);
 
   for (i = 0; i < n; i++)
     vector[i] = va_arg (p, rtx);
@@ -853,7 +863,6 @@ byte_lowpart_offset (enum machine_mode outer_mode,
 rtx
 gen_reg_rtx (enum machine_mode mode)
 {
-  struct function *f = cfun;
   rtx val;
 
   gcc_assert (can_create_pseudo_p ());
@@ -878,22 +887,21 @@ gen_reg_rtx (enum machine_mode mode)
   /* Make sure regno_pointer_align, and regno_reg_rtx are large
      enough to have an element for this pseudo reg number.  */
 
-  if (reg_rtx_no == f->emit->regno_pointer_align_length)
+  if (reg_rtx_no == crtl->emit.regno_pointer_align_length)
     {
-      int old_size = f->emit->regno_pointer_align_length;
+      int old_size = crtl->emit.regno_pointer_align_length;
       char *new;
       rtx *new1;
 
-      new = ggc_realloc (f->emit->regno_pointer_align, old_size * 2);
+      new = XRESIZEVEC (char, crtl->emit.regno_pointer_align, old_size * 2);
       memset (new + old_size, 0, old_size);
-      f->emit->regno_pointer_align = (unsigned char *) new;
+      crtl->emit.regno_pointer_align = (unsigned char *) new;
 
-      new1 = ggc_realloc (f->emit->x_regno_reg_rtx,
-                         old_size * 2 * sizeof (rtx));
+      new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, old_size * 2);
       memset (new1 + old_size, 0, old_size * sizeof (rtx));
       regno_reg_rtx = new1;
 
-      f->emit->regno_pointer_align_length = old_size * 2;
+      crtl->emit.regno_pointer_align_length = old_size * 2;
     }
 
   val = gen_raw_REG (mode, reg_rtx_no);
@@ -954,12 +962,39 @@ set_reg_attrs_from_value (rtx reg, rtx x)
 {
   int offset;
 
+  /* Hard registers can be reused for multiple purposes within the same
+     function, so setting REG_ATTRS, REG_POINTER and REG_POINTER_ALIGN
+     on them is wrong.  */
+  if (HARD_REGISTER_P (reg))
+    return;
+
   offset = byte_lowpart_offset (GET_MODE (reg), GET_MODE (x));
-  if (MEM_P (x) && MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT)
-    REG_ATTRS (reg)
-      = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
-  if (REG_P (x) && REG_ATTRS (x))
-    update_reg_offset (reg, x, offset);
+  if (MEM_P (x))
+    {
+      if (MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT)
+       REG_ATTRS (reg)
+         = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
+      if (MEM_POINTER (x))
+       mark_reg_pointer (reg, MEM_ALIGN (x));
+    }
+  else if (REG_P (x))
+    {
+      if (REG_ATTRS (x))
+       update_reg_offset (reg, x, offset);
+      if (REG_POINTER (x))
+       mark_reg_pointer (reg, REGNO_POINTER_ALIGN (REGNO (x)));
+    }
+}
+
+/* Generate a REG rtx for a new pseudo register, copying the mode
+   and attributes from X.  */
+
+rtx
+gen_reg_rtx_and_attrs (rtx x)
+{
+  rtx reg = gen_reg_rtx (GET_MODE (x));
+  set_reg_attrs_from_value (reg, x);
+  return reg;
 }
 
 /* Set the register attributes for registers contained in PARM_RTX.
@@ -1111,7 +1146,7 @@ get_first_label_num (void)
 
 /* If the rtx for label was created during the expansion of a nested
    function, then first_label_num won't include this label number.
-   Fix this now so that array indicies work later.  */
+   Fix this now so that array indices work later.  */
 
 void
 maybe_set_first_label_num (rtx x)
@@ -1401,8 +1436,7 @@ component_ref_for_mem_expr (tree ref)
     {
       /* Now remove any conversions: they don't change what the underlying
         object is.  Likewise for SAVE_EXPR.  */
-      while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR
-            || TREE_CODE (inner) == NON_LVALUE_EXPR
+      while (CONVERT_EXPR_P (inner)
             || TREE_CODE (inner) == VIEW_CONVERT_EXPR
             || TREE_CODE (inner) == SAVE_EXPR)
        inner = TREE_OPERAND (inner, 0);
@@ -1532,8 +1566,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
 
       /* Now remove any conversions: they don't change what the underlying
         object is.  Likewise for SAVE_EXPR.  */
-      while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
-            || TREE_CODE (t) == NON_LVALUE_EXPR
+      while (CONVERT_EXPR_P (t)
             || TREE_CODE (t) == VIEW_CONVERT_EXPR
             || TREE_CODE (t) == SAVE_EXPR)
        t = TREE_OPERAND (t, 0);
@@ -1595,7 +1628,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
        }
 
       /* If this is a field reference and not a bit-field, record it.  */
-      /* ??? There is some information that can be gleened from bit-fields,
+      /* ??? There is some information that can be gleaned from bit-fields,
         such as the word offset in the structure that might be modified.
         But skip it for now.  */
       else if (TREE_CODE (t) == COMPONENT_REF
@@ -1698,7 +1731,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
 
   if (TREE_CODE (t) == ALIGN_INDIRECT_REF)
     {
-      /* Force EXPR and OFFSE to NULL, since we don't know exactly what
+      /* Force EXPR and OFFSET to NULL, since we don't know exactly what
         we're overlapping.  */
       offset = NULL;
       expr = NULL;
@@ -1932,7 +1965,7 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset,
 
 /* Return a memory reference like MEMREF, but with its mode changed
    to MODE and its address changed to ADDR, which is assumed to be
-   MEMREF offseted by OFFSET bytes.  If VALIDATE is
+   MEMREF offset by OFFSET bytes.  If VALIDATE is
    nonzero, the memory address is forced to be valid.  */
 
 rtx
@@ -3011,9 +3044,8 @@ link_cc0_insns (rtx insn)
   if (NONJUMP_INSN_P (user) && GET_CODE (PATTERN (user)) == SEQUENCE)
     user = XVECEXP (PATTERN (user), 0, 0);
 
-  REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn,
-                                       REG_NOTES (user));
-  REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn));
+  add_reg_note (user, REG_CC_SETTER, insn);
+  add_reg_note (insn, REG_CC_USER, user);
 }
 
 /* Return the next insn that uses CC0 after INSN, which is assumed to
@@ -3068,7 +3100,7 @@ static int
 find_auto_inc (rtx *xp, void *data)
 {
   rtx x = *xp;
-  rtx reg = data;
+  rtx reg = (rtx) data;
 
   if (GET_RTX_CLASS (GET_CODE (x)) != RTX_AUTOINC)
     return 0;
@@ -3132,8 +3164,7 @@ try_split (rtx pat, rtx trial, int last)
   rtx before = PREV_INSN (trial);
   rtx after = NEXT_INSN (trial);
   int has_barrier = 0;
-  rtx tem, note_retval, note_libcall;
-  rtx note, seq;
+  rtx note, seq, tem;
   int probability;
   rtx insn_last, insn;
   int njumps = 0;
@@ -3191,10 +3222,7 @@ try_split (rtx pat, rtx trial, int last)
                 is responsible for this step using
                 split_branch_probability variable.  */
              gcc_assert (njumps == 1);
-             REG_NOTES (insn)
-               = gen_rtx_EXPR_LIST (REG_BR_PROB,
-                                    GEN_INT (probability),
-                                    REG_NOTES (insn));
+             add_reg_note (insn, REG_BR_PROB, GEN_INT (probability));
            }
        }
     }
@@ -3225,10 +3253,7 @@ try_split (rtx pat, rtx trial, int last)
              if (CALL_P (insn)
                  || (flag_non_call_exceptions && INSN_P (insn)
                      && may_trap_p (PATTERN (insn))))
-               REG_NOTES (insn)
-                 = gen_rtx_EXPR_LIST (REG_EH_REGION,
-                                      XEXP (note, 0),
-                                      REG_NOTES (insn));
+               add_reg_note (insn, REG_EH_REGION, XEXP (note, 0));
            }
          break;
 
@@ -3237,10 +3262,7 @@ try_split (rtx pat, rtx trial, int last)
          for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
            {
              if (CALL_P (insn))
-               REG_NOTES (insn)
-                 = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
-                                      XEXP (note, 0),
-                                      REG_NOTES (insn));
+               add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
            }
          break;
 
@@ -3248,10 +3270,7 @@ try_split (rtx pat, rtx trial, int last)
          for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
            {
              if (JUMP_P (insn))
-               REG_NOTES (insn)
-                 = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
-                                      XEXP (note, 0),
-                                      REG_NOTES (insn));
+               add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
            }
          break;
 
@@ -3262,36 +3281,11 @@ try_split (rtx pat, rtx trial, int last)
              rtx reg = XEXP (note, 0);
              if (!FIND_REG_INC_NOTE (insn, reg)
                  && for_each_rtx (&PATTERN (insn), find_auto_inc, reg) > 0)
-               REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, reg,
-                                                     REG_NOTES (insn));
+               add_reg_note (insn, REG_INC, reg);
            }
          break;
 #endif
 
-       case REG_LIBCALL:
-         /* Relink the insns with REG_LIBCALL note and with REG_RETVAL note 
-            after split.  */
-         REG_NOTES (insn_last) 
-           = gen_rtx_INSN_LIST (REG_LIBCALL,
-                                XEXP (note, 0),
-                                REG_NOTES (insn_last)); 
-
-         note_retval = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL);
-         XEXP (note_retval, 0) = insn_last;
-         break;
-
-       case REG_RETVAL:
-         /* Relink the insns with REG_LIBCALL note and with REG_RETVAL note
-            after split.  */
-         REG_NOTES (insn_last) 
-           = gen_rtx_INSN_LIST (REG_RETVAL,
-                                XEXP (note, 0),
-                                REG_NOTES (insn_last)); 
-
-         note_libcall = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL);
-         XEXP (note_libcall, 0) = insn_last;
-         break;
-
        default:
          break;
        }
@@ -4520,6 +4514,62 @@ emit_note (enum insn_note kind)
   return note;
 }
 
+/* Emit a clobber of lvalue X.  */
+
+rtx
+emit_clobber (rtx x)
+{
+  /* CONCATs should not appear in the insn stream.  */
+  if (GET_CODE (x) == CONCAT)
+    {
+      emit_clobber (XEXP (x, 0));
+      return emit_clobber (XEXP (x, 1));
+    }
+  return emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+}
+
+/* Return a sequence of insns to clobber lvalue X.  */
+
+rtx
+gen_clobber (rtx x)
+{
+  rtx seq;
+
+  start_sequence ();
+  emit_clobber (x);
+  seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
+
+/* Emit a use of rvalue X.  */
+
+rtx
+emit_use (rtx x)
+{
+  /* CONCATs should not appear in the insn stream.  */
+  if (GET_CODE (x) == CONCAT)
+    {
+      emit_use (XEXP (x, 0));
+      return emit_use (XEXP (x, 1));
+    }
+  return emit_insn (gen_rtx_USE (VOIDmode, x));
+}
+
+/* Return a sequence of insns to use rvalue X.  */
+
+rtx
+gen_use (rtx x)
+{
+  rtx seq;
+
+  start_sequence ();
+  emit_use (x);
+  seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
+
 /* Cause next statement to emit a line note even if the line number
    has not changed.  */
 
@@ -4536,7 +4586,6 @@ rtx
 set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum)
 {
   rtx note = find_reg_note (insn, kind, NULL_RTX);
-  rtx new_note = NULL;
 
   switch (kind)
     {
@@ -4574,8 +4623,7 @@ set_unique_reg_note (rtx insn, enum reg_note kind, rtx datum)
       break;
     }
 
-  new_note = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
-  REG_NOTES (insn) = new_note;
+  add_reg_note (insn, kind, datum);
 
   switch (kind)
     {
@@ -4676,7 +4724,7 @@ start_sequence (void)
       free_sequence_stack = tem->next;
     }
   else
-    tem = ggc_alloc (sizeof (struct sequence_stack));
+    tem = GGC_NEW (struct sequence_stack);
 
   tem->next = seq_stack;
   tem->first = first_insn;
@@ -4789,14 +4837,13 @@ in_sequence_p (void)
 /* Put the various virtual registers into REGNO_REG_RTX.  */
 
 static void
-init_virtual_regs (struct emit_status *es)
+init_virtual_regs (void)
 {
-  rtx *ptr = es->x_regno_reg_rtx;
-  ptr[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
-  ptr[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
-  ptr[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
-  ptr[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
-  ptr[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
+  regno_reg_rtx[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
+  regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
+  regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
+  regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
+  regno_reg_rtx[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
 }
 
 \f
@@ -4970,9 +5017,6 @@ copy_insn (rtx insn)
 void
 init_emit (void)
 {
-  struct function *f = cfun;
-
-  f->emit = ggc_alloc (sizeof (struct emit_status));
   first_insn = NULL;
   last_insn = NULL;
   cur_insn_uid = 1;
@@ -4983,14 +5027,13 @@ init_emit (void)
 
   /* Init the tables that describe all the pseudo regs.  */
 
-  f->emit->regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
+  crtl->emit.regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
 
-  f->emit->regno_pointer_align
-    = ggc_alloc_cleared (f->emit->regno_pointer_align_length
-                        * sizeof (unsigned char));
+  crtl->emit.regno_pointer_align
+    = XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
 
   regno_reg_rtx
-    = ggc_alloc (f->emit->regno_pointer_align_length * sizeof (rtx));
+    = GGC_NEWVEC (rtx, crtl->emit.regno_pointer_align_length);
 
   /* Put copies of all the hard registers into regno_reg_rtx.  */
   memcpy (regno_reg_rtx,
@@ -4998,7 +5041,7 @@ init_emit (void)
          FIRST_PSEUDO_REGISTER * sizeof (rtx));
 
   /* Put copies of all the virtual register rtx into regno_reg_rtx.  */
-  init_virtual_regs (f->emit);
+  init_virtual_regs ();
 
   /* Indicate that the virtual registers and stack locations are
      all pointers.  */
@@ -5421,8 +5464,7 @@ init_emit_once (int line_numbers)
 rtx
 emit_copy_of_insn_after (rtx insn, rtx after)
 {
-  rtx new;
-  rtx note1, note2, link;
+  rtx new, link;
 
   switch (GET_CODE (insn))
     {
@@ -5440,7 +5482,10 @@ emit_copy_of_insn_after (rtx insn, rtx after)
        CALL_INSN_FUNCTION_USAGE (new)
          = copy_insn (CALL_INSN_FUNCTION_USAGE (insn));
       SIBLING_CALL_P (new) = SIBLING_CALL_P (insn);
-      CONST_OR_PURE_CALL_P (new) = CONST_OR_PURE_CALL_P (insn);
+      RTL_CONST_CALL_P (new) = RTL_CONST_CALL_P (insn);
+      RTL_PURE_CALL_P (new) = RTL_PURE_CALL_P (insn);
+      RTL_LOOPING_CONST_OR_PURE_CALL_P (new) 
+       = RTL_LOOPING_CONST_OR_PURE_CALL_P (insn);
       break;
 
     default:
@@ -5464,24 +5509,12 @@ emit_copy_of_insn_after (rtx insn, rtx after)
     if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND)
       {
        if (GET_CODE (link) == EXPR_LIST)
-         REG_NOTES (new)
-               = gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
-                 copy_insn_1 (XEXP (link, 0)),  REG_NOTES (new));
+         add_reg_note (new, REG_NOTE_KIND (link),
+                       copy_insn_1 (XEXP (link, 0)));
        else
-         REG_NOTES (new)
-              = gen_rtx_INSN_LIST (REG_NOTE_KIND (link),
-                XEXP (link, 0),  REG_NOTES (new));
+         add_reg_note (new, REG_NOTE_KIND (link), XEXP (link, 0));
       }
 
-  /* Fix the libcall sequences.  */
-  if ((note1 = find_reg_note (new, REG_RETVAL, NULL_RTX)) != NULL)
-    {
-      rtx p = new;
-      while ((note2 = find_reg_note (p, REG_LIBCALL, NULL_RTX)) == NULL)
-       p = PREV_INSN (p);
-      XEXP (note1, 0) = p;
-      XEXP (note2, 0) = new;
-    }
   INSN_CODE (new) = INSN_CODE (insn);
   return new;
 }