This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
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: ;
}
}