[PATCH] Clean up (parts of) the gimple "type" verifier
Richard Guenther
rguenther@suse.de
Tue Sep 2 16:38:00 GMT 2008
This patch cleans up the type verifier (it actually verifies other
gimple properties as well). It doesn't touch the verification of
assigns, this will go into a separate patch.
The idea is to allow calling the parts that do not "break" anything
from verify_stmts (which doesn't test type correctness).
As I had to fix java in one case (I tried to avoid touching FEs and
just added ???s for the cases I ran into), this needs approval.
I expect we can fix the ???s in the gimplifier once we do
gimplification unit-at-a-time.
Bootstrapped and tested on x86_64-unknown-linux-gnu, ok for trunk?
Thanks,
Richard.
2008-09-02 Richard Guenther <rguenther@suse.de>
* tree-cfg.c (verify_types_in_gimple_op): Remove.
(verify_types_in_gimple_call): Rename to ...
(verify_gimple_call): ... this. Enhance.
(verify_types_in_gimple_cond): Remove.
(verify_gimple_comparison): New function ...
(verify_types_in_gimple_assign): ... split out from here.
(verify_types_in_gimple_return): Rename to ...
(verify_gimple_return): ... this. Enhance.
(verify_types_in_gimple_switch): Rename to ...
(verify_gimple_switch): ... this. Enhance.
(verify_gimple_goto): New function.
(verify_types_in_gimple_phi): Rename to ...
(verify_gimple_phi): ... this. Enhance.
(verify_types_in_gimple_stmt): Adjust calls to helper functions.
Fold in single-statement cases from verify_types_in_gimple_seq_2.
(verify_types_in_gimple_seq_2): Remove cases handled in
verify_types_in_gimple_stmt.
java/
* decl.c (build_result_decl): Remove no longer applicable
promotion.
Index: gcc/tree-cfg.c
===================================================================
*** gcc/tree-cfg.c.orig 2008-09-02 15:46:31.000000000 +0200
--- gcc/tree-cfg.c 2008-09-02 17:06:14.000000000 +0200
*************** valid_fixed_convert_types_p (tree type1,
*** 3165,3231 ****
|| 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)
{
! bool failed = false;
! unsigned int i;
! tree fn;
! if (gimple_call_lhs (stmt))
! failed |= verify_types_in_gimple_op (gimple_call_lhs (stmt));
! fn = gimple_call_fn (stmt);
! if (TREE_CODE (fn) != OBJ_TYPE_REF
! && verify_types_in_gimple_op (fn))
! failed = true;
! if (gimple_call_chain (stmt))
! failed |= verify_types_in_gimple_op (gimple_call_chain (stmt));
! for (i = 0; i < gimple_call_num_args (stmt); i++)
! failed |= verify_types_in_gimple_op (gimple_call_arg (stmt,i));
! return failed;
}
!
! /* Verify the contents of a GIMPLE_COND STMT. Returns true when there
! is a problem, otherwise false. */
static bool
! verify_types_in_gimple_cond (gimple stmt)
{
! 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));
! return failed;
! }
/* Verify the contents of a GIMPLE_ASSIGN STMT. Returns true when there
is a problem, otherwise false.
--- 3165,3261 ----
|| FIXED_POINT_TYPE_P (type2)));
}
/* Verify the contents of a GIMPLE_CALL STMT. Returns true when there
is a problem, otherwise false. */
static bool
! verify_gimple_call (gimple stmt)
{
! tree fn = gimple_call_fn (stmt);
! tree fntype;
! 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;
! }
! if (gimple_call_lhs (stmt)
! && !is_gimple_lvalue (gimple_call_lhs (stmt)))
! {
! error ("invalid LHS in gimple call");
! return true;
! }
! 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. */
! && !(POINTER_TYPE_P (TREE_TYPE (gimple_call_lhs (stmt)))
! && POINTER_TYPE_P (TREE_TYPE (fntype))
! && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fntype))))
! /* ??? Java is completely off. Especially with functions
! returning java.lang.Object. */
! && !(strcmp (lang_hooks.name, "GNU Java") == 0
! && POINTER_TYPE_P (TREE_TYPE (gimple_call_lhs (stmt)))
! && POINTER_TYPE_P (TREE_TYPE (fntype))))
! {
! error ("invalid non-noop conversion in gimple call");
! debug_generic_stmt (TREE_TYPE (gimple_call_lhs (stmt)));
! debug_generic_stmt (TREE_TYPE (fntype));
! return true;
! }
! /* ??? 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 false;
}
! /* Verifies the gimple comparison with the result type TYPE and
! the operands OP0 and OP1. */
static bool
! verify_gimple_comparison (tree type, tree op0, tree op1)
{
! tree op0_type = TREE_TYPE (op0);
! tree op1_type = TREE_TYPE (op1);
! 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;
! }
+ return false;
+ }
/* Verify the contents of a GIMPLE_ASSIGN STMT. Returns true when there
is a problem, otherwise false.
*************** verify_types_in_gimple_assign (gimple st
*** 3585,3619 ****
return verify_types_in_gimple_reference (rhs1);
case tcc_comparison:
! {
! if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2))
! {
! 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 (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))
! {
! error ("type mismatch in comparison expression");
! debug_generic_expr (lhs_type);
! debug_generic_expr (rhs1_type);
! debug_generic_expr (rhs2_type);
! return true;
! }
! break;
! }
default:;
}
--- 3615,3621 ----
return verify_types_in_gimple_reference (rhs1);
case tcc_comparison:
! return verify_gimple_comparison (lhs_type, rhs1, rhs2);
default:;
}
*************** verify_types_in_gimple_assign (gimple st
*** 3626,3652 ****
is a problem, otherwise false. */
static bool
! verify_types_in_gimple_return (gimple stmt)
{
tree op = gimple_return_retval (stmt);
if (op == NULL)
return false;
!
! return verify_types_in_gimple_op (op);
}
/* 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)
{
if (!is_gimple_val (gimple_switch_index (stmt)))
{
error ("invalid operand to switch statement");
! debug_generic_expr (gimple_switch_index (stmt));
return true;
}
--- 3628,3706 ----
is a problem, otherwise false. */
static bool
! verify_gimple_return (gimple stmt)
{
tree op = gimple_return_retval (stmt);
+ tree restype = TREE_TYPE (TREE_TYPE (cfun->decl));
+ /* We cannot test the following as we do not fix up missing return
+ values in the original source. */
+ if (0 && op == NULL
+ && !VOID_TYPE_P (restype))
+ {
+ error ("return statement without value in function returning non-void");
+ debug_generic_stmt (restype);
+ return true;
+ }
if (op == NULL)
return false;
!
! 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 non-noop 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_gimple_switch (gimple stmt)
{
if (!is_gimple_val (gimple_switch_index (stmt)))
{
error ("invalid operand to switch statement");
! debug_generic_stmt (gimple_switch_index (stmt));
return true;
}
*************** verify_types_in_gimple_switch (gimple st
*** 3658,3673 ****
and false otherwise. */
static bool
! verify_types_in_gimple_phi (gimple stmt)
{
! size_t i;
! if (verify_types_in_gimple_op (gimple_phi_result (stmt)))
! 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;
return false;
}
--- 3712,3745 ----
and false otherwise. */
static bool
! verify_gimple_phi (gimple stmt)
{
! tree type = TREE_TYPE (gimple_phi_result (stmt));
! unsigned i;
! if (!is_gimple_variable (gimple_phi_result (stmt)))
! {
! error ("Invalid PHI result");
! return true;
! }
for (i = 0; i < gimple_phi_num_args (stmt); i++)
! {
! tree arg = gimple_phi_arg_def (stmt, i);
! if (!is_gimple_val (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;
}
*************** verify_types_in_gimple_stmt (gimple stmt
*** 3699,3730 ****
return TREE_CODE (gimple_label_label (stmt)) != LABEL_DECL;
case GIMPLE_CALL:
! return verify_types_in_gimple_call (stmt);
case GIMPLE_COND:
! return verify_types_in_gimple_cond (stmt);
case GIMPLE_GOTO:
! return verify_types_in_gimple_op (gimple_goto_dest (stmt));
!
! case GIMPLE_NOP:
! case GIMPLE_PREDICT:
! return false;
case GIMPLE_SWITCH:
! return verify_types_in_gimple_switch (stmt);
case GIMPLE_RETURN:
! return verify_types_in_gimple_return (stmt);
case GIMPLE_ASM:
return false;
case GIMPLE_CHANGE_DYNAMIC_TYPE:
! return verify_types_in_gimple_op (gimple_cdt_location (stmt));
case GIMPLE_PHI:
! return verify_types_in_gimple_phi (stmt);
default:
gcc_unreachable ();
--- 3771,3807 ----
return TREE_CODE (gimple_label_label (stmt)) != LABEL_DECL;
case GIMPLE_CALL:
! return verify_gimple_call (stmt);
case GIMPLE_COND:
! return verify_gimple_comparison (boolean_type_node,
! gimple_cond_lhs (stmt),
! gimple_cond_rhs (stmt));
case GIMPLE_GOTO:
! return verify_gimple_goto (stmt);
case GIMPLE_SWITCH:
! return verify_gimple_switch (stmt);
case GIMPLE_RETURN:
! return verify_gimple_return (stmt);
case GIMPLE_ASM:
return false;
case GIMPLE_CHANGE_DYNAMIC_TYPE:
! return (!is_gimple_reg (gimple_cdt_location (stmt))
! || !POINTER_TYPE_P (TREE_TYPE (gimple_cdt_location (stmt))));
case GIMPLE_PHI:
! 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 ();
*************** verify_types_in_gimple_seq_2 (gimple_seq
*** 3745,3788 ****
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;
default:
{
--- 3822,3843 ----
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;
default:
{
Index: gcc/java/decl.c
===================================================================
*** gcc/java/decl.c.orig 2008-09-02 15:46:31.000000000 +0200
--- gcc/java/decl.c 2008-09-02 15:50:46.000000000 +0200
*************** build_result_decl (tree fndecl)
*** 1694,1703 ****
tree result = DECL_RESULT (fndecl);
if (! result)
{
- /* To be compatible with C_PROMOTING_INTEGER_TYPE_P in cc1/cc1plus. */
- if (INTEGRAL_TYPE_P (restype)
- && TYPE_PRECISION (restype) < TYPE_PRECISION (integer_type_node))
- restype = integer_type_node;
result = build_decl (RESULT_DECL, NULL_TREE, restype);
DECL_ARTIFICIAL (result) = 1;
DECL_IGNORED_P (result) = 1;
--- 1694,1699 ----
More information about the Gcc-patches
mailing list