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. (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: r126206
This commit is contained in:
parent
bc90eb85d9
commit
8ad0217501
5 changed files with 166 additions and 45 deletions
|
@ -1,3 +1,21 @@
|
|||
2007-07-02 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
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.
|
||||
(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-02 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* tree-nrv.c (dest_safe_for_nrv_p): Grok any handled_component_p,
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2007-07-02 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
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 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* g++.dg/opt/nrv12.C: New test.
|
||||
|
|
50
gcc/testsuite/gcc.dg/tree-ssa/pr31966.c
Normal file
50
gcc/testsuite/gcc.dg/tree-ssa/pr31966.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* Contributed by Jack Lloyd <lloyd@randombit.net> */
|
||||
|
||||
/* { 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;
|
||||
}
|
18
gcc/testsuite/gfortran.dg/pr32533.f90
Normal file
18
gcc/testsuite/gfortran.dg/pr32533.f90
Normal file
|
@ -0,0 +1,18 @@
|
|||
! { dg-do run }
|
||||
! { dg-options "-O2 -ftree-vectorize -ffast-math" }
|
||||
!
|
||||
! Contributed by Joost VandeVondele <jv244@cam.ac.uk>
|
||||
!
|
||||
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
|
|
@ -114,7 +114,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,
|
||||
|
@ -144,7 +145,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;
|
||||
|
@ -164,11 +164,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. */
|
||||
|
@ -192,7 +192,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,12 +275,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
|
||||
|
@ -578,7 +577,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;
|
||||
|
||||
|
@ -615,13 +622,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)
|
||||
|
@ -642,6 +649,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 = build2 (TRUTH_AND_EXPR, boolean_type_node,
|
||||
unshare_expr (prev_cond), cond);
|
||||
|
@ -649,22 +661,30 @@ add_to_dst_predicate_list (struct loop * loop, basic_block bb,
|
|||
bsi_insert_before (bsi, tmp_stmt, BSI_SAME_STMT);
|
||||
new_cond = GIMPLE_STMT_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);
|
||||
}
|
||||
|
||||
|
@ -677,13 +697,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)
|
||||
|
@ -704,42 +723,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
|
||||
|
@ -759,7 +791,7 @@ find_phi_replacement_condition (struct loop *loop,
|
|||
|
||||
gcc_assert (*cond);
|
||||
|
||||
return first_bb;
|
||||
return first_edge->src;
|
||||
}
|
||||
|
||||
|
||||
|
@ -791,10 +823,6 @@ replace_phi_with_cond_gimple_modify_stmt (tree phi, tree cond,
|
|||
/* 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)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue