mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-14 19:41:02 +08:00
configure.ac: Add types checking to stage1 checking flags.
2007-07-26 Richard Guenther <rguenther@suse.de> toplev/ * configure.ac: Add types checking to stage1 checking flags. * configure: Regenerate. gcc/ * tree-cfg.c (verify_gimple_unary_expr, verify_gimple_binary_expr, verify_gimple_min_lval, verify_gimple_reference, verify_gimple_expr, verify_gimple_modify_stmt, verify_gimple_stmt, verify_gimple_1, verify_gimple): New functions. * tree-flow.h (verify_gimple): Declare. (verify_gimple_1): Declare. * gimplify.c (cpt_same_type): Remove. (gimplify_addr_expr): Remove checking code. (check_pointer_types_r): Remove. (gimplify_body): Call verify_gimple_1 instead of check_pointer_types_r. Only verify if there were no errors. * configure.ac: Add types checking flag. * configure: Regenerate. * config.in: Regenerate. From-SVN: r126951
This commit is contained in:
parent
0ee0208ecc
commit
7e98624c5e
@ -1,3 +1,8 @@
|
||||
2007-07-26 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
* configure.ac: Add types checking to stage1 checking flags.
|
||||
* configure: Regenerate.
|
||||
|
||||
2007-07-17 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* COPYING3: New file. Contains version 3 of the GNU General
|
||||
|
4
configure
vendored
4
configure
vendored
@ -11967,9 +11967,9 @@ if test "${enable_stage1_checking+set}" = set; then
|
||||
stage1_checking=--enable-checking=${enable_stage1_checking}
|
||||
else
|
||||
if test "x$enable_checking" = xno; then
|
||||
stage1_checking=--enable-checking
|
||||
stage1_checking=--enable-checking=yes,types
|
||||
else
|
||||
stage1_checking=--enable-checking${enable_checking+=}$enable_checking
|
||||
stage1_checking=--enable-checking=types${enable_checking+,}$enable_checking
|
||||
fi
|
||||
fi;
|
||||
|
||||
|
@ -2593,9 +2593,9 @@ AC_ARG_ENABLE(stage1-checking,
|
||||
of the compiler],
|
||||
[stage1_checking=--enable-checking=${enable_stage1_checking}],
|
||||
[if test "x$enable_checking" = xno; then
|
||||
stage1_checking=--enable-checking
|
||||
stage1_checking=--enable-checking=yes,types
|
||||
else
|
||||
stage1_checking=--enable-checking${enable_checking+=}$enable_checking
|
||||
stage1_checking=--enable-checking=types${enable_checking+,}$enable_checking
|
||||
fi])
|
||||
AC_SUBST(stage1_checking)
|
||||
|
||||
|
@ -121,6 +121,12 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* Define if you want all gimple types to be verified after gimplifiation. */
|
||||
#ifndef USED_FOR_TARGET
|
||||
#undef ENABLE_TYPES_CHECKING
|
||||
#endif
|
||||
|
||||
|
||||
/* Define if you want to run subprograms and generated programs through
|
||||
valgrind (a memory checker). This is extremely expensive. */
|
||||
#ifndef USED_FOR_TARGET
|
||||
|
22
gcc/configure
vendored
22
gcc/configure
vendored
@ -868,7 +868,7 @@ Optional Features:
|
||||
enable only specific categories of checks.
|
||||
Categories are: yes,no,all,none,release.
|
||||
Flags are: assert,df,fold,gc,gcac,misc,
|
||||
rtlflag,rtl,runtime,tree,valgrind.
|
||||
rtlflag,rtl,runtime,tree,valgrind,types.
|
||||
--enable-mapped-location location_t is fileline integer cookie
|
||||
--enable-coverage=LEVEL
|
||||
enable compiler's code coverage collection.
|
||||
@ -6429,22 +6429,26 @@ do
|
||||
ac_fold_checking= ; ac_gc_checking=1 ;
|
||||
ac_gc_always_collect= ; ac_rtl_checking= ;
|
||||
ac_rtlflag_checking=1 ; ac_runtime_checking=1 ;
|
||||
ac_tree_checking=1 ; ac_valgrind_checking= ;;
|
||||
ac_tree_checking=1 ; ac_valgrind_checking= ;
|
||||
ac_types_checking= ;;
|
||||
no|none) ac_assert_checking= ; ac_checking= ; ac_df_checking= ;
|
||||
ac_fold_checking= ; ac_gc_checking= ;
|
||||
ac_gc_always_collect= ; ac_rtl_checking= ;
|
||||
ac_rtlflag_checking= ; ac_runtime_checking= ;
|
||||
ac_tree_checking= ; ac_valgrind_checking= ;;
|
||||
ac_tree_checking= ; ac_valgrind_checking= ;
|
||||
ac_types_checking= ;;
|
||||
all) ac_assert_checking=1 ; ac_checking=1 ; ac_df_checking=1 ;
|
||||
ac_fold_checking=1 ; ac_gc_checking=1 ;
|
||||
ac_gc_always_collect=1 ; ac_rtl_checking=1 ;
|
||||
ac_rtlflag_checking=1 ; ac_runtime_checking=1 ;
|
||||
ac_tree_checking=1 ; ac_valgrind_checking= ;;
|
||||
ac_tree_checking=1 ; ac_valgrind_checking= ;
|
||||
ac_types_checking=1 ;;
|
||||
release) ac_assert_checking=1 ; ac_checking= ; ac_df_checking= ;
|
||||
ac_fold_checking= ; ac_gc_checking= ;
|
||||
ac_gc_always_collect= ; ac_rtl_checking= ;
|
||||
ac_rtlflag_checking= ; ac_runtime_checking=1 ;
|
||||
ac_tree_checking= ; ac_valgrind_checking= ;;
|
||||
ac_tree_checking= ; ac_valgrind_checking= ;
|
||||
ac_types_checking= ;;
|
||||
# these enable particular checks
|
||||
assert) ac_assert_checking=1 ;;
|
||||
df) ac_df_checking=1 ;;
|
||||
@ -6456,6 +6460,7 @@ do
|
||||
rtlflag) ac_rtlflag_checking=1 ;;
|
||||
runtime) ac_runtime_checking=1 ;;
|
||||
tree) ac_tree_checking=1 ;;
|
||||
types) ac_types_checking=1 ;;
|
||||
valgrind) ac_valgrind_checking=1 ;;
|
||||
*) { { echo "$as_me:$LINENO: error: unknown check category $check" >&5
|
||||
echo "$as_me: error: unknown check category $check" >&2;}
|
||||
@ -6504,6 +6509,13 @@ _ACEOF
|
||||
|
||||
TREEBROWSER=tree-browser.o
|
||||
fi
|
||||
if test x$ac_types_checking != x ; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define ENABLE_TYPES_CHECKING 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
if test x$ac_rtl_checking != x ; then
|
||||
|
||||
|
@ -346,7 +346,7 @@ AC_ARG_ENABLE(checking,
|
||||
enable only specific categories of checks.
|
||||
Categories are: yes,no,all,none,release.
|
||||
Flags are: assert,df,fold,gc,gcac,misc,
|
||||
rtlflag,rtl,runtime,tree,valgrind.],
|
||||
rtlflag,rtl,runtime,tree,valgrind,types.],
|
||||
[ac_checking_flags="${enableval}"],[
|
||||
# Determine the default checks.
|
||||
if test x$is_release = x ; then
|
||||
@ -363,22 +363,26 @@ do
|
||||
ac_fold_checking= ; ac_gc_checking=1 ;
|
||||
ac_gc_always_collect= ; ac_rtl_checking= ;
|
||||
ac_rtlflag_checking=1 ; ac_runtime_checking=1 ;
|
||||
ac_tree_checking=1 ; ac_valgrind_checking= ;;
|
||||
ac_tree_checking=1 ; ac_valgrind_checking= ;
|
||||
ac_types_checking= ;;
|
||||
no|none) ac_assert_checking= ; ac_checking= ; ac_df_checking= ;
|
||||
ac_fold_checking= ; ac_gc_checking= ;
|
||||
ac_gc_always_collect= ; ac_rtl_checking= ;
|
||||
ac_rtlflag_checking= ; ac_runtime_checking= ;
|
||||
ac_tree_checking= ; ac_valgrind_checking= ;;
|
||||
ac_tree_checking= ; ac_valgrind_checking= ;
|
||||
ac_types_checking= ;;
|
||||
all) ac_assert_checking=1 ; ac_checking=1 ; ac_df_checking=1 ;
|
||||
ac_fold_checking=1 ; ac_gc_checking=1 ;
|
||||
ac_gc_always_collect=1 ; ac_rtl_checking=1 ;
|
||||
ac_rtlflag_checking=1 ; ac_runtime_checking=1 ;
|
||||
ac_tree_checking=1 ; ac_valgrind_checking= ;;
|
||||
ac_tree_checking=1 ; ac_valgrind_checking= ;
|
||||
ac_types_checking=1 ;;
|
||||
release) ac_assert_checking=1 ; ac_checking= ; ac_df_checking= ;
|
||||
ac_fold_checking= ; ac_gc_checking= ;
|
||||
ac_gc_always_collect= ; ac_rtl_checking= ;
|
||||
ac_rtlflag_checking= ; ac_runtime_checking=1 ;
|
||||
ac_tree_checking= ; ac_valgrind_checking= ;;
|
||||
ac_tree_checking= ; ac_valgrind_checking= ;
|
||||
ac_types_checking= ;;
|
||||
# these enable particular checks
|
||||
assert) ac_assert_checking=1 ;;
|
||||
df) ac_df_checking=1 ;;
|
||||
@ -390,6 +394,7 @@ do
|
||||
rtlflag) ac_rtlflag_checking=1 ;;
|
||||
runtime) ac_runtime_checking=1 ;;
|
||||
tree) ac_tree_checking=1 ;;
|
||||
types) ac_types_checking=1 ;;
|
||||
valgrind) ac_valgrind_checking=1 ;;
|
||||
*) AC_MSG_ERROR(unknown check category $check) ;;
|
||||
esac
|
||||
@ -426,6 +431,12 @@ if test x$ac_tree_checking != x ; then
|
||||
])
|
||||
TREEBROWSER=tree-browser.o
|
||||
fi
|
||||
if test x$ac_types_checking != x ; then
|
||||
AC_DEFINE(ENABLE_TYPES_CHECKING, 1,
|
||||
[Define if you want all gimple types to be verified after gimplifiation.
|
||||
This is cheap.
|
||||
])
|
||||
fi
|
||||
AC_SUBST(TREEBROWSER)
|
||||
if test x$ac_rtl_checking != x ; then
|
||||
AC_DEFINE(ENABLE_RTL_CHECKING, 1,
|
||||
|
100
gcc/gimplify.c
100
gcc/gimplify.c
@ -112,9 +112,6 @@ typedef struct gimple_temp_hash_elt
|
||||
|
||||
/* 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. */
|
||||
@ -3985,19 +3982,7 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
|
||||
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;
|
||||
}
|
||||
@ -6393,84 +6378,6 @@ gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
|
||||
}
|
||||
}
|
||||
|
||||
#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. */
|
||||
@ -6539,8 +6446,9 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms)
|
||||
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);
|
||||
|
704
gcc/tree-cfg.c
704
gcc/tree-cfg.c
@ -3345,6 +3345,710 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
|
||||
#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. */
|
||||
|
@ -752,6 +752,8 @@ extern void bsi_commit_edge_inserts (void);
|
||||
extern void notice_special_calls (tree);
|
||||
extern void clear_special_calls (void);
|
||||
extern void verify_stmts (void);
|
||||
extern void verify_gimple (void);
|
||||
extern void verify_gimple_1 (tree);
|
||||
extern tree tree_block_label (basic_block);
|
||||
extern void extract_true_false_edges_from_block (basic_block, edge *, edge *);
|
||||
extern bool tree_duplicate_sese_region (edge, edge, basic_block *, unsigned,
|
||||
|
Loading…
x
Reference in New Issue
Block a user