[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