OSDN Git Service

* tree-cfg.c (verify_eh_throw_stmt_node): Return nonzero,
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index ce0649d..62a4e89 100644 (file)
@@ -658,9 +658,15 @@ make_cond_expr_edges (basic_block bb)
 
   e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
   e->goto_locus = gimple_location (then_stmt);
+  if (e->goto_locus)
+    e->goto_block = gimple_block (then_stmt);
   e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
   if (e)
-    e->goto_locus = gimple_location (else_stmt);
+    {
+      e->goto_locus = gimple_location (else_stmt);
+      if (e->goto_locus)
+       e->goto_block = gimple_block (else_stmt);
+    }
 
   /* We do not need the labels anymore.  */
   gimple_cond_set_true_label (entry, NULL_TREE);
@@ -849,6 +855,8 @@ make_goto_expr_edges (basic_block bb)
       tree dest = gimple_goto_dest (goto_t);
       edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
       e->goto_locus = gimple_location (goto_t);
+      if (e->goto_locus)
+       e->goto_block = gimple_block (goto_t);
       gsi_remove (&last, true);
       return;
     }
@@ -1997,6 +2005,18 @@ remove_useless_stmts_1 (gimple_stmt_iterator *gsi, struct rus_data *data)
           }
           break;
 
+        case GIMPLE_CHANGE_DYNAMIC_TYPE:
+         /* If we do not optimize remove GIMPLE_CHANGE_DYNAMIC_TYPE as
+            expansion is confused about them and we only remove them
+            during alias computation otherwise.  */
+         if (!optimize)
+           {
+             data->last_was_goto = false;
+             gsi_remove (gsi, false);
+             break;
+           }
+         /* Fallthru.  */
+
         default:
           data->last_was_goto = false;
           gsi_next (gsi);
@@ -2052,14 +2072,9 @@ struct gimple_opt_pass pass_remove_useless_stmts =
 static void
 remove_phi_nodes_and_edges_for_unreachable_block (basic_block bb)
 {
-  gimple_stmt_iterator gsi;
-
   /* Since this block is no longer reachable, we can just delete all
      of its PHI nodes.  */
-  for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); )
-    remove_phi_node (&gsi, true);
-
-  set_phi_nodes (bb, NULL);
+  remove_phi_nodes (bb);
 
   /* Remove edges to BB's successors.  */
   while (EDGE_COUNT (bb->succs) > 0)
@@ -3035,14 +3050,17 @@ verify_types_in_gimple_min_lval (tree expr)
   if (is_gimple_id (expr))
     return false;
 
-  if (TREE_CODE (expr) != INDIRECT_REF
-      && TREE_CODE (expr) != ALIGN_INDIRECT_REF
-      && TREE_CODE (expr) != MISALIGNED_INDIRECT_REF)
+  if (!INDIRECT_REF_P (expr)
+      && TREE_CODE (expr) != TARGET_MEM_REF)
     {
       error ("invalid expression for min lvalue");
       return true;
     }
 
+  /* TARGET_MEM_REFs are strange beasts.  */
+  if (TREE_CODE (expr) == TARGET_MEM_REF)
+    return false;
+
   op = TREE_OPERAND (expr, 0);
   if (!is_gimple_val (op))
     {
@@ -3131,6 +3149,9 @@ verify_types_in_gimple_reference (tree expr)
       /* For VIEW_CONVERT_EXPRs which are allowed here, too, there
         is nothing to verify.  Gross mismatches at most invoke
         undefined behavior.  */
+      if (TREE_CODE (expr) == VIEW_CONVERT_EXPR
+         && !handled_component_p (op))
+       return false;
 
       expr = op;
     }
@@ -3168,107 +3189,139 @@ valid_fixed_convert_types_p (tree type1, tree type2)
              || FIXED_POINT_TYPE_P (type2)));
 }
 
-/* Verify that OP is a valid GIMPLE operand.  Return true if there is
-   an error, false otherwise.  */
-
-static bool
-verify_types_in_gimple_op (tree op)
-{
-  if (!is_gimple_val (op) && !is_gimple_lvalue (op))
-    {
-      error ("Invalid GIMPLE operand");
-      debug_generic_expr (op);
-      return true;
-    }
-
-  return false;
-}
-
-
 /* Verify the contents of a GIMPLE_CALL STMT.  Returns true when there
    is a problem, otherwise false.  */
 
 static bool
-verify_types_in_gimple_call (gimple stmt)
+verify_gimple_call (gimple stmt)
 {
-  bool failed = false;
-  unsigned int i;
-  tree fn;
+  tree fn = gimple_call_fn (stmt);
+  tree fntype;
 
-  if (gimple_call_lhs (stmt))
-    failed |= verify_types_in_gimple_op (gimple_call_lhs (stmt));
+  if (!POINTER_TYPE_P (TREE_TYPE  (fn))
+      || (TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != FUNCTION_TYPE
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != METHOD_TYPE))
+    {
+      error ("non-function in gimple call");
+      return true;
+    }
 
-  fn = gimple_call_fn (stmt);
-  if (TREE_CODE (fn) != OBJ_TYPE_REF
-      && verify_types_in_gimple_op (fn))
-    failed = true;
+  if (gimple_call_lhs (stmt)
+      && !is_gimple_lvalue (gimple_call_lhs (stmt)))
+    {
+      error ("invalid LHS in gimple call");
+      return true;
+    }
 
-  if (gimple_call_chain (stmt))
-    failed |= verify_types_in_gimple_op (gimple_call_chain (stmt));
+  fntype = TREE_TYPE (TREE_TYPE (fn));
+  if (gimple_call_lhs (stmt)
+      && !useless_type_conversion_p (TREE_TYPE (gimple_call_lhs (stmt)),
+                                    TREE_TYPE (fntype))
+      /* ???  At least C++ misses conversions at assignments from
+        void * call results.
+        ???  Java is completely off.  Especially with functions
+        returning java.lang.Object.
+        For now simply allow arbitrary pointer type conversions.  */
+      && !(POINTER_TYPE_P (TREE_TYPE (gimple_call_lhs (stmt)))
+          && POINTER_TYPE_P (TREE_TYPE (fntype))))
+    {
+      error ("invalid conversion in gimple call");
+      debug_generic_stmt (TREE_TYPE (gimple_call_lhs (stmt)));
+      debug_generic_stmt (TREE_TYPE (fntype));
+      return true;
+    }
 
-  for (i = 0; i < gimple_call_num_args (stmt); i++)
-    failed |= verify_types_in_gimple_op (gimple_call_arg (stmt,i));
+  /* ???  The C frontend passes unpromoted arguments in case it
+     didn't see a function declaration before the call.  So for now
+     leave the call arguments unverified.  Once we gimplify
+     unit-at-a-time we have a chance to fix this.  */
 
-  return failed;
+  return false;
 }
 
-
-/* Verify the contents of a GIMPLE_COND STMT.  Returns true when there
-   is a problem, otherwise false.  */
+/* Verifies the gimple comparison with the result type TYPE and
+   the operands OP0 and OP1.  */
 
 static bool
-verify_types_in_gimple_cond (gimple stmt)
+verify_gimple_comparison (tree type, tree op0, tree op1)
 {
-  bool failed = false;
-  
-  failed |= verify_types_in_gimple_op (gimple_cond_lhs (stmt));
-  failed |= verify_types_in_gimple_op (gimple_cond_rhs (stmt));
-  failed |= verify_types_in_gimple_op (gimple_cond_true_label (stmt));
-  failed |= verify_types_in_gimple_op (gimple_cond_false_label (stmt));
+  tree op0_type = TREE_TYPE (op0);
+  tree op1_type = TREE_TYPE (op1);
 
-  return failed;
-}
+  if (!is_gimple_val (op0) || !is_gimple_val (op1))
+    {
+      error ("invalid operands in gimple comparison");
+      return true;
+    }
 
+  /* For comparisons we do not have the operations type as the
+     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))
+    {
+      error ("type mismatch in comparison expression");
+      debug_generic_expr (type);
+      debug_generic_expr (op0_type);
+      debug_generic_expr (op1_type);
+      return true;
+    }
 
-/* Verify the contents of a GIMPLE_ASSIGN STMT.  Returns true when there
-   is a problem, otherwise false.
+  return false;
+}
 
-   Verify that the types of the LHS and the RHS operands are
-   compatible.  This verification largely depends on what kind of
-   operation is done on the RHS of the assignment.  It is not always
-   the case that all the types of the operands must match (e.g., 'a =
-   (unsigned long) b' or 'ptr = ptr + 1').  */
+/* Verify a gimple assignment statement STMT with an unary rhs.
+   Returns true if anything is wrong.  */
 
 static bool
-verify_types_in_gimple_assign (gimple stmt)
+verify_gimple_assign_unary (gimple stmt)
 {
   enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
   tree lhs = gimple_assign_lhs (stmt);
-  tree rhs1 = gimple_assign_rhs1 (stmt);
-  tree rhs2 = (gimple_num_ops (stmt) == 3) ? gimple_assign_rhs2 (stmt) : NULL;
   tree lhs_type = TREE_TYPE (lhs);
+  tree rhs1 = gimple_assign_rhs1 (stmt);
   tree rhs1_type = TREE_TYPE (rhs1);
-  tree rhs2_type = (rhs2) ? TREE_TYPE (rhs2) : NULL;
 
-  /* Special codes we cannot handle via their class.  */
+  if (!is_gimple_reg (lhs)
+      && !(optimize == 0
+          && TREE_CODE (lhs_type) == COMPLEX_TYPE))
+    {
+      error ("non-register as LHS of unary operation");
+      return true;
+    }
+
+  if (!is_gimple_val (rhs1))
+    {
+      error ("invalid operand in unary operation");
+      return true;
+    }
+
+  /* First handle conversions.  */
   switch (rhs_code)
     {
     CASE_CONVERT:
       {
-       if (!is_gimple_val (rhs1))
-         {
-           error ("invalid operand in conversion");
-           return true;
-         }
-
        /* Allow conversions between integral types and pointers only if
-          there is no sign or zero extension involved.  */
-       if (((POINTER_TYPE_P (lhs_type) && INTEGRAL_TYPE_P (rhs1_type))
-            || (POINTER_TYPE_P (rhs1_type) && INTEGRAL_TYPE_P (lhs_type)))
-           && (TYPE_PRECISION (lhs_type) == TYPE_PRECISION (rhs1_type)
-               /* For targets were the precision of sizetype doesn't
-                  match that of pointers we need the following.  */
-               || lhs_type == sizetype || rhs1_type == sizetype))
+          there is no sign or zero extension involved.
+          For targets were the precision of sizetype doesn't match that
+          of pointers we need to allow arbitrary conversions from and
+          to sizetype.  */
+       if ((POINTER_TYPE_P (lhs_type)
+            && INTEGRAL_TYPE_P (rhs1_type)
+            && (TYPE_PRECISION (lhs_type) >= TYPE_PRECISION (rhs1_type)
+                || rhs1_type == sizetype))
+           || (POINTER_TYPE_P (rhs1_type)
+               && INTEGRAL_TYPE_P (lhs_type)
+               && (TYPE_PRECISION (rhs1_type) >= TYPE_PRECISION (lhs_type)
+                   || lhs_type == sizetype)))
          return false;
 
        /* Allow conversion from integer to offset type and vice versa.  */
@@ -3293,12 +3346,6 @@ verify_types_in_gimple_assign (gimple stmt)
 
     case FIXED_CONVERT_EXPR:
       {
-       if (!is_gimple_val (rhs1))
-         {
-           error ("invalid operand in conversion");
-           return true;
-         }
-
        if (!valid_fixed_convert_types_p (lhs_type, rhs1_type)
            && !valid_fixed_convert_types_p (rhs1_type, lhs_type))
          {
@@ -3313,12 +3360,6 @@ verify_types_in_gimple_assign (gimple stmt)
 
     case FLOAT_EXPR:
       {
-       if (!is_gimple_val (rhs1))
-         {
-           error ("invalid operand in int to float conversion");
-           return true;
-         }
-
        if (!INTEGRAL_TYPE_P (rhs1_type) || !SCALAR_FLOAT_TYPE_P (lhs_type))
          {
            error ("invalid types in conversion to floating point");
@@ -3332,12 +3373,6 @@ verify_types_in_gimple_assign (gimple stmt)
 
     case FIX_TRUNC_EXPR:
       {
-       if (!is_gimple_val (rhs1))
-         {
-           error ("invalid operand in float to int conversion");
-           return true;
-         }
-
        if (!INTEGRAL_TYPE_P (lhs_type) || !SCALAR_FLOAT_TYPE_P (rhs1_type))
          {
            error ("invalid types in conversion to integer");
@@ -3349,18 +3384,79 @@ verify_types_in_gimple_assign (gimple stmt)
         return false;
       }
 
-    case COMPLEX_EXPR:
+    case TRUTH_NOT_EXPR:
       {
-       if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2))
-         {
-           error ("invalid operands in complex expression");
-           return true;
-         }
+      }
+
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case BIT_NOT_EXPR:
+    case PAREN_EXPR:
+    case NON_LVALUE_EXPR:
+    case CONJ_EXPR:
+    case REDUC_MAX_EXPR:
+    case REDUC_MIN_EXPR:
+    case REDUC_PLUS_EXPR:
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_LO_EXPR:
+    case VEC_UNPACK_FLOAT_HI_EXPR:
+    case VEC_UNPACK_FLOAT_LO_EXPR:
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  /* For the remaining codes assert there is no conversion involved.  */
+  if (!useless_type_conversion_p (lhs_type, rhs1_type))
+    {
+      error ("non-trivial conversion in unary operation");
+      debug_generic_expr (lhs_type);
+      debug_generic_expr (rhs1_type);
+      return true;
+    }
+
+  return false;
+}
+
+/* Verify a gimple assignment statement STMT with a binary rhs.
+   Returns true if anything is wrong.  */
 
-       if (!TREE_CODE (lhs_type) == COMPLEX_TYPE
-           || !(TREE_CODE (rhs1_type) == INTEGER_TYPE
+static bool
+verify_gimple_assign_binary (gimple stmt)
+{
+  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
+  tree lhs = gimple_assign_lhs (stmt);
+  tree lhs_type = TREE_TYPE (lhs);
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  tree rhs1_type = TREE_TYPE (rhs1);
+  tree rhs2 = gimple_assign_rhs2 (stmt);
+  tree rhs2_type = TREE_TYPE (rhs2);
+
+  if (!is_gimple_reg (lhs)
+      && !(optimize == 0
+          && TREE_CODE (lhs_type) == COMPLEX_TYPE))
+    {
+      error ("non-register as LHS of binary operation");
+      return true;
+    }
+
+  if (!is_gimple_val (rhs1)
+      || !is_gimple_val (rhs2))
+    {
+      error ("invalid operands in binary operation");
+      return true;
+    }
+
+  /* First handle operations that involve different types.  */
+  switch (rhs_code)
+    {
+    case COMPLEX_EXPR:
+      {
+       if (TREE_CODE (lhs_type) != COMPLEX_TYPE
+           || !(INTEGRAL_TYPE_P (rhs1_type)
                 || SCALAR_FLOAT_TYPE_P (rhs1_type))
-           || !(TREE_CODE (rhs2_type) == INTEGER_TYPE
+           || !(INTEGRAL_TYPE_P (rhs2_type)
                 || SCALAR_FLOAT_TYPE_P (rhs2_type)))
          {
            error ("type mismatch in complex expression");
@@ -3373,26 +3469,13 @@ verify_types_in_gimple_assign (gimple stmt)
        return false;
       }
 
-    case CONSTRUCTOR:
-      {
-       /* In this context we know that we are on the RHS of an
-          assignment, so CONSTRUCTOR operands are OK.  */
-       /* FIXME: verify constructor arguments.  */
-       return false;
-      }
-
     case LSHIFT_EXPR:
     case RSHIFT_EXPR:
     case LROTATE_EXPR:
     case RROTATE_EXPR:
       {
-       if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2))
-         {
-           error ("invalid operands in shift expression");
-           return true;
-         }
-
-       if (!TREE_CODE (rhs1_type) == INTEGER_TYPE
+       if (!INTEGRAL_TYPE_P (rhs1_type)
+           || !INTEGRAL_TYPE_P (rhs2_type)
            || !useless_type_conversion_p (lhs_type, rhs1_type))
          {
            error ("type mismatch in shift expression");
@@ -3405,28 +3488,28 @@ verify_types_in_gimple_assign (gimple stmt)
        return false;
       }
 
-    case PLUS_EXPR:
-    case MINUS_EXPR:
+    case VEC_LSHIFT_EXPR:
+    case VEC_RSHIFT_EXPR:
       {
-       if (POINTER_TYPE_P (lhs_type)
-           || POINTER_TYPE_P (rhs1_type)
-           || POINTER_TYPE_P (rhs2_type))
+       if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+           || !INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type))
+           || (!INTEGRAL_TYPE_P (rhs2_type)
+               && (TREE_CODE (rhs2_type) != VECTOR_TYPE
+                   || !INTEGRAL_TYPE_P (TREE_TYPE (rhs2_type))))
+           || !useless_type_conversion_p (lhs_type, rhs1_type))
          {
-           error ("invalid (pointer) operands to plus/minus");
+           error ("type mismatch in vector shift expression");
+           debug_generic_expr (lhs_type);
+           debug_generic_expr (rhs1_type);
+           debug_generic_expr (rhs2_type);
            return true;
          }
 
-       /* Continue with generic binary expression handling.  */
-       break;
+       return false;
       }
 
     case POINTER_PLUS_EXPR:
       {
-       if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2))
-         {
-           error ("invalid operands in pointer plus expression");
-           return true;
-         }
        if (!POINTER_TYPE_P (rhs1_type)
            || !useless_type_conversion_p (lhs_type, rhs1_type)
            || !useless_type_conversion_p (sizetype, rhs2_type))
@@ -3441,30 +3524,6 @@ verify_types_in_gimple_assign (gimple stmt)
        return false;
       } 
 
-    case ADDR_EXPR:
-      {
-       tree op = TREE_OPERAND (rhs1, 0);
-       if (!is_gimple_addressable (op))
-         {
-           error ("invalid operand in unary expression");
-           return true;
-         }
-
-       if (!one_pointer_to_useless_type_conversion_p (lhs_type, TREE_TYPE (op))
-           /* FIXME: a longstanding wart, &a == &a[0].  */
-           && (TREE_CODE (TREE_TYPE (op)) != ARRAY_TYPE
-               || !one_pointer_to_useless_type_conversion_p (lhs_type,
-                     TREE_TYPE (TREE_TYPE (op)))))
-         {
-           error ("type mismatch in address expression");
-           debug_generic_stmt (lhs_type);
-           debug_generic_stmt (TYPE_POINTER_TO (TREE_TYPE (op)));
-           return true;
-         }
-
-       return verify_types_in_gimple_reference (TREE_OPERAND (rhs1, 0));
-      }
-
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
       gcc_unreachable ();
@@ -3473,12 +3532,6 @@ verify_types_in_gimple_assign (gimple stmt)
     case TRUTH_OR_EXPR:
     case TRUTH_XOR_EXPR:
       {
-       if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2))
-         {
-           error ("invalid operands in truth expression");
-           return true;
-         }
-
        /* We allow any kind of integral typed argument and result.  */
        if (!INTEGRAL_TYPE_P (rhs1_type)
            || !INTEGRAL_TYPE_P (rhs2_type)
@@ -3494,162 +3547,297 @@ verify_types_in_gimple_assign (gimple stmt)
        return false;
       }
 
-    case TRUTH_NOT_EXPR:
-      {
-       if (!is_gimple_val (rhs1))
-         {
-           error ("invalid operand in unary not");
-           return true;
-         }
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case LTGT_EXPR:
+      /* Comparisons are also binary, but the result type is not
+        connected to the operand types.  */
+      return verify_gimple_comparison (lhs_type, rhs1, rhs2);
 
-       /* For TRUTH_NOT_EXPR we can have any kind of integral
-          typed arguments and results.  */
-       if (!INTEGRAL_TYPE_P (rhs1_type)
-           || !INTEGRAL_TYPE_P (lhs_type))
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      {
+       if (POINTER_TYPE_P (lhs_type)
+           || POINTER_TYPE_P (rhs1_type)
+           || POINTER_TYPE_P (rhs2_type))
          {
-           error ("type mismatch in not expression");
-           debug_generic_expr (lhs_type);
-           debug_generic_expr (rhs1_type);
+           error ("invalid (pointer) operands to plus/minus");
            return true;
          }
 
-       return false;
-      }
-
-    /* After gimplification we should not have any of these.  */
-    case ASM_EXPR:
-    case BIND_EXPR:
-    case CALL_EXPR:
-    case COND_EXPR:
-    case TREE_LIST:
-    case COMPOUND_EXPR:
-    case MODIFY_EXPR:
-    case INIT_EXPR:
-    case GOTO_EXPR:
-    case LABEL_EXPR:
-    case RETURN_EXPR:
-    case TRY_FINALLY_EXPR:
-    case TRY_CATCH_EXPR:
-    case EH_FILTER_EXPR:
-    case STATEMENT_LIST:
-      {
-       error ("tree node that should already be gimple.");
-       return true;
+       /* Continue with generic binary expression handling.  */
+       break;
       }
 
-    case OBJ_TYPE_REF:
-      /* FIXME.  */
-      return false;
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+    case WIDEN_SUM_EXPR:
+    case WIDEN_MULT_EXPR:
+    case VEC_WIDEN_MULT_HI_EXPR:
+    case VEC_WIDEN_MULT_LO_EXPR:
+    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:
+      /* Continue with generic binary expression handling.  */
+      break;
 
-    default:;
+    default:
+      gcc_unreachable ();
     }
 
-  /* Generic handling via classes.  */
-  switch (TREE_CODE_CLASS (rhs_code))
+  if (!useless_type_conversion_p (lhs_type, rhs1_type)
+      || !useless_type_conversion_p (lhs_type, rhs2_type))
     {
-    case tcc_exceptional: /* for SSA_NAME */
-    case tcc_unary:
-      if (!useless_type_conversion_p (lhs_type, rhs1_type))
-       {
-         error ("non-trivial conversion at assignment");
-         debug_generic_expr (lhs_type);
-         debug_generic_expr (rhs1_type);
-         return true;
-       }
-      break;
+      error ("type mismatch in binary expression");
+      debug_generic_stmt (lhs_type);
+      debug_generic_stmt (rhs1_type);
+      debug_generic_stmt (rhs2_type);
+      return true;
+    }
 
-    case tcc_binary:
-      if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2))
-       {
-         error ("invalid operands in binary expression");
-         return true;
-       }
-      if (!useless_type_conversion_p (lhs_type, rhs1_type)
-         || !useless_type_conversion_p (lhs_type, rhs2_type))
-       {
-         error ("type mismatch in binary expression");
-         debug_generic_stmt (lhs_type);
-         debug_generic_stmt (rhs1_type);
-         debug_generic_stmt (rhs2_type);
-         return true;
-       }
-      break;
+  return false;
+}
 
-    case tcc_reference:
-      /* All tcc_reference trees are GIMPLE_SINGLE_RHS.  Verify that
-         no implicit type change happens here.  */
-      if (!useless_type_conversion_p (lhs_type, rhs1_type))
-       {
-         error ("non-trivial conversion at assignment");
-         debug_generic_expr (lhs_type);
-         debug_generic_expr (rhs1_type);
-         return true;
-       }
-      return verify_types_in_gimple_reference (rhs1);
+/* Verify a gimple assignment statement STMT with a single rhs.
+   Returns true if anything is wrong.  */
+
+static bool
+verify_gimple_assign_single (gimple stmt)
+{
+  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
+  tree lhs = gimple_assign_lhs (stmt);
+  tree lhs_type = TREE_TYPE (lhs);
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  tree rhs1_type = TREE_TYPE (rhs1);
+  bool res = false;
 
-    case tcc_comparison:
+  if (!useless_type_conversion_p (lhs_type, rhs1_type))
+    {
+      error ("non-trivial conversion at assignment");
+      debug_generic_expr (lhs_type);
+      debug_generic_expr (rhs1_type);
+      return true;
+    }
+
+  if (handled_component_p (lhs))
+    res |= verify_types_in_gimple_reference (lhs);
+
+  /* Special codes we cannot handle via their class.  */
+  switch (rhs_code)
+    {
+    case ADDR_EXPR:
       {
-       if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2))
+       tree op = TREE_OPERAND (rhs1, 0);
+       if (!is_gimple_addressable (op))
          {
-           error ("invalid operands in comparison expression");
+           error ("invalid operand in unary expression");
            return true;
          }
 
-       /* For comparisons we do not have the operations type as the
-          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 (rhs1_type, rhs2_type)
-            && !useless_type_conversion_p (rhs2_type, rhs1_type)
-            && (!POINTER_TYPE_P (rhs1_type)
-                || !POINTER_TYPE_P (rhs2_type)
-                || TYPE_MODE (rhs1_type) != TYPE_MODE (rhs2_type)))
-           || !INTEGRAL_TYPE_P (lhs_type))
+       if (!one_pointer_to_useless_type_conversion_p (lhs_type, TREE_TYPE (op))
+           /* FIXME: a longstanding wart, &a == &a[0].  */
+           && (TREE_CODE (TREE_TYPE (op)) != ARRAY_TYPE
+               || !one_pointer_to_useless_type_conversion_p (lhs_type,
+                     TREE_TYPE (TREE_TYPE (op)))))
          {
-           error ("type mismatch in comparison expression");
-           debug_generic_expr (lhs_type);
-           debug_generic_expr (rhs1_type);
-           debug_generic_expr (rhs2_type);
+           error ("type mismatch in address expression");
+           debug_generic_stmt (lhs_type);
+           debug_generic_stmt (TYPE_POINTER_TO (TREE_TYPE (op)));
            return true;
          }
-        break;
+
+       return verify_types_in_gimple_reference (op);
       }
 
+    /* tcc_reference  */
+    case COMPONENT_REF:
+    case BIT_FIELD_REF:
+    case INDIRECT_REF:
+    case ALIGN_INDIRECT_REF:
+    case MISALIGNED_INDIRECT_REF:
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case VIEW_CONVERT_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case TARGET_MEM_REF:
+      if (!is_gimple_reg (lhs)
+         && is_gimple_reg_type (TREE_TYPE (lhs)))
+       {
+         error ("invalid rhs for gimple memory store");
+         debug_generic_stmt (lhs);
+         debug_generic_stmt (rhs1);
+         return true;
+       }
+      return res || verify_types_in_gimple_reference (rhs1);
+
+    /* tcc_constant  */
+    case SSA_NAME:
+    case INTEGER_CST:
+    case REAL_CST:
+    case FIXED_CST:
+    case COMPLEX_CST:
+    case VECTOR_CST:
+    case STRING_CST:
+      return res;
+
+    /* tcc_declaration  */
+    case CONST_DECL:
+      return res;
+    case VAR_DECL:
+    case PARM_DECL:
+      if (!is_gimple_reg (lhs)
+         && !is_gimple_reg (rhs1)
+         && is_gimple_reg_type (TREE_TYPE (lhs)))
+       {
+         error ("invalid rhs for gimple memory store");
+         debug_generic_stmt (lhs);
+         debug_generic_stmt (rhs1);
+         return true;
+       }
+      return res;
+
+    case COND_EXPR:
+    case CONSTRUCTOR:
+    case OBJ_TYPE_REF:
+    case ASSERT_EXPR:
+    case WITH_SIZE_EXPR:
+    case EXC_PTR_EXPR:
+    case FILTER_EXPR:
+    case POLYNOMIAL_CHREC:
+    case DOT_PROD_EXPR:
+    case VEC_COND_EXPR:
+    case REALIGN_LOAD_EXPR:
+      /* FIXME.  */
+      return res;
+
     default:;
     }
 
-  return false;
+  return res;
 }
 
+/* Verify the contents of a GIMPLE_ASSIGN STMT.  Returns true when there
+   is a problem, otherwise false.  */
+
+static bool
+verify_gimple_assign (gimple stmt)
+{
+  switch (gimple_assign_rhs_class (stmt))
+    {
+    case GIMPLE_SINGLE_RHS:
+      return verify_gimple_assign_single (stmt);
+
+    case GIMPLE_UNARY_RHS:
+      return verify_gimple_assign_unary (stmt);
+
+    case GIMPLE_BINARY_RHS:
+      return verify_gimple_assign_binary (stmt);
+
+    default:
+      gcc_unreachable ();
+    }
+}
 
 /* Verify the contents of a GIMPLE_RETURN STMT.  Returns true when there
    is a problem, otherwise false.  */
 
 static bool
-verify_types_in_gimple_return (gimple stmt)
+verify_gimple_return (gimple stmt)
 {
   tree op = gimple_return_retval (stmt);
+  tree restype = TREE_TYPE (TREE_TYPE (cfun->decl));
 
+  /* We cannot test for present return values as we do not fix up missing
+     return values from the original source.  */
   if (op == NULL)
     return false;
-  
-  return verify_types_in_gimple_op (op);
+  if (!is_gimple_val (op)
+      && TREE_CODE (op) != RESULT_DECL)
+    {
+      error ("invalid operand in return statement");
+      debug_generic_stmt (op);
+      return true;
+    }
+
+  if (!useless_type_conversion_p (restype, TREE_TYPE (op))
+      /* ???  With C++ we can have the situation that the result
+        decl is a reference type while the return type is an aggregate.  */
+      && !(TREE_CODE (op) == RESULT_DECL
+          && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE
+          && useless_type_conversion_p (restype, TREE_TYPE (TREE_TYPE (op)))))
+    {
+      error ("invalid conversion in return statement");
+      debug_generic_stmt (restype);
+      debug_generic_stmt (TREE_TYPE (op));
+      return true;
+    }
+
+  return false;
 }
 
 
+/* Verify the contents of a GIMPLE_GOTO STMT.  Returns true when there
+   is a problem, otherwise false.  */
+
+static bool
+verify_gimple_goto (gimple stmt)
+{
+  tree dest = gimple_goto_dest (stmt);
+
+  /* ???  We have two canonical forms of direct goto destinations, a
+     bare LABEL_DECL and an ADDR_EXPR of a LABEL_DECL.  */
+  if (TREE_CODE (dest) != LABEL_DECL
+      && (!is_gimple_val (dest)
+         || !POINTER_TYPE_P (TREE_TYPE (dest))))
+    {
+      error ("goto destination is neither a label nor a pointer");
+      return true;
+    }
+
+  return false;
+}
+
 /* Verify the contents of a GIMPLE_SWITCH STMT.  Returns true when there
    is a problem, otherwise false.  */
 
 static bool
-verify_types_in_gimple_switch (gimple stmt)
+verify_gimple_switch (gimple stmt)
 {
   if (!is_gimple_val (gimple_switch_index (stmt)))
     {
       error ("invalid operand to switch statement");
-      debug_generic_expr (gimple_switch_index (stmt));
+      debug_generic_stmt (gimple_switch_index (stmt));
       return true;
     }
 
@@ -3661,16 +3849,37 @@ verify_types_in_gimple_switch (gimple stmt)
    and false otherwise.  */
 
 static bool
-verify_types_in_gimple_phi (gimple stmt)
+verify_gimple_phi (gimple stmt)
 {
-  size_t i;
+  tree type = TREE_TYPE (gimple_phi_result (stmt));
+  unsigned i;
 
-  if (verify_types_in_gimple_op (gimple_phi_result (stmt)))
-    return true;
+  if (!is_gimple_variable (gimple_phi_result (stmt)))
+    {
+      error ("Invalid PHI result");
+      return true;
+    }
 
   for (i = 0; i < gimple_phi_num_args (stmt); i++)
-    if (verify_types_in_gimple_op (gimple_phi_arg_def (stmt, i)))
-      return true;
+    {
+      tree arg = gimple_phi_arg_def (stmt, i);
+      if ((is_gimple_reg (gimple_phi_result (stmt))
+          && !is_gimple_val (arg))
+         || (!is_gimple_reg (gimple_phi_result (stmt))
+             && !is_gimple_addressable (arg)))
+       {
+         error ("Invalid PHI argument");
+         debug_generic_stmt (arg);
+         return true;
+       }
+      if (!useless_type_conversion_p (type, TREE_TYPE (arg)))
+       {
+         error ("Incompatible types in PHI argument");
+         debug_generic_stmt (type);
+         debug_generic_stmt (TREE_TYPE (arg));
+         return true;
+       }
+    }
 
   return false;
 }
@@ -3696,38 +3905,43 @@ verify_types_in_gimple_stmt (gimple stmt)
   switch (gimple_code (stmt))
     {
     case GIMPLE_ASSIGN:
-      return verify_types_in_gimple_assign (stmt);
+      return verify_gimple_assign (stmt);
 
     case GIMPLE_LABEL:
       return TREE_CODE (gimple_label_label (stmt)) != LABEL_DECL;
 
     case GIMPLE_CALL:
-      return verify_types_in_gimple_call (stmt);
+      return verify_gimple_call (stmt);
 
     case GIMPLE_COND:
-      return verify_types_in_gimple_cond (stmt);
+      return verify_gimple_comparison (boolean_type_node,
+                                      gimple_cond_lhs (stmt),
+                                      gimple_cond_rhs (stmt));
 
     case GIMPLE_GOTO:
-      return verify_types_in_gimple_op (gimple_goto_dest (stmt));
-
-    case GIMPLE_NOP:
-    case GIMPLE_PREDICT:
-      return false;
+      return verify_gimple_goto (stmt);
 
     case GIMPLE_SWITCH:
-      return verify_types_in_gimple_switch (stmt);
+      return verify_gimple_switch (stmt);
 
     case GIMPLE_RETURN:
-      return verify_types_in_gimple_return (stmt);
+      return verify_gimple_return (stmt);
 
     case GIMPLE_ASM:
       return false;
 
     case GIMPLE_CHANGE_DYNAMIC_TYPE:
-      return verify_types_in_gimple_op (gimple_cdt_location (stmt));
+      return (!is_gimple_val (gimple_cdt_location (stmt))
+             || !POINTER_TYPE_P (TREE_TYPE (gimple_cdt_location (stmt))));
 
     case GIMPLE_PHI:
-      return verify_types_in_gimple_phi (stmt);
+      return verify_gimple_phi (stmt);
+
+    /* Tuples that do not have tree operands.  */
+    case GIMPLE_NOP:
+    case GIMPLE_RESX:
+    case GIMPLE_PREDICT:
+      return false;
 
     default:
       gcc_unreachable ();
@@ -3748,44 +3962,22 @@ verify_types_in_gimple_seq_2 (gimple_seq stmts)
 
       switch (gimple_code (stmt))
         {
-          case GIMPLE_BIND:
-            err |= verify_types_in_gimple_seq_2 (gimple_bind_body (stmt));
-            break;
-
-          case GIMPLE_TRY:
-            err |= verify_types_in_gimple_seq_2 (gimple_try_eval (stmt));
-            err |= verify_types_in_gimple_seq_2 (gimple_try_cleanup (stmt));
-            break;
-
-          case GIMPLE_EH_FILTER:
-            err |= verify_types_in_gimple_seq_2
-                    (gimple_eh_filter_failure (stmt));
-            break;
-
-          case GIMPLE_CATCH:
-             err |= verify_types_in_gimple_seq_2 (gimple_catch_handler (stmt));
-             break;
-
-         case GIMPLE_OMP_CRITICAL:
-          case GIMPLE_OMP_CONTINUE:
-          case GIMPLE_OMP_MASTER:
-          case GIMPLE_OMP_ORDERED:
-          case GIMPLE_OMP_SECTION:
-          case GIMPLE_OMP_FOR:
-          case GIMPLE_OMP_PARALLEL:
-         case GIMPLE_OMP_TASK:
-          case GIMPLE_OMP_SECTIONS:
-          case GIMPLE_OMP_SINGLE:
-         case GIMPLE_OMP_ATOMIC_STORE:
-         case GIMPLE_OMP_ATOMIC_LOAD:
-            break;
-
-         /* Tuples that do not have trees.  */
-          case GIMPLE_NOP:
-          case GIMPLE_RESX:
-          case GIMPLE_OMP_RETURN:
-         case GIMPLE_PREDICT:
-            break;
+       case GIMPLE_BIND:
+         err |= verify_types_in_gimple_seq_2 (gimple_bind_body (stmt));
+         break;
+
+       case GIMPLE_TRY:
+         err |= verify_types_in_gimple_seq_2 (gimple_try_eval (stmt));
+         err |= verify_types_in_gimple_seq_2 (gimple_try_cleanup (stmt));
+         break;
+
+       case GIMPLE_EH_FILTER:
+         err |= verify_types_in_gimple_seq_2 (gimple_eh_filter_failure (stmt));
+         break;
+
+       case GIMPLE_CATCH:
+         err |= verify_types_in_gimple_seq_2 (gimple_catch_handler (stmt));
+         break;
 
        default:
          {
@@ -3957,7 +4149,7 @@ verify_eh_throw_stmt_node (void **slot, void *data)
       debug_gimple_stmt (node->stmt);
       eh_error_found = true;
     }
-  return 0;
+  return 1;
 }
 
 
@@ -5554,6 +5746,23 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
       update_stmt (stmt);
       pop_cfun ();
     }
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    if (e->goto_locus)
+      {
+       tree block = e->goto_block;
+       if (d->orig_block == NULL_TREE
+           || block == d->orig_block)
+         e->goto_block = d->new_block;
+#ifdef ENABLE_CHECKING
+       else if (block != d->new_block)
+         {
+           while (block && block != d->orig_block)
+             block = BLOCK_SUPERCONTEXT (block);
+           gcc_assert (block);
+         }
+#endif
+      }
 }
 
 /* Examine the statements in BB (which is in SRC_CFUN); find and return
@@ -5626,6 +5835,8 @@ replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map,
   for (tp = &BLOCK_VARS (block); *tp; tp = &TREE_CHAIN (*tp))
     {
       t = *tp;
+      if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != CONST_DECL)
+       continue;
       replace_by_duplicate_decl (&t, vars_map, to_context);
       if (t != *tp)
        {
@@ -6231,7 +6442,7 @@ need_fake_edge_p (gimple t)
       && !(call_flags & ECF_NORETURN))
     return true;
 
-  if (gimple_code (t) == ASM_EXPR
+  if (gimple_code (t) == GIMPLE_ASM
        && (gimple_asm_volatile_p (t) || gimple_asm_input_p (t)))
     return true;