This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][RFC] A GIMPLE and "GIMPLE type system" verifier


The following patch implements a GIMPLE and GIMPLE type system
(as far as it is defined) verifier.  Actually a rough prototype of it.
It's placed along the existing verify_stmts machinery to be able to

 - call it before lowering (with the patch it's run after useless
   stmt removal)

 - schedule it independently of verify_stmts - this patch does more
   strict verification on the IL and I bet optimization passes will
   cause it to alarm.

So the first goal was to schedule it early (or immediately after)
gimplification to catch gimplifier and frontend "bugs".  With a
few local patches C bootstraps with the checker enabled and only
a few testcases regress.  Most of the C++ failures will be
hopefully addressed by the pointer_plus branch merge, Fortran
seems to have some more rough edges currently (I didn't yet try
other languages).

Now there is the question on what we actually want to enforce with
respect to the GIMPLE type system.  The two questionable areas I
tripped over are

 - conversions from integer to pointer types (and vice versa).
   I'd like to enforce extension/truncation to be done in integer
   type only and not allow (T *)short for example, but require
   (T *)(sizetype)short.  [the same would hold true for ENUMERAL_TYPE
   and BOOLEAN_TYPE, but I didn't try what the fallout from this would be]

 - for comparisons we do not have a "common" operand type as we have
   for other binary expressions where we can use the expression type
   as unifier for a compatibility check.  So I'd like to enforce
   operand compatibility in both directions which actually causes
   problems for pointers, most due to gimplifier problems
   (see http://gcc.gnu.org/ml/gcc-patches/2006-06/msg00179.html for
   a possible way to solve many of the problems showing up that way)

Other than that I rely on tree_ssa_useless_type_conversion_1 which in
turn relies on the types_compatible_p langhook, so this is nowhere
like a real middle-end type system yet.

Comments?

I'm going to fix up the real frontend bugs and otherwise wait for
(or move over to) the pointer_plus branch.

Thanks,
Richard.

2007-05-31  Richard Guenther  <rguenther@suse.de>

	* tree-flow.h (verify_gimple): Declare.
	* tree-cfg.c (verify_gimple): New function.
	(remove_useless_stmts): Call it.
	(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):
	New helper functions.

Index: gcc/tree-cfg.c
===================================================================
*** gcc.orig/tree-cfg.c	2007-05-31 11:41:37.000000000 +0200
--- gcc/tree-cfg.c	2007-05-31 16:00:52.000000000 +0200
*************** remove_useless_stmts (void)
*** 1900,1905 ****
--- 1900,1908 ----
        remove_useless_stmts_1 (&DECL_SAVED_TREE (current_function_decl), &data);
      }
    while (data.repeat);
+ 
+   verify_gimple ();
+ 
    return 0;
  }
  
*************** verify_expr (tree *tp, int *walk_subtree
*** 3319,3324 ****
--- 3322,4033 ----
  #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;
+     }
+ 
+   if (!tree_ssa_useless_type_conversion_1 (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;
+     }
+ 
+   /* Expression arguments need to be compatible to each other in one way
+      and compatible to the type of the expression.
+      FIXME: More strict would be to use || instead of &&, but this
+ 	    breaks a lot.  */
+   if ((!tree_ssa_useless_type_conversion_1 (TREE_TYPE (op0), TREE_TYPE (op1))
+        && !tree_ssa_useless_type_conversion_1 (TREE_TYPE (op1), TREE_TYPE (op0)))
+       || !tree_ssa_useless_type_conversion_1 (type, TREE_TYPE (op0))
+       || !tree_ssa_useless_type_conversion_1 (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 (!tree_ssa_useless_type_conversion_1 (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
+ 	  && !tree_ssa_useless_type_conversion_1 (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
+ 	  && !tree_ssa_useless_type_conversion_1 (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)
+ 	  && !tree_ssa_useless_type_conversion_1 (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;
+ 	}
+ 
+       /* We require same object size.  */
+       if (TREE_CODE (expr) == VIEW_CONVERT_EXPR
+ 	  && !operand_equal_p (TYPE_SIZE (TREE_TYPE (expr)),
+ 			       TYPE_SIZE (TREE_TYPE (op)), 0))
+ 	{
+ 	  error ("different sized types in conversion");
+ 	  debug_generic_stmt (TYPE_SIZE (TREE_TYPE (expr)));
+ 	  debug_generic_stmt (TYPE_SIZE (TREE_TYPE (op)));
+ 	  return true;
+ 	}
+ 
+       if (TREE_CODE (expr) == COMPONENT_REF
+ 	  && !tree_ssa_useless_type_conversion_1 (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;
+ 	}
+ 
+       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.  */
+ 	if (TREE_CODE (type) == OFFSET_TYPE
+ 	    && TREE_CODE (TREE_TYPE (op)) == INTEGER_TYPE)
+ 	  return false;
+ 
+ 	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)))
+ 	    || !tree_ssa_useless_type_conversion_1 (TREE_TYPE (type),
+ 						    TREE_TYPE (op0))
+ 	    || !tree_ssa_useless_type_conversion_1 (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
+ 	    || !tree_ssa_useless_type_conversion_1 (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;
+       }
+ 
+ #if 0 /* Enable on pointer_plus branch.  */
+     /* TODO: disallow other arithmetic on pointers.  */
+     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
+ 	    || !tree_ssa_useless_type_conversion_1 (type, TREE_TYPE (op0))
+ 	    || !tree_ssa_useless_type_conversion_1 (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;
+       }
+ #endif
+ 
+     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 ((TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE
+ 	     && !tree_ssa_useless_type_conversion_1 (type, TREE_TYPE (op1)))
+ 	    || (TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE
+ 	        && !tree_ssa_useless_type_conversion_1 (type, TREE_TYPE (op2))))
+ 	  {
+ 	    error ("type mismatch in conditional expression");
+ 	    debug_generic_stmt (TREE_TYPE (expr));
+ 	    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);
+ 	if (!is_gimple_addressable (op))
+ 	  {
+ 	    error ("invalid operand in unary expression");
+ 	    return true;
+ 	  }
+ 	if (!tree_ssa_useless_type_conversion_1 (type, build_pointer_type (TREE_TYPE (op)))
+ 	    /* FIXME: a longstanding wart, &a == &a[0].  */
+ 	    && (TREE_CODE (TREE_TYPE (op)) != ARRAY_TYPE
+ 		|| !tree_ssa_useless_type_conversion_1 (type, build_pointer_type (TREE_TYPE (TREE_TYPE (op))))))
+ 	  {
+ 	    error ("type mismatch in address expression");
+ 	    debug_generic_stmt (TREE_TYPE (expr));
+ 	    debug_generic_stmt (TREE_TYPE (op));
+ 	    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;
+ 	  }
+ 
+ 	if ((TREE_CODE (TREE_TYPE (op0)) != INTEGER_TYPE
+ 	     && TREE_CODE (TREE_TYPE (op0)) != BOOLEAN_TYPE)
+ 	    || (TREE_CODE (TREE_TYPE (op1)) != INTEGER_TYPE
+ 		&& TREE_CODE (TREE_TYPE (op1)) != BOOLEAN_TYPE)
+ 	    || (TREE_CODE (type) != INTEGER_TYPE
+ 		&& TREE_CODE (type) != BOOLEAN_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 only have boolean type
+ 	   arguments but integer result types.  */
+ 	if ((TREE_CODE (TREE_TYPE (op)) != INTEGER_TYPE
+ 	     && TREE_CODE (TREE_TYPE (op)) != BOOLEAN_TYPE)
+ 	    || (TREE_CODE (type) != INTEGER_TYPE
+ 		&& TREE_CODE (type) != BOOLEAN_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.  This is going to be difficult with non-unit-at-a-time
+ 	 gimplifying.  */
+       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;
+ 	  }
+ 	/* Gimplification removes pointer type conversion like for
+ 	   '(void *) f != (void *) r' which causes the following check
+ 	   to fail if f and r are in no way compatible.
+ 	   FIXME: one solution is to allow arbitrary pointer comparisons.
+ 	   FIXME2: we allow arbitrary integral types as result of a
+ 	   comparison.
+ 	   FIXME3: for comparisons we don't have a expression type that
+ 	   relates to the operands, so we should require || instead of &&
+ 	   for the operands check.
+ 	   FIXME4: getting rid of the void * special handling in
+ 	   tree_ssa_useless_type_conversion_1 solves the gimplifier issue.  */
+ #if 0
+ 	if ((!(POINTER_TYPE_P (TREE_TYPE (op0))
+ 	       && POINTER_TYPE_P (TREE_TYPE (op1)))
+ 	     && (!tree_ssa_useless_type_conversion_1 (TREE_TYPE (op0), TREE_TYPE (op1))
+ 		 || !tree_ssa_useless_type_conversion_1 (TREE_TYPE (op1), TREE_TYPE (op0)))))
+ #endif
+ #if 1
+ 	if (!tree_ssa_useless_type_conversion_1 (TREE_TYPE (op0), TREE_TYPE (op1))
+ 	    || !tree_ssa_useless_type_conversion_1 (TREE_TYPE (op1), TREE_TYPE (op0))
+ 	    || !INTEGRAL_TYPE_P (type))
+ #endif
+ 	  {
+ 	    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 (!tree_ssa_useless_type_conversion_1 (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);
+ 
+   return verify_gimple_expr (rhs) || verify_gimple_expr (lhs);
+ }
+ 
+ /* 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 ASM_EXPR:
+       return false;
+ 
+     default:
+       gcc_unreachable ();
+     }
+ }
+ 
+ /* Verify the GIMPLE statements inside the statement list STMTS.  */
+ 
+ static 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.  */
Index: gcc/tree-flow.h
===================================================================
*** gcc.orig/tree-flow.h	2007-05-31 11:41:37.000000000 +0200
--- gcc/tree-flow.h	2007-05-31 12:10:56.000000000 +0200
*************** extern void bsi_commit_edge_inserts (voi
*** 753,758 ****
--- 753,759 ----
  extern void notice_special_calls (tree);
  extern void clear_special_calls (void);
  extern void verify_stmts (void);
+ extern void verify_gimple (void);
  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,


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]