/* Forward declarations. */
static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
-#ifdef ENABLE_CHECKING
-static bool cpt_same_type (tree a, tree b);
-#endif
/* Mark X addressable. Unlike the langhook we expect X to be in gimple
form and we don't do any syntax checking. */
tree t_op00 = TREE_TYPE (op00);
if (!useless_type_conversion_p (t_expr, t_op00))
- {
-#ifdef ENABLE_CHECKING
- tree t_op0 = TREE_TYPE (op0);
- gcc_assert (POINTER_TYPE_P (t_expr)
- && (cpt_same_type (TREE_TYPE (t_expr), t_op0)
- || (TREE_CODE (t_op0) == ARRAY_TYPE
- && cpt_same_type (TREE_TYPE (t_expr),
- TREE_TYPE (t_op0))))
- && POINTER_TYPE_P (t_op00)
- && cpt_same_type (t_op0, TREE_TYPE (t_op00)));
-#endif
- op00 = fold_convert (TREE_TYPE (expr), op00);
- }
+ op00 = fold_convert (TREE_TYPE (expr), op00);
*expr_p = op00;
ret = GS_OK;
}
}
}
\f
-#ifdef ENABLE_CHECKING
-/* Compare types A and B for a "close enough" match. */
-
-static bool
-cpt_same_type (tree a, tree b)
-{
- if (useless_type_conversion_p (a, b))
- return true;
-
- /* ??? The C++ FE decomposes METHOD_TYPES to FUNCTION_TYPES and doesn't
- link them together. This routine is intended to catch type errors
- that will affect the optimizers, and the optimizers don't add new
- dereferences of function pointers, so ignore it. */
- if ((TREE_CODE (a) == FUNCTION_TYPE || TREE_CODE (a) == METHOD_TYPE)
- && (TREE_CODE (b) == FUNCTION_TYPE || TREE_CODE (b) == METHOD_TYPE))
- return true;
-
- /* ??? The C FE pushes type qualifiers after the fact into the type of
- the element from the type of the array. See build_unary_op's handling
- of ADDR_EXPR. This seems wrong -- if we were going to do this, we
- should have done it when creating the variable in the first place.
- Alternately, why aren't the two array types made variants? */
- if (TREE_CODE (a) == ARRAY_TYPE && TREE_CODE (b) == ARRAY_TYPE)
- return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b));
-
- /* And because of those, we have to recurse down through pointers. */
- if (POINTER_TYPE_P (a) && POINTER_TYPE_P (b))
- return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b));
-
- return false;
-}
-
-/* Check for some cases of the front end missing cast expressions.
- The type of a dereference should correspond to the pointer type;
- similarly the type of an address should match its object. */
-
-static tree
-check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
-{
- tree t = *tp;
- tree ptype, otype, dtype;
-
- switch (TREE_CODE (t))
- {
- case INDIRECT_REF:
- case ARRAY_REF:
- otype = TREE_TYPE (t);
- ptype = TREE_TYPE (TREE_OPERAND (t, 0));
- dtype = TREE_TYPE (ptype);
- gcc_assert (cpt_same_type (otype, dtype));
- break;
-
- case ADDR_EXPR:
- ptype = TREE_TYPE (t);
- otype = TREE_TYPE (TREE_OPERAND (t, 0));
- dtype = TREE_TYPE (ptype);
- if (!cpt_same_type (dtype, otype))
- {
- /* &array is allowed to produce a pointer to the element, rather than
- a pointer to the array type. We must allow this in order to
- properly represent assigning the address of an array in C into
- pointer to the element type. */
- gcc_assert (TREE_CODE (otype) == ARRAY_TYPE
- && POINTER_TYPE_P (ptype)
- && cpt_same_type (dtype, TREE_TYPE (otype)));
- break;
- }
- break;
-
- default:
- return NULL_TREE;
- }
-
-
- return NULL_TREE;
-}
-#endif
/* Gimplify the body of statements pointed to by BODY_P. FNDECL is the
function decl containing BODY. */
pop_gimplify_context (body);
gcc_assert (gimplify_ctxp == NULL);
-#ifdef ENABLE_CHECKING
- walk_tree (body_p, check_pointer_types_r, NULL, NULL);
+#ifdef ENABLE_TYPES_CHECKING
+ if (!errorcount && !sorrycount)
+ verify_gimple_1 (BIND_EXPR_BODY (*body_p));
#endif
timevar_pop (TV_TREE_GIMPLIFY);
#undef CHECK_OP
}
+/* Verifies if EXPR is a valid GIMPLE unary expression. Returns true
+ if there is an error, otherwise false. */
+
+static bool
+verify_gimple_unary_expr (tree expr)
+{
+ tree op = TREE_OPERAND (expr, 0);
+ tree type = TREE_TYPE (expr);
+
+ if (!is_gimple_val (op))
+ {
+ error ("invalid operand in unary expression");
+ return true;
+ }
+
+ /* For general unary expressions we have the operations type
+ as the effective type the operation is carried out on. So all
+ we need to require is that the operand is trivially convertible
+ to that type. */
+ if (!useless_type_conversion_p (type, TREE_TYPE (op)))
+ {
+ error ("type mismatch in unary expression");
+ debug_generic_expr (type);
+ debug_generic_expr (TREE_TYPE (op));
+ return true;
+ }
+
+ return false;
+}
+
+/* Verifies if EXPR is a valid GIMPLE binary expression. Returns true
+ if there is an error, otherwise false. */
+
+static bool
+verify_gimple_binary_expr (tree expr)
+{
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree type = TREE_TYPE (expr);
+
+ if (!is_gimple_val (op0) || !is_gimple_val (op1))
+ {
+ error ("invalid operands in binary expression");
+ return true;
+ }
+
+ /* For general binary expressions we have the operations type
+ as the effective type the operation is carried out on. So all
+ we need to require is that both operands are trivially convertible
+ to that type. */
+ if (!useless_type_conversion_p (type, TREE_TYPE (op0))
+ || !useless_type_conversion_p (type, TREE_TYPE (op1)))
+ {
+ error ("type mismatch in binary expression");
+ debug_generic_stmt (type);
+ debug_generic_stmt (TREE_TYPE (op0));
+ debug_generic_stmt (TREE_TYPE (op1));
+ return true;
+ }
+
+ return false;
+}
+
+/* Verify if EXPR is either a GIMPLE ID or a GIMPLE indirect reference.
+ Returns true if there is an error, otherwise false. */
+
+static bool
+verify_gimple_min_lval (tree expr)
+{
+ tree op;
+
+ 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)
+ {
+ error ("invalid expression for min lvalue");
+ return true;
+ }
+
+ op = TREE_OPERAND (expr, 0);
+ if (!is_gimple_val (op))
+ {
+ error ("invalid operand in indirect reference");
+ debug_generic_stmt (op);
+ return true;
+ }
+ if (!useless_type_conversion_p (TREE_TYPE (expr),
+ TREE_TYPE (TREE_TYPE (op))))
+ {
+ error ("type mismatch in indirect reference");
+ debug_generic_stmt (TREE_TYPE (expr));
+ debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
+ return true;
+ }
+
+ return false;
+}
+
+/* Verify if EXPR is a valid GIMPLE reference expression. Returns true
+ if there is an error, otherwise false. */
+
+static bool
+verify_gimple_reference (tree expr)
+{
+ while (handled_component_p (expr))
+ {
+ tree op = TREE_OPERAND (expr, 0);
+
+ if (TREE_CODE (expr) == ARRAY_REF
+ || TREE_CODE (expr) == ARRAY_RANGE_REF)
+ {
+ if (!is_gimple_val (TREE_OPERAND (expr, 1))
+ || (TREE_OPERAND (expr, 2)
+ && !is_gimple_val (TREE_OPERAND (expr, 2)))
+ || (TREE_OPERAND (expr, 3)
+ && !is_gimple_val (TREE_OPERAND (expr, 3))))
+ {
+ error ("invalid operands to array reference");
+ debug_generic_stmt (expr);
+ return true;
+ }
+ }
+
+ /* Verify if the reference array element types are compatible. */
+ if (TREE_CODE (expr) == ARRAY_REF
+ && !useless_type_conversion_p (TREE_TYPE (expr),
+ TREE_TYPE (TREE_TYPE (op))))
+ {
+ error ("type mismatch in array reference");
+ debug_generic_stmt (TREE_TYPE (expr));
+ debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
+ return true;
+ }
+ if (TREE_CODE (expr) == ARRAY_RANGE_REF
+ && !useless_type_conversion_p (TREE_TYPE (TREE_TYPE (expr)),
+ TREE_TYPE (TREE_TYPE (op))))
+ {
+ error ("type mismatch in array range reference");
+ debug_generic_stmt (TREE_TYPE (TREE_TYPE (expr)));
+ debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
+ return true;
+ }
+
+ if ((TREE_CODE (expr) == REALPART_EXPR
+ || TREE_CODE (expr) == IMAGPART_EXPR)
+ && !useless_type_conversion_p (TREE_TYPE (expr),
+ TREE_TYPE (TREE_TYPE (op))))
+ {
+ error ("type mismatch in real/imagpart reference");
+ debug_generic_stmt (TREE_TYPE (expr));
+ debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
+ return true;
+ }
+
+ if (TREE_CODE (expr) == COMPONENT_REF
+ && !useless_type_conversion_p (TREE_TYPE (expr),
+ TREE_TYPE (TREE_OPERAND (expr, 1))))
+ {
+ error ("type mismatch in component reference");
+ debug_generic_stmt (TREE_TYPE (expr));
+ debug_generic_stmt (TREE_TYPE (TREE_OPERAND (expr, 1)));
+ return true;
+ }
+
+ /* For VIEW_CONVERT_EXPRs which are allowed here, too, there
+ is nothing to verify. Gross mismatches at most invoke
+ undefined behavior. */
+
+ expr = op;
+ }
+
+ return verify_gimple_min_lval (expr);
+}
+
+/* Verify the GIMPLE expression EXPR. Returns true if there is an
+ error, otherwise false. */
+
+static bool
+verify_gimple_expr (tree expr)
+{
+ tree type = TREE_TYPE (expr);
+
+ if (is_gimple_val (expr))
+ return false;
+
+ /* Special codes we cannot handle via their class. */
+ switch (TREE_CODE (expr))
+ {
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ if (!is_gimple_val (op))
+ {
+ error ("invalid operand in conversion");
+ return true;
+ }
+
+ /* Allow conversions between integral types. */
+ if (INTEGRAL_TYPE_P (type) == INTEGRAL_TYPE_P (TREE_TYPE (op)))
+ return false;
+
+ /* Allow conversions between integral types and pointers only if
+ there is no sign or zero extension involved. */
+ if (((POINTER_TYPE_P (type) && INTEGRAL_TYPE_P (TREE_TYPE (op)))
+ || (POINTER_TYPE_P (TREE_TYPE (op)) && INTEGRAL_TYPE_P (type)))
+ && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (op)))
+ return false;
+
+ /* Allow conversion from integer to offset type and vice versa. */
+ if ((TREE_CODE (type) == OFFSET_TYPE
+ && TREE_CODE (TREE_TYPE (op)) == INTEGER_TYPE)
+ || (TREE_CODE (type) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (op)) == OFFSET_TYPE))
+ return false;
+
+ /* Otherwise assert we are converting between types of the
+ same kind. */
+ if (TREE_CODE (type) != TREE_CODE (TREE_TYPE (op)))
+ {
+ error ("invalid types in nop conversion");
+ debug_generic_expr (type);
+ debug_generic_expr (TREE_TYPE (op));
+ return true;
+ }
+
+ return false;
+ }
+
+ case FLOAT_EXPR:
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ if (!is_gimple_val (op))
+ {
+ error ("invalid operand in int to float conversion");
+ return true;
+ }
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (op))
+ || !SCALAR_FLOAT_TYPE_P (type))
+ {
+ error ("invalid types in conversion to floating point");
+ debug_generic_expr (type);
+ debug_generic_expr (TREE_TYPE (op));
+ return true;
+ }
+ return false;
+ }
+
+ case FIX_TRUNC_EXPR:
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ if (!is_gimple_val (op))
+ {
+ error ("invalid operand in float to int conversion");
+ return true;
+ }
+ if (!INTEGRAL_TYPE_P (type)
+ || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (op)))
+ {
+ error ("invalid types in conversion to integer");
+ debug_generic_expr (type);
+ debug_generic_expr (TREE_TYPE (op));
+ return true;
+ }
+ return false;
+ }
+
+ case COMPLEX_EXPR:
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ if (!is_gimple_val (op0) || !is_gimple_val (op1))
+ {
+ error ("invalid operands in complex expression");
+ return true;
+ }
+ if (!TREE_CODE (type) == COMPLEX_TYPE
+ || !(TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE
+ || SCALAR_FLOAT_TYPE_P (TREE_TYPE (op0)))
+ || !(TREE_CODE (TREE_TYPE (op1)) == INTEGER_TYPE
+ || SCALAR_FLOAT_TYPE_P (TREE_TYPE (op1)))
+ || !useless_type_conversion_p (TREE_TYPE (type),
+ TREE_TYPE (op0))
+ || !useless_type_conversion_p (TREE_TYPE (type),
+ TREE_TYPE (op1)))
+ {
+ error ("type mismatch in complex expression");
+ debug_generic_stmt (TREE_TYPE (expr));
+ debug_generic_stmt (TREE_TYPE (op0));
+ debug_generic_stmt (TREE_TYPE (op1));
+ return true;
+ }
+ return false;
+ }
+
+ case CONSTRUCTOR:
+ {
+ /* This is used like COMPLEX_EXPR but for vectors. */
+ if (TREE_CODE (type) != VECTOR_TYPE)
+ {
+ error ("constructor not allowed for non-vector types");
+ debug_generic_stmt (type);
+ return true;
+ }
+ /* FIXME: verify constructor arguments. */
+ return false;
+ }
+
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ if (!is_gimple_val (op0) || !is_gimple_val (op1))
+ {
+ error ("invalid operands in shift expression");
+ return true;
+ }
+ if (!TREE_CODE (TREE_TYPE (op1)) == INTEGER_TYPE
+ || !useless_type_conversion_p (type, TREE_TYPE (op0)))
+ {
+ error ("type mismatch in shift expression");
+ debug_generic_stmt (TREE_TYPE (expr));
+ debug_generic_stmt (TREE_TYPE (op0));
+ debug_generic_stmt (TREE_TYPE (op1));
+ return true;
+ }
+ return false;
+ }
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ if (POINTER_TYPE_P (type)
+ || POINTER_TYPE_P (TREE_TYPE (op0))
+ || POINTER_TYPE_P (TREE_TYPE (op1)))
+ {
+ error ("invalid (pointer) operands to plus/minus");
+ return true;
+ }
+ /* Continue with generic binary expression handling. */
+ break;
+ }
+
+ case POINTER_PLUS_EXPR:
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ if (!is_gimple_val (op0) || !is_gimple_val (op1))
+ {
+ error ("invalid operands in pointer plus expression");
+ return true;
+ }
+ if (!POINTER_TYPE_P (TREE_TYPE (op0))
+ || TREE_CODE (TREE_TYPE (op1)) != INTEGER_TYPE
+ || !useless_type_conversion_p (type, TREE_TYPE (op0))
+ || !useless_type_conversion_p (sizetype, TREE_TYPE (op1)))
+ {
+ error ("type mismatch in pointer plus expression");
+ debug_generic_stmt (type);
+ debug_generic_stmt (TREE_TYPE (op0));
+ debug_generic_stmt (TREE_TYPE (op1));
+ return true;
+ }
+ return false;
+ }
+
+ case COND_EXPR:
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree op2 = TREE_OPERAND (expr, 2);
+ if ((!is_gimple_val (op1)
+ && TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE)
+ || (!is_gimple_val (op2)
+ && TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE))
+ {
+ error ("invalid operands in conditional expression");
+ return true;
+ }
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
+ || (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE
+ && !useless_type_conversion_p (type, TREE_TYPE (op1)))
+ || (TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE
+ && !useless_type_conversion_p (type, TREE_TYPE (op2))))
+ {
+ error ("type mismatch in conditional expression");
+ debug_generic_stmt (type);
+ debug_generic_stmt (TREE_TYPE (op0));
+ debug_generic_stmt (TREE_TYPE (op1));
+ debug_generic_stmt (TREE_TYPE (op2));
+ return true;
+ }
+ return verify_gimple_expr (op0);
+ }
+
+ case ADDR_EXPR:
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ tree ptr_type;
+ if (!is_gimple_addressable (op))
+ {
+ error ("invalid operand in unary expression");
+ return true;
+ }
+ ptr_type = build_pointer_type (TREE_TYPE (op));
+ if (!useless_type_conversion_p (type, ptr_type)
+ /* FIXME: a longstanding wart, &a == &a[0]. */
+ && (TREE_CODE (TREE_TYPE (op)) != ARRAY_TYPE
+ || !useless_type_conversion_p (type,
+ build_pointer_type (TREE_TYPE (TREE_TYPE (op))))))
+ {
+ error ("type mismatch in address expression");
+ debug_generic_stmt (TREE_TYPE (expr));
+ debug_generic_stmt (ptr_type);
+ return true;
+ }
+
+ return verify_gimple_reference (op);
+ }
+
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+
+ if (!is_gimple_val (op0) || !is_gimple_val (op1))
+ {
+ error ("invalid operands in truth expression");
+ return true;
+ }
+
+ /* We allow any kind of integral typed argument and result. */
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
+ || !INTEGRAL_TYPE_P (TREE_TYPE (op1))
+ || !INTEGRAL_TYPE_P (type))
+ {
+ error ("type mismatch in binary truth expression");
+ debug_generic_stmt (type);
+ debug_generic_stmt (TREE_TYPE (op0));
+ debug_generic_stmt (TREE_TYPE (op1));
+ return true;
+ }
+
+ return false;
+ }
+
+ case TRUTH_NOT_EXPR:
+ {
+ tree op = TREE_OPERAND (expr, 0);
+
+ if (!is_gimple_val (op))
+ {
+ error ("invalid operand in unary not");
+ return true;
+ }
+
+ /* For TRUTH_NOT_EXPR we can have any kind of integral
+ typed arguments and results. */
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (op))
+ || !INTEGRAL_TYPE_P (type))
+ {
+ error ("type mismatch in not expression");
+ debug_generic_expr (TREE_TYPE (expr));
+ debug_generic_expr (TREE_TYPE (op));
+ return true;
+ }
+
+ return false;
+ }
+
+ case CALL_EXPR:
+ /* FIXME. The C frontend passes unpromoted arguments in case it
+ didn't see a function declaration before the call. */
+ return false;
+
+ default:;
+ }
+
+ /* Generic handling via classes. */
+ switch (TREE_CODE_CLASS (TREE_CODE (expr)))
+ {
+ case tcc_unary:
+ return verify_gimple_unary_expr (expr);
+
+ case tcc_binary:
+ return verify_gimple_binary_expr (expr);
+
+ case tcc_reference:
+ return verify_gimple_reference (expr);
+
+ case tcc_comparison:
+ {
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ if (!is_gimple_val (op0) || !is_gimple_val (op1))
+ {
+ error ("invalid operands in comparison 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 (TREE_TYPE (op0), TREE_TYPE (op1))
+ && !useless_type_conversion_p (TREE_TYPE (op1), TREE_TYPE (op0))
+ && (!POINTER_TYPE_P (TREE_TYPE (op0))
+ || !POINTER_TYPE_P (TREE_TYPE (op1))
+ || TYPE_MODE (TREE_TYPE (op0)) != TYPE_MODE (TREE_TYPE (op1))))
+ || !INTEGRAL_TYPE_P (type))
+ {
+ error ("type mismatch in comparison expression");
+ debug_generic_stmt (TREE_TYPE (expr));
+ debug_generic_stmt (TREE_TYPE (op0));
+ debug_generic_stmt (TREE_TYPE (op1));
+ return true;
+ }
+ break;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return false;
+}
+
+/* Verify the GIMPLE assignment statement STMT. Returns true if there
+ is an error, otherwise false. */
+
+static bool
+verify_gimple_modify_stmt (tree stmt)
+{
+ tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+ tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
+
+ gcc_assert (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT);
+
+ if (!useless_type_conversion_p (TREE_TYPE (lhs),
+ TREE_TYPE (rhs)))
+ {
+ error ("non-trivial conversion at assignment");
+ debug_generic_expr (TREE_TYPE (lhs));
+ debug_generic_expr (TREE_TYPE (rhs));
+ return true;
+ }
+
+ /* Loads/stores from/to a variable are ok. */
+ if ((is_gimple_val (lhs)
+ && is_gimple_variable (rhs))
+ || (is_gimple_val (rhs)
+ && is_gimple_variable (lhs)))
+ return false;
+
+ /* Aggregate copies are ok. */
+ if (!is_gimple_reg_type (TREE_TYPE (lhs))
+ && !is_gimple_reg_type (TREE_TYPE (rhs)))
+ return false;
+
+ /* We might get 'loads' from a parameter which is not a gimple value. */
+ if (TREE_CODE (rhs) == PARM_DECL)
+ return verify_gimple_expr (lhs);
+
+ if (!is_gimple_variable (lhs)
+ && verify_gimple_expr (lhs))
+ return true;
+
+ if (!is_gimple_variable (rhs)
+ && verify_gimple_expr (rhs))
+ return true;
+
+ return false;
+}
+
+/* Verify the GIMPLE statement STMT. Returns true if there is an
+ error, otherwise false. */
+
+static bool
+verify_gimple_stmt (tree stmt)
+{
+ if (!is_gimple_stmt (stmt))
+ {
+ error ("is not a valid GIMPLE statement");
+ return true;
+ }
+
+ if (OMP_DIRECTIVE_P (stmt))
+ {
+ /* OpenMP directives are validated by the FE and never operated
+ on by the optimizers. Furthermore, OMP_FOR may contain
+ non-gimple expressions when the main index variable has had
+ its address taken. This does not affect the loop itself
+ because the header of an OMP_FOR is merely used to determine
+ how to setup the parallel iteration. */
+ return false;
+ }
+
+ switch (TREE_CODE (stmt))
+ {
+ case GIMPLE_MODIFY_STMT:
+ return verify_gimple_modify_stmt (stmt);
+
+ case GOTO_EXPR:
+ case LABEL_EXPR:
+ return false;
+
+ case SWITCH_EXPR:
+ if (!is_gimple_val (TREE_OPERAND (stmt, 0)))
+ {
+ error ("invalid operand to switch statement");
+ debug_generic_expr (TREE_OPERAND (stmt, 0));
+ }
+ return false;
+
+ case RETURN_EXPR:
+ {
+ tree op = TREE_OPERAND (stmt, 0);
+
+ if (TREE_CODE (TREE_TYPE (stmt)) != VOID_TYPE)
+ {
+ error ("type error in return expression");
+ return true;
+ }
+
+ if (op == NULL_TREE
+ || TREE_CODE (op) == RESULT_DECL)
+ return false;
+
+ return verify_gimple_modify_stmt (op);
+ }
+
+ case CALL_EXPR:
+ case COND_EXPR:
+ return verify_gimple_expr (stmt);
+
+ case NOP_EXPR:
+ case CHANGE_DYNAMIC_TYPE_EXPR:
+ case ASM_EXPR:
+ return false;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Verify the GIMPLE statements inside the statement list STMTS. */
+
+void
+verify_gimple_1 (tree stmts)
+{
+ tree_stmt_iterator tsi;
+
+ for (tsi = tsi_start (stmts); !tsi_end_p (tsi); tsi_next (&tsi))
+ {
+ tree stmt = tsi_stmt (tsi);
+
+ switch (TREE_CODE (stmt))
+ {
+ case BIND_EXPR:
+ verify_gimple_1 (BIND_EXPR_BODY (stmt));
+ break;
+
+ case TRY_CATCH_EXPR:
+ case TRY_FINALLY_EXPR:
+ verify_gimple_1 (TREE_OPERAND (stmt, 0));
+ verify_gimple_1 (TREE_OPERAND (stmt, 1));
+ break;
+
+ case CATCH_EXPR:
+ verify_gimple_1 (CATCH_BODY (stmt));
+ break;
+
+ case EH_FILTER_EXPR:
+ verify_gimple_1 (EH_FILTER_FAILURE (stmt));
+ break;
+
+ default:
+ if (verify_gimple_stmt (stmt))
+ debug_generic_expr (stmt);
+ }
+ }
+}
+
+/* Verify the GIMPLE statements inside the current function. */
+
+void
+verify_gimple (void)
+{
+ verify_gimple_1 (BIND_EXPR_BODY (DECL_SAVED_TREE (cfun->decl)));
+}
/* Verify STMT, return true if STMT is not in GIMPLE form.
TODO: Implement type checking. */