This is the mail archive of the gcc@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]

Re: tree_ssa_useless_type_conversions


> In message <20031111085648.GA1729@kam.mff.cuni.cz>, Jan Hubicka writes:
>  >I am having problem to think of how to do type checking in such a
>  >relaxed typing system.  Gimple specifies that types must match.
> I think we need to update the gimple documentation.  We have relaxed
> the requirement that types must match exactly.
> 
>  >If I
>  >write tree_ssa_types_compatible_p predicate that duplicate the code of
>  >useless_type_conversion, I run into proplem that the function is not
>  >transitive nor symmetric and thus we do not produce equivalence classes.
> Yup.  There are cases when it can't be symmetric, particularly in regards
> to casting pointer types.
> 
>  >We may change type twice, both times doing allowed useless conversion
>  >and end up with non-useless conversion.
> That would be a bug.  Specifics please (ie compilable code).

Here is the patch I am using.  I am running out of time, so it is not
updated for current tree (sorry), the verify_flow_info changes has been
partly committed, so you need to apply only the
tree_ssa_types_compatible check.
The checks fails on several places in the testsuite...

Honza

Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.213.2.60
diff -c -3 -p -r1.213.2.60 fold-const.c
*** fold-const.c	9 Nov 2003 02:35:15 -0000	1.213.2.60
--- fold-const.c	9 Nov 2003 20:42:13 -0000
*************** nondestructive_fold_binary_to_constant (
*** 9106,9111 ****
--- 9106,9119 ----
    tree subop1;
    tree tem;
  
+ #if 1
+   /* Types of operands must match. if not something is broken elsewhere.  */
+   if (!tree_ssa_types_compatible_p (TREE_TYPE (op0), TREE_TYPE (op1))
+       || (TREE_CODE_CLASS (code) != '<' && !tree_ssa_types_compatible_p (type, TREE_TYPE (op0)))
+       || (TREE_CODE_CLASS (code) != '<' && !tree_ssa_types_compatible_p (type, TREE_TYPE (op1))))
+     abort ();
+ #endif
+ 
    /* If this is a commutative operation, and ARG0 is a constant, move it
       to ARG1 to reduce the number of tests below.  */
    if (commutative_tree_code (code)
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.142
diff -c -3 -p -r1.1.4.142 tree-flow.h
*** tree-flow.h	8 Nov 2003 09:49:19 -0000	1.1.4.142
--- tree-flow.h	9 Nov 2003 20:42:14 -0000
*************** extern void ssa_remove_edge (edge);
*** 524,529 ****
--- 526,532 ----
  extern edge ssa_redirect_edge (edge, basic_block);
  extern void set_is_used (tree);
  extern bool tree_ssa_useless_type_conversion (tree);
+ extern bool tree_ssa_types_compatible_p (tree, tree);
  extern void build_dominator_tree (dominance_info);
  extern unsigned int next_ssa_version;
  
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.146
diff -c -3 -p -r1.1.4.146 tree-ssa.c
*** tree-ssa.c	8 Nov 2003 18:17:28 -0000	1.1.4.146
--- tree-ssa.c	9 Nov 2003 20:42:14 -0000
*************** get_def_blocks_for (tree var)
*** 2380,2385 ****
--- 2352,2398 ----
  
    dm.var = var;
    return (struct def_blocks_d *) htab_find (def_blocks, &dm);
+ }
+ 
+ bool
+ tree_ssa_types_compatible_p (tree type1, tree type2)
+ {
+ 	return true;
+   /* If the inner and outer types are effectively the same, then
+      strip the type conversion and enter the equivalence into
+      the table.  */
+   if (type1 == type2
+       || TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
+     return true;
+ 
+   /* If the outer type is a (void *), then we can enter the
+      equivalence into the table.  The opposite is not true since
+      that conversion would result in a loss of information if
+      the equivalence was used.  Consider an indirect function call
+      where we need to know the exact type of the function to
+      correctly implement the ABI.  */
+   else if (POINTER_TYPE_P (type1) && POINTER_TYPE_P (type2)
+ 	   && TREE_CODE (TREE_TYPE (type2)) == VOID_TYPE)
+     return true;
+ 
+   /* Pointers and references are equivalent once we get to GENERIC,
+      so strip conversions that just switch between them.  */
+   else if (POINTER_TYPE_P (type1) && POINTER_TYPE_P (type2)
+ 	   && TREE_TYPE (type1) == TREE_TYPE (type2))
+     return true;
+ 
+   /* If both the inner and outer types are integral types, then
+      we can enter the equivalence if they have the same mode
+      and signedness and precision (The type _Bool can have size of 4
+      (only happens on powerpc-darwin right now but can happen on any 
+      target that defines BOOL_TYPE_SIZE to be INT_TYPE_SIZE) and a
+      precision of 1 while unsigned int is the same expect for a 
+      precision of 4 so testing of precision is nessary).  */
+   else if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2)
+ 	   && TYPE_MODE (type1) == TYPE_MODE (type2)
+ 	   && TREE_UNSIGNED (type1) == TREE_UNSIGNED (type2)
+ 	   && TYPE_PRECISION (type1) == TYPE_PRECISION (type2))
+     return true;
  }
  
  /* Return true if EXPR is a useless type conversion, otherwise return
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.202
diff -c -3 -p -r1.1.4.202 tree-cfg.c
*** tree-cfg.c	9 Nov 2003 16:03:38 -0000	1.1.4.202
--- tree-cfg.c	9 Nov 2003 20:42:14 -0000
*************** tree_verify_flow_info (void)
*** 3494,3515 ****
  
    FOR_EACH_BB (bb)
      {
        bsi = bsi_last (bb);
        if (bsi_end_p (bsi))
  	continue;
  
        stmt = bsi_stmt (bsi);
        switch (TREE_CODE (stmt))
  	{
  	case COND_EXPR:
! 	  if (TREE_CODE (COND_EXPR_THEN (stmt)) != GOTO_EXPR
! 	      || TREE_CODE (COND_EXPR_ELSE (stmt)) != GOTO_EXPR)
  	    {
! 	      fprintf (stderr, "Structured COND_EXPR at end of bb %d\n",
! 		       bb->index);
  	      err = 1;
  	    }
  	  break;
  	default: ;
  	}
      }
--- 3557,3801 ----
  
    FOR_EACH_BB (bb)
      {
+       edge e;
+       bool last = false;
+       tree phi;
+       int i;
+ 
+       for (e = bb->pred; e; e = e->pred_next)
+ 	if (e->aux)
+ 	  {
+ 	    error ("Aux pointer initialized for edge %d->%d\n", e->src->index, e->dest->index);
+ 	    err = 1;
+ 	  }
+       phi = phi_nodes (bb);
+       for ( ; phi; phi = TREE_CHAIN (phi))
+ 	{
+ 	  int phi_num_args = PHI_NUM_ARGS (phi);
+ 
+ 	  for (e = bb->pred; e; e = e->pred_next)
+ 	    e->aux = (void *)1;
+ 	  for (i = 0; i < phi_num_args; i++)
+ 	    {
+ 	      e = PHI_ARG_EDGE (phi, i);
+ 	      if (e->dest != bb)
+ 		{
+ 		  error ("Phi node for edge %d->%d in %d\n", e->src->index, e->dest->index, bb->index);
+ 		  err = 1;
+ 		}
+ 	      if (e->aux == (void *)0)
+ 		{
+ 		  error ("Phi node for dead edge %d->%d\n", e->src->index, e->dest->index);
+ 		  err = 1;
+ 		}
+ 	      if (e->aux == (void *)2)
+ 		{
+ 		  error ("Phi node duplicated for edge %d->%d\n", e->src->index, e->dest->index);
+ 		  err = 1;
+ 		}
+ 	      if (!tree_ssa_types_compatible_p (TREE_TYPE (PHI_RESULT (phi)), TREE_TYPE (PHI_ARG_DEF (phi, i))))
+ 		{
+ 		  debug_tree (PHI_RESULT (phi));
+ 		  debug_tree (PHI_ARG_DEF (phi, i));
+ 		  error ("Phi node types conflict for edge %d->%d\n", e->src->index, e->dest->index);
+ 		  err = 1;
+ 		}
+ 	      e->aux = (void *)2;
+ 	    }
+ 	  for (e = bb->pred; e; e = e->pred_next)
+ 	    {
+ 	      if (e->aux != (void *)2)
+ 		{
+ 		  error ("Edge %d->%d miss phi node entry\n", e->src->index, e->dest->index);
+ 		  err = 1;
+ 		}
+ 	      e->aux = (void *)0;
+ 	    }
+ 	}
+ 
+       /* Skip labels on the start of basic block.  */
+       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ 	{
+ 	  if (TREE_CODE (bsi_stmt (bsi)) != LABEL_EXPR)
+ 	    break;
+ 	  if (label_to_block (LABEL_EXPR_LABEL (bsi_stmt (bsi))) != bb)
+ 	    {
+ 	      error ("Label to block does not match in bb %d\n", bb->index);
+ 	      err = 1;
+ 	    }
+ 	}
+       /* Verify that body of basic block is free of control flow.  */
+       for (; !bsi_end_p (bsi); bsi_next (&bsi))
+ 	{
+ 	  tree stmt = bsi_stmt (bsi);
+ 
+ 	  if (last)
+ 	    {
+ 	      error ("Control flow in the middle of basic block %d\n", bb->index);
+ 	      err = 1;
+ 	    }
+ 	  if (stmt_ends_bb_p (stmt))
+ 	    last = true;
+ 	  if (TREE_CODE (stmt) == LABEL_EXPR)
+ 	    {
+ 	      error ("Label in the middle of basic block %d\n", bb->index);
+ 	      err = 1;
+ 	    }
+ 	}
        bsi = bsi_last (bb);
        if (bsi_end_p (bsi))
  	continue;
  
+       for (e = bb->succ; e; e = e->succ_next)
+ 	if (e->flags & EDGE_FALLTHRU && e->dest != bb->next_bb)
+ 	  {
+ 	    error ("Fallthru edge of bb %d does not point to following block\n", bb->index);
+ 	    err = 1;
+ 	  }
+ 
+ 
        stmt = bsi_stmt (bsi);
        switch (TREE_CODE (stmt))
  	{
  	case COND_EXPR:
! 	  {
! 	    edge true_edge;
! 	    edge false_edge;
! 	    if (TREE_CODE (COND_EXPR_THEN (stmt)) != GOTO_EXPR
! 		|| TREE_CODE (COND_EXPR_ELSE (stmt)) != GOTO_EXPR)
! 	      {
! 		error ("Structured COND_EXPR at end of bb %d\n", bb->index);
! 		err = 1;
! 	      }
! 	    if (bb->succ->flags & EDGE_TRUE_VALUE)
! 	      true_edge = bb->succ, false_edge = bb->succ->succ_next;
! 	    else
! 	      false_edge = bb->succ, true_edge = bb->succ->succ_next;
! 	    if (!true_edge || !false_edge
! 		|| !(true_edge->flags & EDGE_TRUE_VALUE)
! 		|| !(false_edge->flags & EDGE_FALSE_VALUE)
! 		|| (true_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
! 		|| (false_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
! 		|| bb->succ->succ_next->succ_next)
! 	      {
! 		error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		err = 1;
! 	      }
! 	    if (!has_label_p (true_edge->dest,
! 			      GOTO_DESTINATION (COND_EXPR_THEN (stmt)))
! 		|| !has_label_p (false_edge->dest,
! 				 GOTO_DESTINATION (COND_EXPR_ELSE (stmt))))
! 	      {
! 		error ("Label does not match edge at end of bb %d\n", bb->index);
! 		err = 1;
! 	      }
! 	  }
! 	  break;
! 	case GOTO_EXPR:
! 	  if (simple_goto_p (stmt))
! 	    {
! 	      if (!bb->succ || bb->succ->succ_next
! 		  || (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
! 					 | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
! 		{
! 		  error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		  err = 1;
! 		}
! 	      if (!has_label_p (bb->succ->dest, GOTO_DESTINATION (stmt)))
! 		{
! 		  error ("Label does not match edge at end of bb %d\n", bb->index);
! 		  err = 1;
! 		}
! 	    }
! 	  else
! 	    {
! 	      /* We shall double check that the labels in destination blocks have
! 	         address taken.  */
! 
! 	      for (e = bb->succ; e; e = e->succ_next)
! 		if ((e->flags & (EDGE_FALLTHRU | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))
! 		    || !(e->flags & EDGE_ABNORMAL))
! 		  {
! 		    error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		    err = 1;
! 		  }
! 	      if (nonlocal_goto_p (stmt))
! 		{
! 	          for (e = bb->succ; e; e = e->succ_next)
! 		    if (e->dest == EXIT_BLOCK_PTR)
! 		      break;
! 		  if (!e)
! 		    {
! 		      error ("Missing edge to exit past nonlocal goto bb %d\n", bb->index);
! 		      err = 1;
! 		    }
! 		}
! 	    }
! 	  break;
! 	case RETURN_EXPR:
! 	  if (!bb->succ || bb->succ->succ_next
! 	      || (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
! 		  		     | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
  	    {
! 	      error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 	      err = 1;
! 	    }
! 	  if (bb->succ->dest != EXIT_BLOCK_PTR)
! 	    {
! 	      error ("Return edge does not point to exit in bb %d\n", bb->index);
  	      err = 1;
  	    }
  	  break;
+ 	case SWITCH_EXPR:
+ 	  {
+ 	    edge e;
+ 	    size_t i, n;
+ 	    tree vec;
+ 
+ 	    vec = SWITCH_LABELS (stmt);
+ 	    n = TREE_VEC_LENGTH (vec);
+ 
+ 	    /* Mark all destination basic block.  */
+ 	    for (i = 0; i < n; ++i)
+ 	      {
+ 		tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
+ 		basic_block label_bb = label_to_block (lab);
+ 
+ 		if (label_bb->aux && label_bb->aux != (void *)1)
+ 		  abort ();
+ 		label_bb->aux = (void *)1;
+ 	      }
+ 
+ 	    for (e = bb->succ; e; e = e->succ_next)
+ 	      {
+ 		if (!e->dest->aux)
+ 		  {
+ 		    error ("Extra outgoing edge %d->%d\n", bb->index, e->dest->index);
+ 		    err = 1;
+ 		  }
+ 		e->dest->aux = (void *)2;
+ 		if ((e->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
+ 					   | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
+ 		  {
+ 		    error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
+ 		    err = 1;
+ 		  }
+ 	      }
+ 	    /* Check we do have all of them.  */
+ 	    for (i = 0; i < n; ++i)
+ 	      {
+ 		tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
+ 		basic_block label_bb = label_to_block (lab);
+ 
+ 		if (label_bb->aux != (void *)2)
+ 		  {
+ 		    error ("Missing edge %i->%i\n", bb->index, label_bb->index);
+ 		    err = 1;
+ 		  }
+ 	      }
+ 	    for (e = bb->succ; e; e = e->succ_next)
+ 	      e->dest->aux = (void *)0;
+ 	  }
  	default: ;
  	}
      }


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