OSDN Git Service

2011-11-09 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index 1207908..d81cc67 100644 (file)
@@ -117,6 +117,7 @@ static int gimple_verify_flow_info (void);
 static void gimple_make_forwarder_block (edge);
 static void gimple_cfg2vcg (FILE *);
 static gimple first_non_label_stmt (basic_block);
+static bool verify_gimple_transaction (gimple);
 
 /* Flowgraph optimization and cleanup.  */
 static void gimple_merge_blocks (basic_block, basic_block);
@@ -666,6 +667,15 @@ make_edges (void)
                }
              break;
 
+           case GIMPLE_TRANSACTION:
+             {
+               tree abort_label = gimple_transaction_label (last);
+               if (abort_label)
+                 make_edge (bb, label_to_block (abort_label), 0);
+               fallthru = true;
+             }
+             break;
+
            default:
              gcc_assert (!stmt_ends_bb_p (last));
              fallthru = true;
@@ -1196,22 +1206,30 @@ cleanup_dead_labels (void)
   FOR_EACH_BB (bb)
     {
       gimple stmt = last_stmt (bb);
+      tree label, new_label;
+
       if (!stmt)
        continue;
 
       switch (gimple_code (stmt))
        {
        case GIMPLE_COND:
-         {
-           tree true_label = gimple_cond_true_label (stmt);
-           tree false_label = gimple_cond_false_label (stmt);
+         label = gimple_cond_true_label (stmt);
+         if (label)
+           {
+             new_label = main_block_label (label);
+             if (new_label != label)
+               gimple_cond_set_true_label (stmt, new_label);
+           }
 
-           if (true_label)
-             gimple_cond_set_true_label (stmt, main_block_label (true_label));
-           if (false_label)
-             gimple_cond_set_false_label (stmt, main_block_label (false_label));
-           break;
-         }
+         label = gimple_cond_false_label (stmt);
+         if (label)
+           {
+             new_label = main_block_label (label);
+             if (new_label != label)
+               gimple_cond_set_false_label (stmt, new_label);
+           }
+         break;
 
        case GIMPLE_SWITCH:
          {
@@ -1221,8 +1239,10 @@ cleanup_dead_labels (void)
            for (i = 0; i < n; ++i)
              {
                tree case_label = gimple_switch_label (stmt, i);
-               tree label = main_block_label (CASE_LABEL (case_label));
-               CASE_LABEL (case_label) = label;
+               label = CASE_LABEL (case_label);
+               new_label = main_block_label (label);
+               if (new_label != label)
+                 CASE_LABEL (case_label) = new_label;
              }
            break;
          }
@@ -1243,13 +1263,27 @@ cleanup_dead_labels (void)
        /* We have to handle gotos until they're removed, and we don't
           remove them until after we've created the CFG edges.  */
        case GIMPLE_GOTO:
-          if (!computed_goto_p (stmt))
+         if (!computed_goto_p (stmt))
            {
-             tree new_dest = main_block_label (gimple_goto_dest (stmt));
-             gimple_goto_set_dest (stmt, new_dest);
+             label = gimple_goto_dest (stmt);
+             new_label = main_block_label (label);
+             if (new_label != label)
+               gimple_goto_set_dest (stmt, new_label);
            }
          break;
 
+       case GIMPLE_TRANSACTION:
+         {
+           tree label = gimple_transaction_label (stmt);
+           if (label)
+             {
+               tree new_label = main_block_label (label);
+               if (new_label != label)
+                 gimple_transaction_set_label (stmt, new_label);
+             }
+         }
+         break;
+
        default:
          break;
       }
@@ -1454,8 +1488,8 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
        break;
       lab = gimple_label_label (stmt);
 
-      /* Do not remove user labels.  */
-      if (!DECL_ARTIFICIAL (lab))
+      /* Do not remove user forced labels or for -O0 any user labels.  */
+      if (!DECL_ARTIFICIAL (lab) && (!optimize || FORCED_LABEL (lab)))
        return false;
     }
 
@@ -1566,9 +1600,11 @@ replace_uses_by (tree name, tree val)
 
       if (gimple_code (stmt) != GIMPLE_PHI)
        {
+         gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
          size_t i;
 
-         fold_stmt_inplace (stmt);
+         fold_stmt (&gsi);
+         stmt = gsi_stmt (gsi);
          if (cfgcleanup_altered_bbs && !is_gimple_debug (stmt))
            bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index);
 
@@ -1699,6 +1735,15 @@ gimple_merge_blocks (basic_block a, basic_block b)
              gimple_stmt_iterator dest_gsi = gsi_start_bb (a);
              gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
            }
+         /* Other user labels keep around in a form of a debug stmt.  */
+         else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_STMTS)
+           {
+             gimple dbg = gimple_build_debug_bind (label,
+                                                   integer_zero_node,
+                                                   stmt);
+             gimple_debug_bind_reset_value (dbg);
+             gsi_insert_before (&gsi, dbg, GSI_SAME_STMT);
+           }
 
          lp_nr = EH_LANDING_PAD_NR (label);
          if (lp_nr)
@@ -2261,6 +2306,13 @@ is_ctrl_altering_stmt (gimple t)
        if (flags & ECF_NORETURN)
          return true;
 
+       /* TM ending statements have backedges out of the transaction.
+          Return true so we split the basic block containing them.
+          Note that the TM_BUILTIN test is merely an optimization.  */
+       if ((flags & ECF_TM_BUILTIN)
+           && is_tm_ending_fndecl (gimple_call_fndecl (t)))
+         return true;
+
        /* BUILT_IN_RETURN call is same as return statement.  */
        if (gimple_call_builtin_p (t, BUILT_IN_RETURN))
          return true;
@@ -2282,6 +2334,10 @@ is_ctrl_altering_stmt (gimple t)
       /* OpenMP directives alter control flow.  */
       return true;
 
+    case GIMPLE_TRANSACTION:
+      /* A transaction start alters control flow.  */
+      return true;
+
     default:
       break;
     }
@@ -2772,13 +2828,11 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
          error ("invalid operand to pointer plus, first operand is not a pointer");
          return t;
        }
-      /* Check to make sure the second operand is an integer with type of
-        sizetype.  */
-      if (!useless_type_conversion_p (sizetype,
-                                    TREE_TYPE (TREE_OPERAND (t, 1))))
+      /* Check to make sure the second operand is a ptrofftype.  */
+      if (!ptrofftype_p (TREE_TYPE (TREE_OPERAND (t, 1))))
        {
          error ("invalid operand to pointer plus, second operand is not an "
-                "integer with type of sizetype");
+                "integer type of appropriate width");
          return t;
        }
       /* FALLTHROUGH */
@@ -3195,25 +3249,55 @@ verify_gimple_comparison (tree type, tree op0, tree op1)
      effective type the comparison is carried out in.  Instead
      we require that either the first operand is trivially
      convertible into the second, or the other way around.
-     The resulting type of a comparison may be any integral type.
      Because we special-case pointers to void we allow
      comparisons of pointers with the same mode as well.  */
-  if ((!useless_type_conversion_p (op0_type, op1_type)
-       && !useless_type_conversion_p (op1_type, op0_type)
-       && (!POINTER_TYPE_P (op0_type)
-          || !POINTER_TYPE_P (op1_type)
-          || TYPE_MODE (op0_type) != TYPE_MODE (op1_type)))
-      || !INTEGRAL_TYPE_P (type)
-      || (TREE_CODE (type) != BOOLEAN_TYPE
-         && TYPE_PRECISION (type) != 1))
-    {
-      error ("type mismatch in comparison expression");
-      debug_generic_expr (type);
+  if (!useless_type_conversion_p (op0_type, op1_type)
+      && !useless_type_conversion_p (op1_type, op0_type)
+      && (!POINTER_TYPE_P (op0_type)
+         || !POINTER_TYPE_P (op1_type)
+         || TYPE_MODE (op0_type) != TYPE_MODE (op1_type)))
+    {
+      error ("mismatching comparison operand types");
       debug_generic_expr (op0_type);
       debug_generic_expr (op1_type);
       return true;
     }
 
+  /* The resulting type of a comparison may be an effective boolean type.  */
+  if (INTEGRAL_TYPE_P (type)
+      && (TREE_CODE (type) == BOOLEAN_TYPE
+         || TYPE_PRECISION (type) == 1))
+    ;
+  /* Or an integer vector type with the same size and element count
+     as the comparison operand types.  */
+  else if (TREE_CODE (type) == VECTOR_TYPE
+          && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE)
+    {
+      if (TREE_CODE (op0_type) != VECTOR_TYPE
+         || TREE_CODE (op1_type) != VECTOR_TYPE)
+        {
+          error ("non-vector operands in vector comparison");
+          debug_generic_expr (op0_type);
+          debug_generic_expr (op1_type);
+          return true;
+        }
+
+      if (TYPE_VECTOR_SUBPARTS (type) != TYPE_VECTOR_SUBPARTS (op0_type)
+         || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type)))
+             != GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0_type)))))
+        {
+          error ("invalid vector comparison resulting type");
+          debug_generic_expr (type);
+          return true;
+        }
+    }
+  else
+    {
+      error ("bogus comparison result type");
+      debug_generic_expr (type);
+      return true;
+    }
+
   return false;
 }
 
@@ -3248,17 +3332,17 @@ verify_gimple_assign_unary (gimple stmt)
       {
        /* Allow conversions between integral types and pointers only if
           there is no sign or zero extension involved.
-          For targets were the precision of sizetype doesn't match that
+          For targets were the precision of ptrofftype doesn't match that
           of pointers we need to allow arbitrary conversions from and
-          to sizetype.  */
+          to ptrofftype.  */
        if ((POINTER_TYPE_P (lhs_type)
             && INTEGRAL_TYPE_P (rhs1_type)
             && (TYPE_PRECISION (lhs_type) >= TYPE_PRECISION (rhs1_type)
-                || rhs1_type == sizetype))
+                || ptrofftype_p (rhs1_type)))
            || (POINTER_TYPE_P (rhs1_type)
                && INTEGRAL_TYPE_P (lhs_type)
                && (TYPE_PRECISION (rhs1_type) >= TYPE_PRECISION (lhs_type)
-                   || lhs_type == sizetype)))
+                   || ptrofftype_p (sizetype))))
          return false;
 
        /* Allow conversion from integer to offset type and vice versa.  */
@@ -3312,7 +3396,9 @@ verify_gimple_assign_unary (gimple stmt)
 
     case FLOAT_EXPR:
       {
-       if (!INTEGRAL_TYPE_P (rhs1_type) || !SCALAR_FLOAT_TYPE_P (lhs_type))
+       if ((!INTEGRAL_TYPE_P (rhs1_type) || !SCALAR_FLOAT_TYPE_P (lhs_type))
+           && (!VECTOR_INTEGER_TYPE_P (rhs1_type)
+               || !VECTOR_FLOAT_TYPE_P(lhs_type)))
          {
            error ("invalid types in conversion to floating point");
            debug_generic_expr (lhs_type);
@@ -3325,7 +3411,9 @@ verify_gimple_assign_unary (gimple stmt)
 
     case FIX_TRUNC_EXPR:
       {
-       if (!INTEGRAL_TYPE_P (lhs_type) || !SCALAR_FLOAT_TYPE_P (rhs1_type))
+        if ((!INTEGRAL_TYPE_P (lhs_type) || !SCALAR_FLOAT_TYPE_P (rhs1_type))
+            && (!VECTOR_INTEGER_TYPE_P (lhs_type)
+                || !VECTOR_FLOAT_TYPE_P(rhs1_type)))
          {
            error ("invalid types in conversion to integer");
            debug_generic_expr (lhs_type);
@@ -3480,6 +3568,44 @@ verify_gimple_assign_binary (gimple stmt)
        return false;
       }
 
+    case WIDEN_LSHIFT_EXPR:
+      {
+        if (!INTEGRAL_TYPE_P (lhs_type)
+            || !INTEGRAL_TYPE_P (rhs1_type)
+            || TREE_CODE (rhs2) != INTEGER_CST
+            || (2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type)))
+          {
+            error ("type mismatch in widening vector shift expression");
+            debug_generic_expr (lhs_type);
+            debug_generic_expr (rhs1_type);
+            debug_generic_expr (rhs2_type);
+            return true;
+          }
+
+        return false;
+      }
+
+    case VEC_WIDEN_LSHIFT_HI_EXPR:
+    case VEC_WIDEN_LSHIFT_LO_EXPR:
+      {
+        if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+            || TREE_CODE (lhs_type) != VECTOR_TYPE
+            || !INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type))
+            || !INTEGRAL_TYPE_P (TREE_TYPE (lhs_type))
+            || TREE_CODE (rhs2) != INTEGER_CST
+            || (2 * TYPE_PRECISION (TREE_TYPE (rhs1_type))
+                > TYPE_PRECISION (TREE_TYPE (lhs_type))))
+          {
+            error ("type mismatch in widening vector shift expression");
+            debug_generic_expr (lhs_type);
+            debug_generic_expr (rhs1_type);
+            debug_generic_expr (rhs2_type);
+            return true;
+          }
+
+        return false;
+      }
+
     case PLUS_EXPR:
     case MINUS_EXPR:
       {
@@ -3525,7 +3651,7 @@ verify_gimple_assign_binary (gimple stmt)
 do_pointer_plus_expr_check:
        if (!POINTER_TYPE_P (rhs1_type)
            || !useless_type_conversion_p (lhs_type, rhs1_type)
-           || !useless_type_conversion_p (sizetype, rhs2_type))
+           || !ptrofftype_p (rhs2_type))
          {
            error ("type mismatch in pointer plus expression");
            debug_generic_stmt (lhs_type);
@@ -3566,7 +3692,7 @@ do_pointer_plus_expr_check:
     case WIDEN_MULT_EXPR:
       if (TREE_CODE (lhs_type) != INTEGER_TYPE)
        return true;
-      return ((2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type))
+      return ((2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type))
              || (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)));
 
     case WIDEN_SUM_EXPR:
@@ -3640,7 +3766,8 @@ verify_gimple_assign_ternary (gimple stmt)
       return true;
     }
 
-  if (!is_gimple_val (rhs1)
+  if (((rhs_code == VEC_COND_EXPR || rhs_code == COND_EXPR)
+       ? !is_gimple_condexpr (rhs1) : !is_gimple_val (rhs1))
       || !is_gimple_val (rhs2)
       || !is_gimple_val (rhs3))
     {
@@ -3657,7 +3784,7 @@ verify_gimple_assign_ternary (gimple stmt)
           && !FIXED_POINT_TYPE_P (rhs1_type))
          || !useless_type_conversion_p (rhs1_type, rhs2_type)
          || !useless_type_conversion_p (lhs_type, rhs3_type)
-         || 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type)
+         || 2 * TYPE_PRECISION (rhs1_type) > TYPE_PRECISION (lhs_type)
          || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))
        {
          error ("type mismatch in widening multiply-accumulate expression");
@@ -3683,6 +3810,72 @@ verify_gimple_assign_ternary (gimple stmt)
        }
       break;
 
+    case COND_EXPR:
+    case VEC_COND_EXPR:
+      if (!useless_type_conversion_p (lhs_type, rhs2_type)
+         || !useless_type_conversion_p (lhs_type, rhs3_type))
+       {
+         error ("type mismatch in conditional expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+      break;
+
+    case VEC_PERM_EXPR:
+      if (!useless_type_conversion_p (lhs_type, rhs1_type)
+         || !useless_type_conversion_p (lhs_type, rhs2_type))
+       {
+         error ("type mismatch in vector permute expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+         || TREE_CODE (rhs2_type) != VECTOR_TYPE
+         || TREE_CODE (rhs3_type) != VECTOR_TYPE)
+       {
+         error ("vector types expected in vector permute expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      if (TYPE_VECTOR_SUBPARTS (rhs1_type) != TYPE_VECTOR_SUBPARTS (rhs2_type)
+         || TYPE_VECTOR_SUBPARTS (rhs2_type)
+            != TYPE_VECTOR_SUBPARTS (rhs3_type)
+         || TYPE_VECTOR_SUBPARTS (rhs3_type)
+            != TYPE_VECTOR_SUBPARTS (lhs_type))
+       {
+         error ("vectors with different element number found "
+                "in vector permute expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      if (TREE_CODE (TREE_TYPE (rhs3_type)) != INTEGER_TYPE
+         || GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs3_type)))
+            != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs1_type))))
+       {
+         error ("invalid mask type in vector permute expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+
+      return false;
+
     case DOT_PROD_EXPR:
     case REALIGN_LOAD_EXPR:
       /* FIXME.  */
@@ -3799,26 +3992,10 @@ verify_gimple_assign_single (gimple stmt)
        }
       return res;
 
-    case COND_EXPR:
-      if (!is_gimple_reg (lhs)
-         || (!is_gimple_reg (TREE_OPERAND (rhs1, 0))
-             && !COMPARISON_CLASS_P (TREE_OPERAND (rhs1, 0)))
-         || (!is_gimple_reg (TREE_OPERAND (rhs1, 1))
-             && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 1)))
-         || (!is_gimple_reg (TREE_OPERAND (rhs1, 2))
-             && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 2))))
-       {
-         error ("invalid COND_EXPR in gimple assignment");
-         debug_generic_stmt (rhs1);
-         return true;
-       }
-      return res;
-
     case CONSTRUCTOR:
     case OBJ_TYPE_REF:
     case ASSERT_EXPR:
     case WITH_SIZE_EXPR:
-    case VEC_COND_EXPR:
       /* FIXME.  */
       return res;
 
@@ -3931,7 +4108,6 @@ verify_gimple_switch (gimple stmt)
   return false;
 }
 
-
 /* Verify a gimple debug statement STMT.
    Returns true if anything is wrong.  */
 
@@ -4032,6 +4208,9 @@ verify_gimple_stmt (gimple stmt)
     case GIMPLE_ASM:
       return false;
 
+    case GIMPLE_TRANSACTION:
+      return verify_gimple_transaction (stmt);
+
     /* Tuples that do not have tree operands.  */
     case GIMPLE_NOP:
     case GIMPLE_PREDICT:
@@ -4148,10 +4327,19 @@ verify_gimple_in_seq_2 (gimple_seq stmts)
          err |= verify_gimple_in_seq_2 (gimple_eh_filter_failure (stmt));
          break;
 
+       case GIMPLE_EH_ELSE:
+         err |= verify_gimple_in_seq_2 (gimple_eh_else_n_body (stmt));
+         err |= verify_gimple_in_seq_2 (gimple_eh_else_e_body (stmt));
+         break;
+
        case GIMPLE_CATCH:
          err |= verify_gimple_in_seq_2 (gimple_catch_handler (stmt));
          break;
 
+       case GIMPLE_TRANSACTION:
+         err |= verify_gimple_transaction (stmt);
+         break;
+
        default:
          {
            bool err2 = verify_gimple_stmt (stmt);
@@ -4165,6 +4353,18 @@ verify_gimple_in_seq_2 (gimple_seq stmts)
   return err;
 }
 
+/* Verify the contents of a GIMPLE_TRANSACTION.  Returns true if there
+   is a problem, otherwise false.  */
+
+static bool
+verify_gimple_transaction (gimple stmt)
+{
+  tree lab = gimple_transaction_label (stmt);
+  if (lab != NULL && TREE_CODE (lab) != LABEL_DECL)
+    return true;
+  return verify_gimple_in_seq_2 (gimple_transaction_body (stmt));
+}
+
 
 /* Verify the GIMPLE statements inside the statement list STMTS.  */
 
@@ -4929,6 +5129,13 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
        redirect_eh_dispatch_edge (stmt, e, dest);
       break;
 
+    case GIMPLE_TRANSACTION:
+      /* The ABORT edge has a stored label associated with it, otherwise
+        the edges are simply redirectable.  */
+      if (e->flags == 0)
+       gimple_transaction_set_label (stmt, gimple_block_label (dest));
+      break;
+
     default:
       /* Otherwise it must be a fallthru edge, and we don't need to
         do anything besides redirecting it.  */
@@ -5084,6 +5291,12 @@ gimple_duplicate_bb (basic_block bb)
       if (gimple_code (stmt) == GIMPLE_LABEL)
        continue;
 
+      /* Don't duplicate label debug stmts.  */
+      if (gimple_debug_bind_p (stmt)
+         && TREE_CODE (gimple_debug_bind_get_var (stmt))
+            == LABEL_DECL)
+       continue;
+
       /* Create a new copy of STMT and duplicate STMT's virtual
         operands.  */
       copy = gimple_copy (stmt);
@@ -6305,8 +6518,10 @@ dump_function_to_file (tree fn, FILE *file, int flags)
   bool ignore_topmost_bind = false, any_var = false;
   basic_block bb;
   tree chain;
+  bool tmclone = TREE_CODE (fn) == FUNCTION_DECL && decl_is_tm_clone (fn);
 
-  fprintf (file, "%s (", lang_hooks.decl_printable_name (fn, 2));
+  fprintf (file, "%s %s(", lang_hooks.decl_printable_name (fn, 2),
+          tmclone ? "[tm-clone] " : "");
 
   arg = DECL_ARGUMENTS (fn);
   while (arg)