OSDN Git Service

* config/mcore/mcore.h (PREDICATE_CODES): Add SYMBOL_REF and
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-loop-ivopts.c
index 84965b9..7853d69 100644 (file)
@@ -647,7 +647,7 @@ struct nfe_cache_elt
   /* The edge for that the number of iterations is cached.  */
   edge exit;
 
-  /* True if the # of iterations was succesfully determined.  */
+  /* True if the # of iterations was successfully determined.  */
   bool valid_p;
 
   /* Description of # of iterations.  */
@@ -730,8 +730,8 @@ tree_ssa_iv_optimize_init (struct loops *loops, struct ivopts_data *data)
   data->version_info_size = 2 * num_ssa_names;
   data->version_info = xcalloc (data->version_info_size,
                                sizeof (struct version_info));
-  data->relevant = BITMAP_XMALLOC ();
-  data->important_candidates = BITMAP_XMALLOC ();
+  data->relevant = BITMAP_ALLOC (NULL);
+  data->important_candidates = BITMAP_ALLOC (NULL);
   data->max_inv_id = 0;
   data->niters = htab_create (10, nfe_hash, nfe_eq, free);
 
@@ -766,10 +766,10 @@ determine_base_object (tree expr)
       base = get_base_address (obj);
 
       if (!base)
-       return fold_convert (ptr_type_node, expr);
+       return expr;
 
       if (TREE_CODE (base) == INDIRECT_REF)
-       return fold_convert (ptr_type_node, TREE_OPERAND (base, 0));
+       return determine_base_object (TREE_OPERAND (base, 0));
 
       return fold (build1 (ADDR_EXPR, ptr_type_node, base));
 
@@ -788,6 +788,10 @@ determine_base_object (tree expr)
 
       return fold (build (code, ptr_type_node, op0, op1));
 
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+      return determine_base_object (TREE_OPERAND (expr, 0));
+
     default:
       return fold_convert (ptr_type_node, expr);
     }
@@ -1148,7 +1152,7 @@ record_use (struct ivopts_data *data, tree *use_p, struct iv *iv,
   use->iv = iv;
   use->stmt = stmt;
   use->op_p = use_p;
-  use->related_cands = BITMAP_XMALLOC ();
+  use->related_cands = BITMAP_ALLOC (NULL);
 
   /* To avoid showing ssa name in the dumps, if it was not reset by the
      caller.  */
@@ -1737,6 +1741,105 @@ find_interesting_uses (struct ivopts_data *data)
   free (body);
 }
 
+/* Strips constant offsets from EXPR and stores them to OFFSET.  If INSIDE_ADDR
+   is true, assume we are inside an address.  */
+
+static tree
+strip_offset (tree expr, bool inside_addr, unsigned HOST_WIDE_INT *offset)
+{
+  tree op0 = NULL_TREE, op1 = NULL_TREE, step;
+  enum tree_code code;
+  tree type, orig_type = TREE_TYPE (expr);
+  unsigned HOST_WIDE_INT off0, off1, st;
+  tree orig_expr = expr;
+
+  STRIP_NOPS (expr);
+  type = TREE_TYPE (expr);
+  code = TREE_CODE (expr);
+  *offset = 0;
+
+  switch (code)
+    {
+    case INTEGER_CST:
+      if (!cst_and_fits_in_hwi (expr)
+         || zero_p (expr))
+       return orig_expr;
+
+      *offset = int_cst_value (expr);
+      return build_int_cst_type (orig_type, 0);
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      op0 = TREE_OPERAND (expr, 0);
+      op1 = TREE_OPERAND (expr, 1);
+
+      op0 = strip_offset (op0, false, &off0);
+      op1 = strip_offset (op1, false, &off1);
+
+      *offset = (code == PLUS_EXPR ? off0 + off1 : off0 - off1);
+      if (op0 == TREE_OPERAND (expr, 0)
+         && op1 == TREE_OPERAND (expr, 1))
+       return orig_expr;
+
+      if (zero_p (op1))
+       expr = op0;
+      else if (zero_p (op0))
+       {
+         if (code == PLUS_EXPR)
+           expr = op1;
+         else
+           expr = build1 (NEGATE_EXPR, type, op1);
+       }
+      else
+       expr = build2 (code, type, op0, op1);
+
+      return fold_convert (orig_type, expr);
+
+    case ARRAY_REF:
+      if (!inside_addr)
+       return orig_expr;
+
+      step = array_ref_element_size (expr);
+      if (!cst_and_fits_in_hwi (step))
+       break;
+
+      st = int_cst_value (step);
+      op1 = TREE_OPERAND (expr, 1);
+      op1 = strip_offset (op1, false, &off1);
+      *offset = off1 * st;
+      break;
+
+    case COMPONENT_REF:
+      if (!inside_addr)
+       return orig_expr;
+      break;
+
+    case ADDR_EXPR:
+      inside_addr = true;
+      break;
+
+    default:
+      return orig_expr;
+    }
+
+  /* Default handling of expressions for that we want to recurse into
+     the first operand.  */
+  op0 = TREE_OPERAND (expr, 0);
+  op0 = strip_offset (op0, inside_addr, &off0);
+  *offset += off0;
+
+  if (op0 == TREE_OPERAND (expr, 0)
+      && (!op1 || op1 == TREE_OPERAND (expr, 1)))
+    return orig_expr;
+
+  expr = copy_node (expr);
+  TREE_OPERAND (expr, 0) = op0;
+  if (op1)
+    TREE_OPERAND (expr, 1) = op1;
+
+  return fold_convert (orig_type, expr);
+}
+
 /* Adds a candidate BASE + STEP * i.  Important field is set to IMPORTANT and
    position to POS.  If USE is not NULL, the candidate is set as related to
    it.  If both BASE and STEP are NULL, we add a pseudocandidate for the
@@ -1962,7 +2065,8 @@ static void
 add_address_candidates (struct ivopts_data *data,
                        struct iv *iv, struct iv_use *use)
 {
-  tree base, abase, tmp, *act;
+  tree base, abase;
+  unsigned HOST_WIDE_INT offset;
 
   /* First, the trivial choices.  */
   add_iv_value_candidates (data, iv, use);
@@ -1991,26 +2095,9 @@ add_address_candidates (struct ivopts_data *data,
 
   /* Third, try removing the constant offset.  */
   abase = iv->base;
-  while (TREE_CODE (abase) == PLUS_EXPR
-        && TREE_CODE (TREE_OPERAND (abase, 1)) != INTEGER_CST)
-    abase = TREE_OPERAND (abase, 0);
-  /* We found the offset, so make the copy of the non-shared part and
-     remove it.  */
-  if (TREE_CODE (abase) == PLUS_EXPR)
-    {
-      tmp = iv->base;
-      act = &base;
-
-      for (tmp = iv->base; tmp != abase; tmp = TREE_OPERAND (tmp, 0))
-       {
-         *act = build2 (PLUS_EXPR, TREE_TYPE (tmp),
-                        NULL_TREE, TREE_OPERAND (tmp, 1));
-         act = &TREE_OPERAND (*act, 0);
-       }
-      *act = TREE_OPERAND (tmp, 0);
-
-      add_candidate (data, base, iv->step, false, use);
-    }
+  base = strip_offset (abase, false, &offset);
+  if (offset)
+    add_candidate (data, base, iv->step, false, use);
 }
 
 /* Possibly adds pseudocandidate for replacing the final value of USE by
@@ -2097,7 +2184,7 @@ record_important_candidates (struct ivopts_data *data)
       for (i = 0; i < n_iv_uses (data); i++)
        {
          use = iv_use (data, i);
-         BITMAP_XFREE (use->related_cands);
+         BITMAP_FREE (use->related_cands);
        }
     }
   else
@@ -2173,7 +2260,7 @@ set_use_iv_cost (struct ivopts_data *data,
 
   if (cost == INFTY)
     {
-      BITMAP_XFREE (depends_on);
+      BITMAP_FREE (depends_on);
       return;
     }
 
@@ -2261,8 +2348,8 @@ static rtx
 produce_memory_decl_rtl (tree obj, int *regno)
 {
   rtx x;
-  if (!obj)
-    abort ();
+  
+  gcc_assert (obj);
   if (TREE_STATIC (obj) || DECL_EXTERNAL (obj))
     {
       const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (obj));
@@ -2340,7 +2427,8 @@ computation_cost (tree expr)
   rtx seq, rslt;
   tree type = TREE_TYPE (expr);
   unsigned cost;
-  int regno = 0;
+  /* Avoid using hard regs in ways which may be unsupported.  */
+  int regno = LAST_VIRTUAL_REGISTER + 1;
 
   walk_tree (&expr, prepare_decl_rtl, &regno, NULL);
   start_sequence ();
@@ -2472,53 +2560,6 @@ get_computation (struct loop *loop, struct iv_use *use, struct iv_cand *cand)
   return get_computation_at (loop, use, cand, use->stmt);
 }
 
-/* Strips constant offsets from EXPR and adds them to OFFSET.  */
-
-static void
-strip_offset (tree *expr, unsigned HOST_WIDE_INT *offset)
-{
-  tree op0, op1;
-  enum tree_code code;
-  
-  while (1)
-    {
-      if (cst_and_fits_in_hwi (*expr))
-       {
-         *offset += int_cst_value (*expr);
-         *expr = integer_zero_node;
-         return;
-       }
-
-      code = TREE_CODE (*expr);
-     
-      if (code != PLUS_EXPR && code != MINUS_EXPR)
-       return;
-
-      op0 = TREE_OPERAND (*expr, 0);
-      op1 = TREE_OPERAND (*expr, 1);
-
-      if (cst_and_fits_in_hwi (op1))
-       {
-         if (code == PLUS_EXPR)
-           *offset += int_cst_value (op1);
-         else
-           *offset -= int_cst_value (op1);
-
-         *expr = op0;
-         continue;
-       }
-
-      if (code != PLUS_EXPR)
-       return;
-
-      if (!cst_and_fits_in_hwi (op0))
-       return;
-
-      *offset += int_cst_value (op0);
-      *expr = op1;
-    }
-}
-
 /* Returns cost of addition in MODE.  */
 
 static unsigned
@@ -2787,7 +2828,7 @@ find_depends (tree *expr_p, int *ws ATTRIBUTE_UNUSED, void *data)
     return NULL_TREE;
 
   if (!*depends_on)
-    *depends_on = BITMAP_XMALLOC ();
+    *depends_on = BITMAP_ALLOC (NULL);
   bitmap_set_bit (*depends_on, info->inv_id);
 
   return NULL_TREE;
@@ -2841,6 +2882,8 @@ force_var_cost (struct ivopts_data *data,
       costs_initialized = true;
     }
 
+  STRIP_NOPS (expr);
+
   if (depends_on)
     {
       fd_ivopts_data = data;
@@ -2875,6 +2918,8 @@ force_var_cost (struct ivopts_data *data,
     case MULT_EXPR:
       op0 = TREE_OPERAND (expr, 0);
       op1 = TREE_OPERAND (expr, 1);
+      STRIP_NOPS (op0);
+      STRIP_NOPS (op1);
 
       if (is_gimple_val (op0))
        cost0 = 0;
@@ -3020,11 +3065,14 @@ difference_cost (struct ivopts_data *data,
 {
   unsigned cost;
   enum machine_mode mode = TYPE_MODE (TREE_TYPE (e1));
+  unsigned HOST_WIDE_INT off1, off2;
+
+  e1 = strip_offset (e1, false, &off1);
+  e2 = strip_offset (e2, false, &off2);
+  *offset += off1 - off2;
 
-  strip_offset (&e1, offset);
-  *offset = -*offset;
-  strip_offset (&e2, offset);
-  *offset = -*offset;
+  STRIP_NOPS (e1);
+  STRIP_NOPS (e2);
 
   if (TREE_CODE (e1) == ADDR_EXPR)
     return ptr_difference_cost (data, e1, e2, symbol_present, var_present, offset,
@@ -3542,7 +3590,7 @@ determine_use_iv_costs (struct ivopts_data *data)
   unsigned i, j;
   struct iv_use *use;
   struct iv_cand *cand;
-  bitmap to_clear = BITMAP_XMALLOC ();
+  bitmap to_clear = BITMAP_ALLOC (NULL);
 
   alloc_use_cost_map (data);
 
@@ -3576,7 +3624,7 @@ determine_use_iv_costs (struct ivopts_data *data)
        }
     }
 
-  BITMAP_XFREE (to_clear);
+  BITMAP_FREE (to_clear);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -3633,8 +3681,11 @@ determine_iv_cost (struct ivopts_data *data, struct iv_cand *cand)
 
   cand->cost = cost_step + cost_base / AVG_LOOP_NITER (current_loop);
 
-  /* Prefer the original iv unless we may gain something by replacing it.  */
-  if (cand->pos == IP_ORIGINAL)
+  /* Prefer the original iv unless we may gain something by replacing it;
+     this is not really relevant for artificial ivs created by other
+     passes.  */
+  if (cand->pos == IP_ORIGINAL
+      && !DECL_ARTIFICIAL (SSA_NAME_VAR (cand->var_before)))
     cand->cost--;
   
   /* Prefer not to insert statements into latch unless there are some
@@ -3969,7 +4020,7 @@ iv_ca_delta_add (struct iv_use *use, struct cost_pair *old_cp,
 }
 
 /* Joins two lists of changes L1 and L2.  Destructive -- old lists
-   are rewritten.   */
+   are rewritten.  */
 
 static struct iv_ca_delta *
 iv_ca_delta_join (struct iv_ca_delta *l1, struct iv_ca_delta *l2)
@@ -4087,7 +4138,7 @@ iv_ca_new (struct ivopts_data *data)
   nw->bad_uses = 0;
   nw->cand_for_use = xcalloc (n_iv_uses (data), sizeof (struct cost_pair *));
   nw->n_cand_uses = xcalloc (n_iv_cands (data), sizeof (unsigned));
-  nw->cands = BITMAP_XMALLOC ();
+  nw->cands = BITMAP_ALLOC (NULL);
   nw->n_cands = 0;
   nw->n_regs = 0;
   nw->cand_use_cost = 0;
@@ -4105,7 +4156,7 @@ iv_ca_free (struct iv_ca **ivs)
 {
   free ((*ivs)->cand_for_use);
   free ((*ivs)->n_cand_uses);
-  BITMAP_XFREE ((*ivs)->cands);
+  BITMAP_FREE ((*ivs)->cands);
   free ((*ivs)->n_invariant_uses);
   free (*ivs);
   *ivs = NULL;
@@ -4604,7 +4655,7 @@ remove_statement (tree stmt, bool including_defined_name)
          /* Prevent the ssa name defined by the statement from being removed.  */
          SET_PHI_RESULT (stmt, NULL);
        }
-      remove_phi_node (stmt, NULL_TREE, bb_for_stmt (stmt));
+      remove_phi_node (stmt, NULL_TREE);
     }
   else
     {
@@ -4830,15 +4881,17 @@ rewrite_use_compare (struct ivopts_data *data,
   
   if (may_eliminate_iv (data, use, cand, &compare, &bound))
     {
+      tree var = var_at_stmt (data->current_loop, cand, use->stmt);
+      tree var_type = TREE_TYPE (var);
+
+      bound = fold_convert (var_type, bound);
       op = force_gimple_operand (unshare_expr (bound), &stmts,
                                 true, NULL_TREE);
 
       if (stmts)
        bsi_insert_before (&bsi, stmts, BSI_SAME_STMT);
 
-      *use->op_p = build2 (compare, boolean_type_node,
-                         var_at_stmt (data->current_loop,
-                                      cand, use->stmt), op);
+      *use->op_p = build2 (compare, boolean_type_node, var, op);
       modify_stmt (use->stmt);
       return;
     }
@@ -4937,7 +4990,7 @@ compute_phi_arg_on_exit (edge exit, tree stmts, tree op)
   block_stmt_iterator bsi;
   tree phi, stmt, def, next;
 
-  if (EDGE_COUNT (exit->dest->preds) > 1)
+  if (!single_pred_p (exit->dest))
     split_loop_exit_edge (exit);
 
   if (TREE_CODE (stmts) == STATEMENT_LIST)
@@ -5145,10 +5198,10 @@ free_loop_data (struct ivopts_data *data)
       struct iv_use *use = iv_use (data, i);
 
       free (use->iv);
-      BITMAP_XFREE (use->related_cands);
+      BITMAP_FREE (use->related_cands);
       for (j = 0; j < use->n_map_members; j++)
        if (use->cost_map[j].depends_on)
-         BITMAP_XFREE (use->cost_map[j].depends_on);
+         BITMAP_FREE (use->cost_map[j].depends_on);
       free (use->cost_map);
       free (use);
     }
@@ -5200,8 +5253,8 @@ tree_ssa_iv_optimize_finalize (struct loops *loops, struct ivopts_data *data)
 
   free_loop_data (data);
   free (data->version_info);
-  BITMAP_XFREE (data->relevant);
-  BITMAP_XFREE (data->important_candidates);
+  BITMAP_FREE (data->relevant);
+  BITMAP_FREE (data->important_candidates);
   htab_delete (data->niters);
 
   VARRAY_FREE (decl_rtl_to_reset);