OSDN Git Service

PR c++/44158
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 8e37b64..98ef8d9 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -643,7 +643,7 @@ fixed_base_plus_p (rtx x)
       return false;
 
     case PLUS:
-      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+      if (!CONST_INT_P (XEXP (x, 1)))
        return false;
       return fixed_base_plus_p (XEXP (x, 0));
 
@@ -686,7 +686,7 @@ approx_reg_cost_1 (rtx *xp, void *data)
        {
          if (regno < FIRST_PSEUDO_REGISTER)
            {
-             if (SMALL_REGISTER_CLASSES)
+             if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
                return 1;
              *cost_p += 2;
            }
@@ -2237,7 +2237,7 @@ hash_rtx_string (const char *ps)
   return hash;
 }
 
-/* Same as hash_rtx, but call CB on each rtx if it is not NULL.  
+/* Same as hash_rtx, but call CB on each rtx if it is not NULL.
    When the callback returns true, we continue with the new rtx.  */
 
 unsigned
@@ -2260,7 +2260,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
     return hash;
 
   /* Invoke the callback first.  */
-  if (cb != NULL 
+  if (cb != NULL
       && ((*cb) (x, mode, &newx, &newmode)))
     {
       hash += hash_rtx_cb (newx, newmode, do_not_record_p,
@@ -2304,7 +2304,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
              record = true;
            else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
              record = true;
-           else if (SMALL_REGISTER_CLASSES)
+           else if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
              record = false;
            else if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno)))
              record = false;
@@ -2370,7 +2370,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
          {
            elt = CONST_VECTOR_ELT (x, i);
            hash += hash_rtx_cb (elt, GET_MODE (elt),
-                                 do_not_record_p, hash_arg_in_memory_p, 
+                                 do_not_record_p, hash_arg_in_memory_p,
                                  have_reg_qty, cb);
          }
 
@@ -2516,7 +2516,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
              x = XEXP (x, i);
              goto repeat;
            }
-          
+
          hash += hash_rtx_cb (XEXP (x, i), VOIDmode, do_not_record_p,
                                hash_arg_in_memory_p,
                                have_reg_qty, cb);
@@ -2623,6 +2623,10 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
   if (GET_MODE (x) != GET_MODE (y))
     return 0;
 
+  /* MEMs refering to different address space are not equivalent.  */
+  if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
+    return 0;
+
   switch (code)
     {
     case PC:
@@ -2680,8 +2684,8 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
             They could e.g. be two different entities allocated into the
             same space on the stack (see e.g. PR25130).  In that case, the
             MEM addresses can be the same, even though the two MEMs are
-            absolutely not equivalent.  
-   
+            absolutely not equivalent.
+
             But because really all MEM attributes should be the same for
             equivalent MEMs, we just use the invariant that MEMs that have
             the same attributes share the same mem_attrs data structure.  */
@@ -2813,7 +2817,7 @@ cse_rtx_varies_p (const_rtx x, bool from_alias)
     }
 
   if (GET_CODE (x) == PLUS
-      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && CONST_INT_P (XEXP (x, 1))
       && REG_P (XEXP (x, 0))
       && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
     {
@@ -3423,7 +3427,7 @@ fold_rtx (rtx x, rtx insn)
                     constant through simplifications.  */
                  p = lookup (folded_arg0, SAFE_HASH (folded_arg0, mode_arg0),
                              mode_arg0);
-                 
+
                  if (p != NULL)
                    {
                      cheapest_simplification = x;
@@ -3525,7 +3529,7 @@ fold_rtx (rtx x, rtx insn)
 
          if (y != 0
              && (inner_const = equiv_constant (XEXP (y, 1))) != 0
-             && GET_CODE (inner_const) == CONST_INT
+             && CONST_INT_P (inner_const)
              && INTVAL (inner_const) != 0)
            folded_arg0 = gen_rtx_IOR (mode_arg0, XEXP (y, 0), inner_const);
        }
@@ -3595,7 +3599,7 @@ fold_rtx (rtx x, rtx insn)
             the smallest negative number this would overflow: depending
             on the mode, this would either just be the same value (and
             hence not save anything) or be incorrect.  */
-         if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT
+         if (const_arg1 != 0 && CONST_INT_P (const_arg1)
              && INTVAL (const_arg1) < 0
              /* This used to test
 
@@ -3623,10 +3627,10 @@ fold_rtx (rtx x, rtx insn)
        case MINUS:
          /* If we have (MINUS Y C), see if Y is known to be (PLUS Z C2).
             If so, produce (PLUS Z C2-C).  */
-         if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT)
+         if (const_arg1 != 0 && CONST_INT_P (const_arg1))
            {
              rtx y = lookup_as_function (XEXP (x, 0), PLUS);
-             if (y && GET_CODE (XEXP (y, 1)) == CONST_INT)
+             if (y && CONST_INT_P (XEXP (y, 1)))
                return fold_rtx (plus_constant (copy_rtx (y),
                                                -INTVAL (const_arg1)),
                                 NULL_RTX);
@@ -3647,7 +3651,7 @@ fold_rtx (rtx x, rtx insn)
             if the intermediate operation's result has only one reference.  */
 
          if (REG_P (folded_arg0)
-             && const_arg1 && GET_CODE (const_arg1) == CONST_INT)
+             && const_arg1 && CONST_INT_P (const_arg1))
            {
              int is_shift
                = (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT);
@@ -3680,7 +3684,7 @@ fold_rtx (rtx x, rtx insn)
                break;
 
              inner_const = equiv_constant (fold_rtx (XEXP (y, 1), 0));
-             if (!inner_const || GET_CODE (inner_const) != CONST_INT)
+             if (!inner_const || !CONST_INT_P (inner_const))
                break;
 
              /* Don't associate these operations if they are a PLUS with the
@@ -3734,7 +3738,7 @@ fold_rtx (rtx x, rtx insn)
                 of shifts.  */
 
              if (is_shift
-                 && GET_CODE (new_const) == CONST_INT
+                 && CONST_INT_P (new_const)
                  && INTVAL (new_const) >= GET_MODE_BITSIZE (mode))
                {
                  /* As an exception, we can turn an ASHIFTRT of this
@@ -4358,6 +4362,8 @@ cse_insn (rtx insn)
       apply_change_group ();
       fold_rtx (x, insn);
     }
+  else if (DEBUG_INSN_P (insn))
+    canon_reg (PATTERN (insn), insn);
 
   /* Store the equivalent value in SRC_EQV, if different, or if the DEST
      is a STRICT_LOW_PART.  The latter condition is necessary because SRC_EQV
@@ -4430,6 +4436,7 @@ cse_insn (rtx insn)
 
   for (i = 0; i < n_sets; i++)
     {
+      bool repeat = false;
       rtx src, dest;
       rtx src_folded;
       struct table_elt *elt = 0, *p;
@@ -4506,8 +4513,8 @@ cse_insn (rtx insn)
        {
          rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
 
-         if (GET_CODE (src) == CONST_INT
-             && GET_CODE (width) == CONST_INT
+         if (CONST_INT_P (src)
+             && CONST_INT_P (width)
              && INTVAL (width) < HOST_BITS_PER_WIDE_INT
              && (INTVAL (src) & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
            src_folded
@@ -4668,7 +4675,7 @@ cse_insn (rtx insn)
       /* See if we have a CONST_INT that is already in a register in a
         wider mode.  */
 
-      if (src_const && src_related == 0 && GET_CODE (src_const) == CONST_INT
+      if (src_const && src_related == 0 && CONST_INT_P (src_const)
          && GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
        {
@@ -4703,7 +4710,7 @@ cse_insn (rtx insn)
         value.  */
 
       if (flag_expensive_optimizations && ! src_related
-         && GET_CODE (src) == AND && GET_CODE (XEXP (src, 1)) == CONST_INT
+         && GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1))
          && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        {
          enum machine_mode tmode;
@@ -5023,6 +5030,77 @@ cse_insn (rtx insn)
                break;
            }
 
+         /* Try to optimize
+            (set (reg:M N) (const_int A))
+            (set (reg:M2 O) (const_int B))
+            (set (zero_extract:M2 (reg:M N) (const_int C) (const_int D))
+                 (reg:M2 O)).  */
+         if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
+             && CONST_INT_P (trial)
+             && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 1))
+             && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 2))
+             && REG_P (XEXP (SET_DEST (sets[i].rtl), 0))
+             && (GET_MODE_BITSIZE (GET_MODE (SET_DEST (sets[i].rtl)))
+                 >= INTVAL (XEXP (SET_DEST (sets[i].rtl), 1)))
+             && ((unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))
+                 + (unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 2))
+                 <= HOST_BITS_PER_WIDE_INT))
+           {
+             rtx dest_reg = XEXP (SET_DEST (sets[i].rtl), 0);
+             rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
+             rtx pos = XEXP (SET_DEST (sets[i].rtl), 2);
+             unsigned int dest_hash = HASH (dest_reg, GET_MODE (dest_reg));
+             struct table_elt *dest_elt
+               = lookup (dest_reg, dest_hash, GET_MODE (dest_reg));
+             rtx dest_cst = NULL;
+
+             if (dest_elt)
+               for (p = dest_elt->first_same_value; p; p = p->next_same_value)
+                 if (p->is_const && CONST_INT_P (p->exp))
+                   {
+                     dest_cst = p->exp;
+                     break;
+                   }
+             if (dest_cst)
+               {
+                 HOST_WIDE_INT val = INTVAL (dest_cst);
+                 HOST_WIDE_INT mask;
+                 unsigned int shift;
+                 if (BITS_BIG_ENDIAN)
+                   shift = GET_MODE_BITSIZE (GET_MODE (dest_reg))
+                           - INTVAL (pos) - INTVAL (width);
+                 else
+                   shift = INTVAL (pos);
+                 if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
+                   mask = ~(HOST_WIDE_INT) 0;
+                 else
+                   mask = ((HOST_WIDE_INT) 1 << INTVAL (width)) - 1;
+                 val &= ~(mask << shift);
+                 val |= (INTVAL (trial) & mask) << shift;
+                 val = trunc_int_for_mode (val, GET_MODE (dest_reg));
+                 validate_unshare_change (insn, &SET_DEST (sets[i].rtl),
+                                          dest_reg, 1);
+                 validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
+                                          GEN_INT (val), 1);
+                 if (apply_change_group ())
+                   {
+                     rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+                     if (note)
+                       {
+                         remove_note (insn, note);
+                         df_notes_rescan (insn);
+                       }
+                     src_eqv = NULL_RTX;
+                     src_eqv_elt = NULL;
+                     src_eqv_volatile = 0;
+                     src_eqv_in_memory = 0;
+                     src_eqv_hash = 0;
+                     repeat = true;
+                     break;
+                   }
+               }
+           }
+
          /* We don't normally have an insn matching (set (pc) (pc)), so
             check for this separately here.  We will delete such an
             insn below.
@@ -5098,6 +5176,13 @@ cse_insn (rtx insn)
            }
        }
 
+      /* If we changed the insn too much, handle this set from scratch.  */
+      if (repeat)
+       {
+         i--;
+         continue;
+       }
+
       src = SET_SRC (sets[i].rtl);
 
       /* In general, it is good to have a SET with SET_SRC == SET_DEST.
@@ -5226,8 +5311,8 @@ cse_insn (rtx insn)
        {
          rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
 
-         if (src_const != 0 && GET_CODE (src_const) == CONST_INT
-             && GET_CODE (width) == CONST_INT
+         if (src_const != 0 && CONST_INT_P (src_const)
+             && CONST_INT_P (width)
              && INTVAL (width) < HOST_BITS_PER_WIDE_INT
              && ! (INTVAL (src_const)
                    & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
@@ -5788,7 +5873,7 @@ cse_insn (rtx insn)
            {
              prev = PREV_INSN (prev);
            }
-         while (prev != bb_head && NOTE_P (prev));
+         while (prev != bb_head && (NOTE_P (prev) || DEBUG_INSN_P (prev)));
 
          /* Do not swap the registers around if the previous instruction
             attaches a REG_EQUIV note to REG1.
@@ -5995,7 +6080,7 @@ cse_process_notes (rtx x, rtx object, bool *changed)
    describe the path.
    It is filled with a queue of basic blocks, starting with FIRST_BB
    and following a trace through the CFG.
-  
+
    If all paths starting at FIRST_BB have been followed, or no new path
    starting at FIRST_BB can be constructed, this function returns FALSE.
    Otherwise, DATA->path is filled and the function returns TRUE indicating
@@ -6011,7 +6096,7 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
   basic_block bb;
   edge e;
   int path_size;
+
   SET_BIT (cse_visited_basic_blocks, first_bb->index);
 
   /* See if there is a previous path.  */
@@ -6172,7 +6257,7 @@ cse_prescan_path (struct cse_basic_block_data *data)
   int path_entry;
 
   /* Scan to end of each basic block in the path.  */
-  for (path_entry = 0; path_entry < path_size; path_entry++) 
+  for (path_entry = 0; path_entry < path_size; path_entry++)
     {
       basic_block bb;
       rtx insn;
@@ -6244,7 +6329,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
 
             FIXME: This is a real kludge and needs to be done some other
                    way.  */
-         if (INSN_P (insn)
+         if (NONDEBUG_INSN_P (insn)
              && num_insns++ > PARAM_VALUE (PARAM_MAX_CSE_INSNS))
            {
              flush_hash_table ();
@@ -6536,12 +6621,15 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
                       incr);
       return;
 
+    case DEBUG_INSN:
+      return;
+
     case CALL_INSN:
     case INSN:
     case JUMP_INSN:
-    /* We expect dest to be NULL_RTX here.  If the insn may trap, mark
-       this fact by setting DEST to pc_rtx.  */
-      if (flag_non_call_exceptions && may_trap_p (PATTERN (x)))
+      /* We expect dest to be NULL_RTX here.  If the insn may trap, mark
+         this fact by setting DEST to pc_rtx.  */
+      if (insn_could_throw_p (x))
        dest = pc_rtx;
       if (code == CALL_INSN)
        count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, dest, incr);
@@ -6608,6 +6696,19 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
     }
 }
 \f
+/* Return true if a register is dead.  Can be used in for_each_rtx.  */
+
+static int
+is_dead_reg (rtx *loc, void *data)
+{
+  rtx x = *loc;
+  int *counts = (int *)data;
+
+  return (REG_P (x)
+         && REGNO (x) >= FIRST_PSEUDO_REGISTER
+         && counts[REGNO (x)] == 0);
+}
+
 /* Return true if set is live.  */
 static bool
 set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
@@ -6628,9 +6729,7 @@ set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
               || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
     return false;
 #endif
-  else if (!REG_P (SET_DEST (set))
-          || REGNO (SET_DEST (set)) < FIRST_PSEUDO_REGISTER
-          || counts[REGNO (SET_DEST (set))] != 0
+  else if (!is_dead_reg (&SET_DEST (set), counts)
           || side_effects_p (SET_SRC (set)))
     return true;
   return false;
@@ -6642,7 +6741,7 @@ static bool
 insn_live_p (rtx insn, int *counts)
 {
   int i;
-  if (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+  if (insn_could_throw_p (insn))
     return true;
   else if (GET_CODE (PATTERN (insn)) == SET)
     return set_live_p (PATTERN (insn), insn, counts);
@@ -6662,6 +6761,29 @@ insn_live_p (rtx insn, int *counts)
        }
       return false;
     }
+  else if (DEBUG_INSN_P (insn))
+    {
+      rtx next;
+
+      for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
+       if (NOTE_P (next))
+         continue;
+       else if (!DEBUG_INSN_P (next))
+         return true;
+       else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
+         return false;
+
+      /* If this debug insn references a dead register, drop the
+        location expression for now.  ??? We could try to find the
+        def and see if propagation is possible.  */
+      if (for_each_rtx (&INSN_VAR_LOCATION_LOC (insn), is_dead_reg, counts))
+       {
+         INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+         df_insn_rescan (insn);
+       }
+
+      return true;
+    }
   else
     return true;
 }
@@ -6741,7 +6863,7 @@ cse_change_cc_mode (rtx *loc, void *data)
       && GET_MODE (*loc) != GET_MODE (args->newreg))
     {
       validate_change (args->insn, loc, args->newreg, 1);
-      
+
       return -1;
     }
   return 0;
@@ -6761,10 +6883,10 @@ cse_change_cc_mode_insn (rtx insn, rtx newreg)
 
   args.insn = insn;
   args.newreg = newreg;
-  
+
   for_each_rtx (&PATTERN (insn), cse_change_cc_mode, &args);
   for_each_rtx (&REG_NOTES (insn), cse_change_cc_mode, &args);
-  
+
   /* If the following assertion was triggered, there is most probably
      something wrong with the cc_modes_compatible back end function.
      CC modes only can be considered compatible if the insn - with the mode
@@ -6883,7 +7005,7 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
                                       XEXP (SET_SRC (set), 0))
                       && rtx_equal_p (XEXP (cc_src, 1),
                                       XEXP (SET_SRC (set), 1)))
-                          
+
                {
                  comp_mode = targetm.cc_modes_compatible (mode, set_mode);
                  if (comp_mode != VOIDmode
@@ -7140,8 +7262,8 @@ struct rtl_opt_pass pass_cse =
  {
   RTL_PASS,
   "cse1",                               /* name */
-  gate_handle_cse,                      /* gate */   
-  rest_of_handle_cse,                  /* execute */       
+  gate_handle_cse,                      /* gate */
+  rest_of_handle_cse,                  /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
@@ -7203,8 +7325,8 @@ struct rtl_opt_pass pass_cse2 =
  {
   RTL_PASS,
   "cse2",                               /* name */
-  gate_handle_cse2,                     /* gate */   
-  rest_of_handle_cse2,                 /* execute */       
+  gate_handle_cse2,                     /* gate */
+  rest_of_handle_cse2,                 /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
@@ -7264,8 +7386,8 @@ struct rtl_opt_pass pass_cse_after_global_opts =
  {
   RTL_PASS,
   "cse_local",                          /* name */
-  gate_handle_cse_after_global_opts,    /* gate */   
-  rest_of_handle_cse_after_global_opts, /* execute */       
+  gate_handle_cse_after_global_opts,    /* gate */
+  rest_of_handle_cse_after_global_opts, /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */