i386.c (legitimize_tls_address): Generate tls_initial_exec_64_sun only when !TARGET_X32.
[gcc.git] / gcc / tree-cfg.c
index db10daf6abc7da55bb2711ed2f22504521f6a499..cd68f1f86c4031d3458fae7084ca18067b16cbfc 100644 (file)
@@ -1,6 +1,6 @@
 /* Control flow functions for trees.
    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011  Free Software Foundation, Inc.
+   2010, 2011, 2012  Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
@@ -56,7 +56,7 @@ static const int initial_cfg_capacity = 20;
 
 /* This hash table allows us to efficiently lookup all CASE_LABEL_EXPRs
    which use a particular edge.  The CASE_LABEL_EXPRs are chained together
-   via their TREE_CHAIN field, which we clear after we're done with the
+   via their CASE_CHAIN field, which we clear after we're done with the
    hash table to prevent problems with duplication of GIMPLE_SWITCHes.
 
    Access to this list of CASE_LABEL_EXPRs allows us to efficiently
@@ -377,7 +377,7 @@ make_blocks (gimple_seq seq)
       if (start_new_block || stmt_starts_bb_p (stmt, prev_stmt))
        {
          if (!first_stmt_of_seq)
-           seq = gsi_split_seq_before (&i);
+           gsi_split_seq_before (&i, &seq);
          bb = create_basic_block (seq, NULL, bb);
          start_new_block = false;
        }
@@ -438,8 +438,7 @@ create_bb (void *h, void *e, basic_block after)
 
   bb->index = last_basic_block;
   bb->flags = BB_NEW;
-  bb->il.gimple = ggc_alloc_cleared_gimple_bb_info ();
-  set_bb_seq (bb, h ? (gimple_seq) h : gimple_seq_alloc ());
+  set_bb_seq (bb, h ? (gimple_seq) h : NULL);
 
   /* Add the new block to the linked list of blocks.  */
   link_block (bb, after);
@@ -1592,7 +1591,7 @@ replace_uses_by (tree name, tree val)
                  /* This can only occur for virtual operands, since
                     for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
                     would prevent replacement.  */
-                 gcc_assert (!is_gimple_reg (name));
+                 gcc_checking_assert (!is_gimple_reg (name));
                  SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
                }
            }
@@ -1604,28 +1603,37 @@ replace_uses_by (tree name, tree val)
          gimple orig_stmt = stmt;
          size_t i;
 
-         fold_stmt (&gsi);
-         stmt = gsi_stmt (gsi);
-         if (cfgcleanup_altered_bbs && !is_gimple_debug (stmt))
+         /* Mark the block if we changed the last stmt in it.  */
+         if (cfgcleanup_altered_bbs
+             && stmt_ends_bb_p (stmt))
            bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index);
 
-         /* FIXME.  This should go in update_stmt.  */
-         for (i = 0; i < gimple_num_ops (stmt); i++)
-           {
-             tree op = gimple_op (stmt, i);
-              /* Operands may be empty here.  For example, the labels
-                 of a GIMPLE_COND are nulled out following the creation
-                 of the corresponding CFG edges.  */
-             if (op && TREE_CODE (op) == ADDR_EXPR)
-               recompute_tree_invariant_for_addr_expr (op);
-           }
+         /* FIXME.  It shouldn't be required to keep TREE_CONSTANT
+            on ADDR_EXPRs up-to-date on GIMPLE.  Propagation will
+            only change sth from non-invariant to invariant, and only
+            when propagating constants.  */
+         if (is_gimple_min_invariant (val))
+           for (i = 0; i < gimple_num_ops (stmt); i++)
+             {
+               tree op = gimple_op (stmt, i);
+               /* Operands may be empty here.  For example, the labels
+                  of a GIMPLE_COND are nulled out following the creation
+                  of the corresponding CFG edges.  */
+               if (op && TREE_CODE (op) == ADDR_EXPR)
+                 recompute_tree_invariant_for_addr_expr (op);
+             }
+
+         if (fold_stmt (&gsi))
+           stmt = gsi_stmt (gsi);
+
+         if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
+           gimple_purge_dead_eh_edges (gimple_bb (stmt));
 
-         maybe_clean_or_replace_eh_stmt (orig_stmt, stmt);
          update_stmt (stmt);
        }
     }
 
-  gcc_assert (has_zero_uses (name));
+  gcc_checking_assert (has_zero_uses (name));
 
   /* Also update the trees stored in loop structures.  */
   if (current_loops)
@@ -1646,7 +1654,6 @@ static void
 gimple_merge_blocks (basic_block a, basic_block b)
 {
   gimple_stmt_iterator last, gsi, psi;
-  gimple_seq phis = phi_nodes (b);
 
   if (dump_file)
     fprintf (dump_file, "Merging blocks %d and %d\n", a->index, b->index);
@@ -1654,7 +1661,7 @@ gimple_merge_blocks (basic_block a, basic_block b)
   /* Remove all single-valued PHI nodes from block B of the form
      V_i = PHI <V_j> by propagating V_j to all the uses of V_i.  */
   gsi = gsi_last_bb (a);
-  for (psi = gsi_start (phis); !gsi_end_p (psi); )
+  for (psi = gsi_start_phis (b); !gsi_end_p (psi); )
     {
       gimple phi = gsi_stmt (psi);
       tree def = gimple_phi_result (phi), use = gimple_phi_arg_def (phi, 0);
@@ -1910,7 +1917,8 @@ remove_bb (basic_block bb)
     }
 
   remove_phi_nodes_and_edges_for_unreachable_block (bb);
-  bb->il.gimple = NULL;
+  bb->il.gimple.seq = NULL;
+  bb->il.gimple.phi_nodes = NULL;
 }
 
 
@@ -2264,6 +2272,43 @@ gimple_cfg2vcg (FILE *file)
                             Miscellaneous helpers
 ---------------------------------------------------------------------------*/
 
+/* Return true if T, a GIMPLE_CALL, can make an abnormal transfer of control
+   flow.  Transfers of control flow associated with EH are excluded.  */
+
+static bool
+call_can_make_abnormal_goto (gimple t)
+{
+  /* If the function has no non-local labels, then a call cannot make an
+     abnormal transfer of control.  */
+  if (!cfun->has_nonlocal_label)
+   return false;
+
+  /* Likewise if the call has no side effects.  */
+  if (!gimple_has_side_effects (t))
+    return false;
+
+  /* Likewise if the called function is leaf.  */
+  if (gimple_call_flags (t) & ECF_LEAF)
+    return false;
+
+  return true;
+}
+
+
+/* Return true if T can make an abnormal transfer of control flow.
+   Transfers of control flow associated with EH are excluded.  */
+
+bool
+stmt_can_make_abnormal_goto (gimple t)
+{
+  if (computed_goto_p (t))
+    return true;
+  if (is_gimple_call (t))
+    return call_can_make_abnormal_goto (t);
+  return false;
+}
+
+
 /* Return true if T represents a stmt that always transfers control.  */
 
 bool
@@ -2297,10 +2342,8 @@ is_ctrl_altering_stmt (gimple t)
       {
        int flags = gimple_call_flags (t);
 
-       /* A non-pure/const call alters flow control if the current
-          function has nonlocal labels.  */
-       if (!(flags & (ECF_CONST | ECF_PURE | ECF_LEAF))
-           && cfun->has_nonlocal_label)
+       /* A call alters control flow if it can make an abnormal goto.  */
+       if (call_can_make_abnormal_goto (t))
          return true;
 
        /* A call also alters control flow if it does not return.  */
@@ -2358,21 +2401,6 @@ simple_goto_p (gimple t)
 }
 
 
-/* Return true if T can make an abnormal transfer of control flow.
-   Transfers of control flow associated with EH are excluded.  */
-
-bool
-stmt_can_make_abnormal_goto (gimple t)
-{
-  if (computed_goto_p (t))
-    return true;
-  if (is_gimple_call (t))
-    return (gimple_has_side_effects (t) && cfun->has_nonlocal_label
-           && !(gimple_call_flags (t) & ECF_LEAF));
-  return false;
-}
-
-
 /* Return true if STMT should start a new basic block.  PREV_STMT is
    the statement preceding STMT.  It is used when STMT is a label or a
    case label.  Labels should only start a new basic block if their
@@ -2781,17 +2809,19 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
                  error ("invalid position or size operand to BIT_FIELD_REF");
                  return t;
                }
-             else if (INTEGRAL_TYPE_P (TREE_TYPE (t))
-                      && (TYPE_PRECISION (TREE_TYPE (t))
-                          != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
+             if (INTEGRAL_TYPE_P (TREE_TYPE (t))
+                 && (TYPE_PRECISION (TREE_TYPE (t))
+                     != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
                {
                  error ("integral result type precision does not match "
                         "field size of BIT_FIELD_REF");
                  return t;
                }
-             if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-                 && (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (t)))
-                     != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
+             else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+                      && !AGGREGATE_TYPE_P (TREE_TYPE (t))
+                      && TYPE_MODE (TREE_TYPE (t)) != BLKmode
+                      && (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (t)))
+                          != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
                {
                  error ("mode precision of non-integral result does not "
                         "match field size of BIT_FIELD_REF");
@@ -3331,25 +3361,22 @@ verify_gimple_assign_unary (gimple stmt)
     {
     CASE_CONVERT:
       {
-       /* Allow conversions between integral types and pointers only if
+       /* Allow conversions from pointer type to integral type only if
           there is no sign or zero extension involved.
           For targets were the precision of ptrofftype doesn't match that
-          of pointers we need to allow arbitrary conversions from and
-          to ptrofftype.  */
+          of pointers we need to allow arbitrary conversions to ptrofftype.  */
        if ((POINTER_TYPE_P (lhs_type)
-            && INTEGRAL_TYPE_P (rhs1_type)
-            && (TYPE_PRECISION (lhs_type) >= TYPE_PRECISION (rhs1_type)
-                || ptrofftype_p (rhs1_type)))
+            && INTEGRAL_TYPE_P (rhs1_type))
            || (POINTER_TYPE_P (rhs1_type)
                && INTEGRAL_TYPE_P (lhs_type)
                && (TYPE_PRECISION (rhs1_type) >= TYPE_PRECISION (lhs_type)
                    || ptrofftype_p (sizetype))))
          return false;
 
-       /* Allow conversion from integer to offset type and vice versa.  */
+       /* Allow conversion from integral to offset type and vice versa.  */
        if ((TREE_CODE (lhs_type) == OFFSET_TYPE
-            && TREE_CODE (rhs1_type) == INTEGER_TYPE)
-           || (TREE_CODE (lhs_type) == INTEGER_TYPE
+            && INTEGRAL_TYPE_P (rhs1_type))
+           || (INTEGRAL_TYPE_P (lhs_type)
                && TREE_CODE (rhs1_type) == OFFSET_TYPE))
          return false;
 
@@ -3702,10 +3729,6 @@ do_pointer_plus_expr_check:
     case VEC_PACK_TRUNC_EXPR:
     case VEC_PACK_SAT_EXPR:
     case VEC_PACK_FIX_TRUNC_EXPR:
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
-    case VEC_INTERLEAVE_HIGH_EXPR:
-    case VEC_INTERLEAVE_LOW_EXPR:
       /* FIXME.  */
       return false;
 
@@ -4099,6 +4122,10 @@ verify_gimple_goto (gimple stmt)
 static bool
 verify_gimple_switch (gimple stmt)
 {
+  unsigned int i, n;
+  tree elt, prev_upper_bound = NULL_TREE;
+  tree index_type, elt_type = NULL_TREE;
+
   if (!is_gimple_val (gimple_switch_index (stmt)))
     {
       error ("invalid operand to switch statement");
@@ -4106,6 +4133,75 @@ verify_gimple_switch (gimple stmt)
       return true;
     }
 
+  index_type = TREE_TYPE (gimple_switch_index (stmt));
+  if (! INTEGRAL_TYPE_P (index_type))
+    {
+      error ("non-integral type switch statement");
+      debug_generic_expr (index_type);
+      return true;
+    }
+
+  elt = gimple_switch_default_label (stmt);
+  if (CASE_LOW (elt) != NULL_TREE || CASE_HIGH (elt) != NULL_TREE)
+    {
+      error ("invalid default case label in switch statement");
+      debug_generic_expr (elt);
+      return true;
+    }
+
+  n = gimple_switch_num_labels (stmt);
+  for (i = 1; i < n; i++)
+    {
+      elt = gimple_switch_label (stmt, i);
+
+      if (! CASE_LOW (elt))
+       {
+         error ("invalid case label in switch statement");
+         debug_generic_expr (elt);
+         return true;
+       }
+      if (CASE_HIGH (elt)
+         && ! tree_int_cst_lt (CASE_LOW (elt), CASE_HIGH (elt)))
+       {
+         error ("invalid case range in switch statement");
+         debug_generic_expr (elt);
+         return true;
+       }
+
+      if (elt_type)
+       {
+         if (TREE_TYPE (CASE_LOW (elt)) != elt_type
+             || (CASE_HIGH (elt) && TREE_TYPE (CASE_HIGH (elt)) != elt_type))
+           {
+             error ("type mismatch for case label in switch statement");
+             debug_generic_expr (elt);
+             return true;
+           }
+       }
+      else
+       {
+         elt_type = TREE_TYPE (CASE_LOW (elt));
+         if (TYPE_PRECISION (index_type) < TYPE_PRECISION (elt_type))
+           {
+             error ("type precision mismatch in switch statement");
+             return true;
+           }
+       }
+
+      if (prev_upper_bound)
+       {
+         if (! tree_int_cst_lt (prev_upper_bound, CASE_LOW (elt)))
+           {
+             error ("case labels not sorted in switch statement");
+             return true;
+           }
+       }
+
+      prev_upper_bound = CASE_HIGH (elt);
+      if (! prev_upper_bound)
+       prev_upper_bound = CASE_LOW (elt);
+    }
+
   return false;
 }
 
@@ -4591,13 +4687,13 @@ gimple_verify_flow_info (void)
   edge e;
   edge_iterator ei;
 
-  if (ENTRY_BLOCK_PTR->il.gimple)
+  if (ENTRY_BLOCK_PTR->il.gimple.seq || ENTRY_BLOCK_PTR->il.gimple.phi_nodes)
     {
       error ("ENTRY_BLOCK has IL associated with it");
       err = 1;
     }
 
-  if (EXIT_BLOCK_PTR->il.gimple)
+  if (EXIT_BLOCK_PTR->il.gimple.seq || EXIT_BLOCK_PTR->il.gimple.phi_nodes)
     {
       error ("EXIT_BLOCK has IL associated with it");
       err = 1;
@@ -5225,7 +5321,7 @@ gimple_split_block (basic_block bb, void *stmt)
      brings ugly quadratic memory consumption in the inliner.
      (We are still quadratic since we need to update stmt BB pointers,
      sadly.)  */
-  list = gsi_split_seq_before (&gsi);
+  gsi_split_seq_before (&gsi, &list);
   set_bb_seq (new_bb, list);
   for (gsi_tgt = gsi_start (list);
        !gsi_end_p (gsi_tgt); gsi_next (&gsi_tgt))
@@ -5571,6 +5667,20 @@ gimple_duplicate_sese_region (edge entry, edge exit,
   return true;
 }
 
+/* Checks if BB is part of the region defined by N_REGION BBS.  */
+static bool 
+bb_part_of_region_p (basic_block bb, basic_block* bbs, unsigned n_region)
+{
+  unsigned int n;
+
+  for (n = 0; n < n_region; n++)
+    {
+     if (bb == bbs[n])
+       return true;
+    }
+  return false;
+}
+
 /* Duplicates REGION consisting of N_REGION blocks.  The new blocks
    are stored to REGION_COPY in the same order in that they appear
    in REGION, if REGION_COPY is not NULL.  ENTRY is the entry to
@@ -5621,6 +5731,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
   gimple_stmt_iterator psi;
   gimple phi;
   tree def;
+  struct loop *target, *aloop, *cloop;
 
   gcc_assert (EDGE_COUNT (exit->src->succs) == 2);
   exits[0] = exit;
@@ -5631,7 +5742,16 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
 
   initialize_original_copy_tables ();
   set_loop_copy (orig_loop, loop);
-  duplicate_subloops (orig_loop, loop);
+
+  target= loop;
+  for (aloop = orig_loop->inner; aloop; aloop = aloop->next)
+    {
+      if (bb_part_of_region_p (aloop->header, region, n_region))
+       {
+         cloop = duplicate_loop (aloop, target);
+         duplicate_subloops (aloop, cloop);
+       }
+    }
 
   if (!region_copy)
     {
@@ -5734,7 +5854,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
            add_phi_arg (phi, def, e, gimple_phi_arg_location_from_edge (phi, e));
          }
       }
-  e = redirect_edge_and_branch (nexits[0], nexits[1]->dest);
+  e = redirect_edge_and_branch (nexits[1], nexits[0]->dest);
   PENDING_STMT (e) = NULL;
   
   /* Anything that is outside of the region, but was dominated by something
@@ -6037,8 +6157,8 @@ move_stmt_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
          p->remap_decls_p = false;
          *handled_ops_p = true;
 
-         walk_gimple_seq (gimple_omp_body (stmt), move_stmt_r,
-                          move_stmt_op, wi);
+         walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), move_stmt_r,
+                              move_stmt_op, wi);
 
          p->remap_decls_p = save_remap_decls_p;
        }
@@ -6877,9 +6997,20 @@ need_fake_edge_p (gimple t)
           && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FORK))
     return false;
 
-  if (is_gimple_call (t)
-      && !(call_flags & ECF_NORETURN))
-    return true;
+  if (is_gimple_call (t))
+    {
+      edge_iterator ei;
+      edge e;
+      basic_block bb;
+
+      if (!(call_flags & ECF_NORETURN))
+       return true;
+
+      bb = gimple_bb (t);
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if ((e->flags & EDGE_FAKE) == 0)
+         return true;
+    }
 
   if (gimple_code (t) == GIMPLE_ASM
        && (gimple_asm_volatile_p (t) || gimple_asm_input_p (t)))
@@ -6890,9 +7021,10 @@ need_fake_edge_p (gimple t)
 
 
 /* Add fake edges to the function exit for any non constant and non
-   noreturn calls, volatile inline assembly in the bitmap of blocks
-   specified by BLOCKS or to the whole CFG if BLOCKS is zero.  Return
-   the number of blocks that were split.
+   noreturn calls (or noreturn calls with EH/abnormal edges),
+   volatile inline assembly in the bitmap of blocks specified by BLOCKS
+   or to the whole CFG if BLOCKS is zero.  Return the number of blocks
+   that were split.
 
    The goal is to expose cases in which entering a basic block does
    not imply that all subsequent instructions must be executed.  */