From: Uros Bizjak Date: Wed, 4 Jul 2007 05:49:31 +0000 (+0200) Subject: re PR tree-optimization/31966 (Miscompiles valid code with -ftree-vectorize) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bb81c73518a414fc93148fad3640c36ad2e0d32d;p=thirdparty%2Fgcc.git re PR tree-optimization/31966 (Miscompiles valid code with -ftree-vectorize) PR tree-optimization/31966 PR tree-optimization/32533 * tree-if-conv.c (add_to_dst_predicate_list): Use "edge", not "basic_block" description as its third argument. Update function calls to get destination bb from "edge" argument. Save "cond" into aux field of the edge. Update prototype for changed arguments. (if_convertible_loop_p): Clear aux field of incoming edges if bb contains phi node. (find_phi_replacement_condition): Operate on incoming edges, not on predecessor blocks. If there is a condition saved in the incoming edge aux field, AND it with incoming bb predicate. Return source bb of the first edge. (clean_predicate_lists): Clean aux field of outgoing node edges. (tree_if_conversion): Do not initialize cond variable. Move variable declaration into the loop. (replace_phi_with_cond_gimple_modify_stmt): Remove unneded initializations of new_stmt, arg0 and arg1 variables. testsuite/ChangeLog: PR tree-optimization/31966 PR tree-optimization/32533 * gcc.dg/tree-ssa/pr31966.c: New runtime test. * gfortran.dg/pr32533.f90: Ditto. From-SVN: r126302 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7fd3fc5a3729..2fadd3d9b3d6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2007-07-04 Uros Bizjak + + PR tree-optimization/31966 + PR tree-optimization/32533 + * tree-if-conv.c (add_to_dst_predicate_list): Use "edge", not + "basic_block" description as its third argument. Update function + calls to get destination bb from "edge" argument. Save "cond" into + aux field of the edge. Update prototype for changed arguments. + (if_convertible_loop_p): Clear aux field of incoming edges if bb + contains phi node. + (find_phi_replacement_condition): Operate on incoming edges, not + on predecessor blocks. If there is a condition saved in the + incoming edge aux field, AND it with incoming bb predicate. + Return source bb of the first edge. + (clean_predicate_lists): Clean aux field of outgoing node edges. + (tree_if_conversion): Do not initialize cond variable. Move + variable declaration into the loop. + (replace_phi_with_cond_gimple_modify_stmt): Remove unneded + initializations of new_stmt, arg0 and arg1 variables. + 2007-07-04 Kaz Kojima PR target/32506 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4136b9795742..2181c0f45685 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2007-07-04 Uros Bizjak + + PR tree-optimization/31966 + PR tree-optimization/32533 + * gcc.dg/tree-ssa/pr31966.c: New runtime test. + * gfortran.dg/pr32533.f90: Ditto. + 2007-07-02 Kaveh R. Ghazi * gcc.dg/c99-math.h: Fix typo. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr31966.c b/gcc/testsuite/gcc.dg/tree-ssa/pr31966.c new file mode 100644 index 000000000000..a18f9d041ee9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr31966.c @@ -0,0 +1,50 @@ +/* Contributed by Jack Lloyd */ + +/* { dg-options "-O2 -ftree-vectorize" } */ +/* { dg-options "-O2 -ftree-vectorize -march=nocona" { target { i?86-*-* x86_64-*-* } } } */ + +typedef unsigned long long word; + +const unsigned int MP_WORD_BITS = 64; +const word MP_WORD_MASK = ~((word)0); +const word MP_WORD_TOP_BIT = (word)1 << (8*sizeof(word) - 1); + +extern void abort (void); + +word do_div(word n1, word n0, word d) +{ + word high = n1 % d, quotient = 0; + unsigned int j; + + for(j = 0; j != MP_WORD_BITS; ++j) + { + word high_top_bit = (high & MP_WORD_TOP_BIT); + + high <<= 1; + high |= (n0 >> (MP_WORD_BITS-1-j)) & 1; + quotient <<= 1; + + if(high_top_bit || high >= d) + { + high -= d; + quotient |= 1; + } + } + + return quotient; +} + +int main() +{ + word result; + + result = do_div(0x0000000000200000ll, + 0x0000000000000000ll, + 0x86E53497CE000000ll); + + + if (result != 0x3CBA83) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gfortran.dg/pr32533.f90 b/gcc/testsuite/gfortran.dg/pr32533.f90 new file mode 100644 index 000000000000..c312415eb02a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr32533.f90 @@ -0,0 +1,18 @@ +! { dg-do run } +! { dg-options "-O2 -ftree-vectorize -ffast-math" } +! +! Contributed by Joost VandeVondele +! +SUBROUTINE T(nsubcell,sab_max,subcells) + INTEGER, PARAMETER :: dp=KIND(0.0D0) + REAL(dp) :: sab_max(3), subcells,nsubcell(3) + nsubcell(:) = MIN(MAX(1,NINT(0.5_dp*subcells/sab_max(:))),20) +END SUBROUTINE T + +INTEGER, PARAMETER :: dp=KIND(0.0D0) +REAL(dp) :: sab_max(3), subcells,nsubcell(3) +subcells=2.0_dp +sab_max=0.590060749244805_dp +CALL T(nsubcell,sab_max,subcells) +IF (ANY(nsubcell.NE.2.0_dp)) CALL ABORT() +END diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index 6643d5b65ad9..77da47959144 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -113,7 +113,8 @@ static bool if_convertible_stmt_p (struct loop *, basic_block, tree); static bool if_convertible_bb_p (struct loop *, basic_block, basic_block); static bool if_convertible_loop_p (struct loop *, bool); static void add_to_predicate_list (basic_block, tree); -static tree add_to_dst_predicate_list (struct loop * loop, basic_block, tree, tree, +static tree add_to_dst_predicate_list (struct loop * loop, edge, + tree, tree, block_stmt_iterator *); static void clean_predicate_lists (struct loop *loop); static basic_block find_phi_replacement_condition (struct loop *loop, @@ -143,7 +144,6 @@ tree_if_conversion (struct loop *loop, bool for_vectorizer) { basic_block bb; block_stmt_iterator itr; - tree cond; unsigned int i; ifc_bbs = NULL; @@ -163,11 +163,11 @@ tree_if_conversion (struct loop *loop, bool for_vectorizer) return false; } - cond = NULL_TREE; - /* Do actual work now. */ for (i = 0; i < loop->num_nodes; i++) { + tree cond; + bb = ifc_bbs [i]; /* Update condition using predicate list. */ @@ -191,7 +191,6 @@ tree_if_conversion (struct loop *loop, bool for_vectorizer) basic_block bb_n = single_succ (bb); if (cond != NULL_TREE) add_to_predicate_list (bb_n, cond); - cond = NULL_TREE; } } @@ -275,12 +274,12 @@ tree_if_convert_cond_expr (struct loop *loop, tree stmt, tree cond, /* Add new condition into destination's predicate list. */ /* If 'c' is true then TRUE_EDGE is taken. */ - add_to_dst_predicate_list (loop, true_edge->dest, cond, + add_to_dst_predicate_list (loop, true_edge, cond, unshare_expr (c), bsi); /* If 'c' is false then FALSE_EDGE is taken. */ c2 = invert_truthvalue (unshare_expr (c)); - add_to_dst_predicate_list (loop, false_edge->dest, cond, c2, bsi); + add_to_dst_predicate_list (loop, false_edge, cond, c2, bsi); /* Now this conditional statement is redundant. Remove it. But, do not remove exit condition! Update exit condition @@ -565,7 +564,15 @@ if_convertible_loop_p (struct loop *loop, bool for_vectorizer ATTRIBUTE_UNUSED) /* ??? Check data dependency for vectorizer. */ /* What about phi nodes ? */ - for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) + phi = phi_nodes (bb); + + /* Clear aux field of incoming edges to a bb with a phi node. */ + if (phi) + FOR_EACH_EDGE (e, ei, bb->preds) + e->aux = NULL; + + /* Check statements. */ + for (; phi; phi = PHI_CHAIN (phi)) if (!if_convertible_phi_p (loop, bb, phi)) return false; @@ -602,13 +609,13 @@ add_to_predicate_list (basic_block bb, tree new_cond) existing condition. */ static tree -add_to_dst_predicate_list (struct loop * loop, basic_block bb, +add_to_dst_predicate_list (struct loop * loop, edge e, tree prev_cond, tree cond, block_stmt_iterator *bsi) { tree new_cond = NULL_TREE; - if (!flow_bb_inside_loop_p (loop, bb)) + if (!flow_bb_inside_loop_p (loop, e->dest)) return NULL_TREE; if (prev_cond == boolean_true_node || !prev_cond) @@ -629,6 +636,11 @@ add_to_dst_predicate_list (struct loop * loop, basic_block bb, if (tmp_stmts2) bsi_insert_before (bsi, tmp_stmts2, BSI_SAME_STMT); + /* Add the condition to aux field of the edge. In case edge + destination is a PHI node, this condition will be ANDed with + block predicate to construct complete condition. */ + e->aux = cond; + /* new_cond == prev_cond AND cond */ tmp = build (TRUTH_AND_EXPR, boolean_type_node, unshare_expr (prev_cond), cond); @@ -636,22 +648,30 @@ add_to_dst_predicate_list (struct loop * loop, basic_block bb, bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT); new_cond = TREE_OPERAND (tmp_stmt, 0); } - add_to_predicate_list (bb, new_cond); + add_to_predicate_list (e->dest, new_cond); return new_cond; } -/* During if-conversion aux field from basic block is used to hold predicate - list. Clean each basic block's predicate list for the given LOOP. */ +/* During if-conversion aux field from basic block structure is used to hold + predicate list. Clean each basic block's predicate list for the given LOOP. + Also clean aux field of succesor edges, used to hold true and false + condition from conditional expression. */ static void clean_predicate_lists (struct loop *loop) { basic_block *bb; unsigned int i; + edge e; + edge_iterator ei; + bb = get_loop_body (loop); for (i = 0; i < loop->num_nodes; i++) - bb[i]->aux = NULL; - + { + bb[i]->aux = NULL; + FOR_EACH_EDGE (e, ei, bb[i]->succs) + e->aux = NULL; + } free (bb); } @@ -664,13 +684,12 @@ find_phi_replacement_condition (struct loop *loop, basic_block bb, tree *cond, block_stmt_iterator *bsi) { - basic_block first_bb = NULL; - basic_block second_bb = NULL; + edge first_edge, second_edge; tree tmp_cond, new_stmts; gcc_assert (EDGE_COUNT (bb->preds) == 2); - first_bb = (EDGE_PRED (bb, 0))->src; - second_bb = (EDGE_PRED (bb, 1))->src; + first_edge = EDGE_PRED (bb, 0); + second_edge = EDGE_PRED (bb, 1); /* Use condition based on following criteria: 1) @@ -691,42 +710,55 @@ find_phi_replacement_condition (struct loop *loop, S3: x = (c == d) ? b : a; S3 is preferred over S1 and S2*, Make 'b' first_bb and use - its condition. + its condition. 4) If pred B is dominated by pred A then use pred B's condition. See PR23115. */ /* Select condition that is not TRUTH_NOT_EXPR. */ - tmp_cond = first_bb->aux; + tmp_cond = (first_edge->src)->aux; if (TREE_CODE (tmp_cond) == TRUTH_NOT_EXPR) { - basic_block tmp_bb; - tmp_bb = first_bb; - first_bb = second_bb; - second_bb = tmp_bb; + edge tmp_edge; + + tmp_edge = first_edge; + first_edge = second_edge; + second_edge = tmp_edge; } /* Check if FIRST_BB is loop header or not and make sure that FIRST_BB does not dominate SECOND_BB. */ - if (first_bb == loop->header - || dominated_by_p (CDI_DOMINATORS, second_bb, first_bb)) + if (first_edge->src == loop->header + || dominated_by_p (CDI_DOMINATORS, + second_edge->src, first_edge->src)) { - tmp_cond = second_bb->aux; - if (TREE_CODE (tmp_cond) == TRUTH_NOT_EXPR) - { - /* Select non loop header condition but do not switch basic blocks. */ - *cond = invert_truthvalue (unshare_expr (tmp_cond)); - } + *cond = (second_edge->src)->aux; + + /* If there is a condition on an incoming edge, + AND it with the incoming bb predicate. */ + if (second_edge->aux) + *cond = build2 (TRUTH_AND_EXPR, boolean_type_node, + *cond, first_edge->aux); + + if (TREE_CODE (*cond) == TRUTH_NOT_EXPR) + /* We can be smart here and choose inverted + condition without switching bbs. */ + *cond = invert_truthvalue (*cond); else - { - /* Select non loop header condition. */ - first_bb = second_bb; - *cond = first_bb->aux; - } + /* Select non loop header bb. */ + first_edge = second_edge; } else - /* FIRST_BB is not loop header */ - *cond = first_bb->aux; + { + /* FIRST_BB is not loop header */ + *cond = (first_edge->src)->aux; + + /* If there is a condition on an incoming edge, + AND it with the incoming bb predicate. */ + if (first_edge->aux) + *cond = build2 (TRUTH_AND_EXPR, boolean_type_node, + *cond, first_edge->aux); + } /* Create temp. for the condition. Vectorizer prefers to have gimple value as condition. Various targets use different means to communicate @@ -746,7 +778,7 @@ find_phi_replacement_condition (struct loop *loop, gcc_assert (*cond); - return first_bb; + return first_edge->src; } @@ -777,10 +809,6 @@ replace_phi_with_cond_modify_expr (tree phi, tree cond, basic_block true_bb, /* Find basic block and initialize iterator. */ bb = bb_for_stmt (phi); - new_stmt = NULL_TREE; - arg_0 = NULL_TREE; - arg_1 = NULL_TREE; - /* Use condition that is not TRUTH_NOT_EXPR in conditional modify expr. */ if (EDGE_PRED (bb, 1)->src == true_bb) {