From: Richard Biener Date: Fri, 13 Oct 2017 07:02:55 +0000 (+0000) Subject: re PR tree-optimization/82451 ([GRAPHITE] codegen error in get_rename_from_scev) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a68f286ccc36bc6d5e483383e490e2531307466b;p=gcc.git re PR tree-optimization/82451 ([GRAPHITE] codegen error in get_rename_from_scev) 2017-10-13 Richard Biener PR tree-optimization/82451 Revert 2017-10-02 Richard Biener PR tree-optimization/82355 * graphite-isl-ast-to-gimple.c (build_iv_mapping): Also build a mapping for the enclosing loop but avoid generating one for the loop tree root. (copy_bb_and_scalar_dependences): Remove premature codegen error on PHIs in blocks duplicated into multiple places. * graphite-scop-detection.c (scop_detection::stmt_has_simple_data_refs_p): For a loop not in the region use it as loop and nest to analyze the DR in. (try_generate_gimple_bb): Likewise. * graphite-sese-to-poly.c (extract_affine_chrec): Adjust. (add_loop_constraints): For blocks in a loop not in the region create a dimension with a single iteration. * sese.h (gbb_loop_at_index): Remove assert. * cfgloop.c (loop_preheader_edge): For the loop tree root return the single successor of the entry block. * graphite-isl-ast-to-gimple.c (graphite_regenerate_ast_isl): Reset the SCEV hashtable and niters. * graphite-scop-detection.c (scop_detection::graphite_can_represent_scev): Add SCOP parameter, assert that we only have POLYNOMIAL_CHREC that vary in loops contained in the region. (scop_detection::graphite_can_represent_expr): Adjust. (scop_detection::stmt_has_simple_data_refs_p): For loops not in the region set loop to NULL. The nest is now the entry edge to the region. (try_generate_gimple_bb): Likewise. * sese.c (scalar_evolution_in_region): Adjust for instantiate_scev change. * tree-data-ref.h (graphite_find_data_references_in_stmt): Make nest parameter the edge into the region. (create_data_ref): Likewise. * tree-data-ref.c (dr_analyze_indices): Make nest parameter an entry edge into a region and adjust instantiate_scev calls. (create_data_ref): Likewise. (graphite_find_data_references_in_stmt): Likewise. (find_data_references_in_stmt): Pass the loop preheader edge from the nest argument. * tree-scalar-evolution.h (instantiate_scev): Make instantiate_below parameter the edge into the region. (instantiate_parameters): Use the loop preheader edge as entry. * tree-scalar-evolution.c (analyze_scalar_evolution): Handle NULL loop. (get_instantiated_value_entry): Make instantiate_below parameter the edge into the region. (instantiate_scev_name): Likewise. Adjust dominance checks, when we cannot use loop-based instantiation instantiate by walking use-def chains. (instantiate_scev_poly): Adjust. (instantiate_scev_binary): Likewise. (instantiate_scev_convert): Likewise. (instantiate_scev_not): Likewise. (instantiate_array_ref): Remove. (instantiate_scev_3): Likewise. (instantiate_scev_2): Likewise. (instantiate_scev_1): Likewise. (instantiate_scev_r): Do not blindly handle N-operand trees. Do not instantiate array-refs. Handle all constants and invariants. (instantiate_scev): Make instantiate_below parameter the edge into the region. (resolve_mixers): Use the loop preheader edge for the region parameter to instantiate_scev_r. * tree-ssa-loop-prefetch.c (determine_loop_nest_reuse): Adjust. * gcc.dg/graphite/pr82451.c: New testcase. * gfortran.dg/graphite/id-27.f90: Likewise. * gfortran.dg/graphite/pr82451.f: Likewise. From-SVN: r253707 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 890ee0e5d0e..bff2a6fe00d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,74 @@ +2017-10-13 Richard Biener + + PR tree-optimization/82451 + Revert + 2017-10-02 Richard Biener + + PR tree-optimization/82355 + * graphite-isl-ast-to-gimple.c (build_iv_mapping): Also build + a mapping for the enclosing loop but avoid generating one for + the loop tree root. + (copy_bb_and_scalar_dependences): Remove premature codegen + error on PHIs in blocks duplicated into multiple places. + * graphite-scop-detection.c + (scop_detection::stmt_has_simple_data_refs_p): For a loop not + in the region use it as loop and nest to analyze the DR in. + (try_generate_gimple_bb): Likewise. + * graphite-sese-to-poly.c (extract_affine_chrec): Adjust. + (add_loop_constraints): For blocks in a loop not in the region + create a dimension with a single iteration. + * sese.h (gbb_loop_at_index): Remove assert. + + * cfgloop.c (loop_preheader_edge): For the loop tree root + return the single successor of the entry block. + * graphite-isl-ast-to-gimple.c (graphite_regenerate_ast_isl): + Reset the SCEV hashtable and niters. + * graphite-scop-detection.c + (scop_detection::graphite_can_represent_scev): Add SCOP parameter, + assert that we only have POLYNOMIAL_CHREC that vary in loops + contained in the region. + (scop_detection::graphite_can_represent_expr): Adjust. + (scop_detection::stmt_has_simple_data_refs_p): For loops + not in the region set loop to NULL. The nest is now the + entry edge to the region. + (try_generate_gimple_bb): Likewise. + * sese.c (scalar_evolution_in_region): Adjust for + instantiate_scev change. + * tree-data-ref.h (graphite_find_data_references_in_stmt): + Make nest parameter the edge into the region. + (create_data_ref): Likewise. + * tree-data-ref.c (dr_analyze_indices): Make nest parameter an + entry edge into a region and adjust instantiate_scev calls. + (create_data_ref): Likewise. + (graphite_find_data_references_in_stmt): Likewise. + (find_data_references_in_stmt): Pass the loop preheader edge + from the nest argument. + * tree-scalar-evolution.h (instantiate_scev): Make instantiate_below + parameter the edge into the region. + (instantiate_parameters): Use the loop preheader edge as entry. + * tree-scalar-evolution.c (analyze_scalar_evolution): Handle + NULL loop. + (get_instantiated_value_entry): Make instantiate_below parameter + the edge into the region. + (instantiate_scev_name): Likewise. Adjust dominance checks, + when we cannot use loop-based instantiation instantiate by + walking use-def chains. + (instantiate_scev_poly): Adjust. + (instantiate_scev_binary): Likewise. + (instantiate_scev_convert): Likewise. + (instantiate_scev_not): Likewise. + (instantiate_array_ref): Remove. + (instantiate_scev_3): Likewise. + (instantiate_scev_2): Likewise. + (instantiate_scev_1): Likewise. + (instantiate_scev_r): Do not blindly handle N-operand trees. + Do not instantiate array-refs. Handle all constants and invariants. + (instantiate_scev): Make instantiate_below parameter + the edge into the region. + (resolve_mixers): Use the loop preheader edge for the region + parameter to instantiate_scev_r. + * tree-ssa-loop-prefetch.c (determine_loop_nest_reuse): Adjust. + 2017-10-13 Richard Biener PR tree-optimization/82525 diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c index 6911426787b..c3bd9c05013 100644 --- a/gcc/cfgloop.c +++ b/gcc/cfgloop.c @@ -1713,12 +1713,19 @@ loop_preheader_edge (const struct loop *loop) edge e; edge_iterator ei; - gcc_assert (loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS)); + gcc_assert (loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS) + && ! loops_state_satisfies_p (LOOPS_MAY_HAVE_MULTIPLE_LATCHES)); FOR_EACH_EDGE (e, ei, loop->header->preds) if (e->src != loop->latch) break; + if (! e) + { + gcc_assert (! loop_outer (loop)); + return single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)); + } + return e; } diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c index 9a9f8c86726..874941824cd 100644 --- a/gcc/graphite-isl-ast-to-gimple.c +++ b/gcc/graphite-isl-ast-to-gimple.c @@ -750,10 +750,8 @@ build_iv_mapping (vec iv_map, gimple_poly_bb_p gbb, if (codegen_error_p ()) t = integer_zero_node; - loop_p old_loop = gbb_loop_at_index (gbb, region, i - 2); - /* Record sth only for real loops. */ - if (loop_in_sese_p (old_loop, region)) - iv_map[old_loop->num] = t; + loop_p old_loop = gbb_loop_at_index (gbb, region, i - 1); + iv_map[old_loop->num] = t; } } @@ -1571,6 +1569,12 @@ graphite_regenerate_ast_isl (scop_p scop) update_ssa (TODO_update_ssa); checking_verify_ssa (true, true); rewrite_into_loop_closed_ssa (NULL, 0); + /* We analyzed evolutions of all SCOPs during SCOP detection + which cached evolutions. Now we've introduced PHIs for + liveouts which causes those cached solutions to be invalid + for code-generation purposes given we'd insert references + to SSA names not dominating their new use. */ + scev_reset (); } if (t.codegen_error_p ()) diff --git a/gcc/graphite-scop-detection.c b/gcc/graphite-scop-detection.c index 3cd99322b77..c7e1dba9423 100644 --- a/gcc/graphite-scop-detection.c +++ b/gcc/graphite-scop-detection.c @@ -381,7 +381,7 @@ public: Something like "i * n" or "n * m" is not allowed. */ - static bool graphite_can_represent_scev (tree scev); + static bool graphite_can_represent_scev (sese_l scop, tree scev); /* Return true when EXPR can be represented in the polyhedral model. @@ -934,7 +934,7 @@ scop_detection::graphite_can_represent_init (tree e) Something like "i * n" or "n * m" is not allowed. */ bool -scop_detection::graphite_can_represent_scev (tree scev) +scop_detection::graphite_can_represent_scev (sese_l scop, tree scev) { if (chrec_contains_undetermined (scev)) return false; @@ -945,13 +945,13 @@ scop_detection::graphite_can_represent_scev (tree scev) case BIT_NOT_EXPR: CASE_CONVERT: case NON_LVALUE_EXPR: - return graphite_can_represent_scev (TREE_OPERAND (scev, 0)); + return graphite_can_represent_scev (scop, TREE_OPERAND (scev, 0)); case PLUS_EXPR: case POINTER_PLUS_EXPR: case MINUS_EXPR: - return graphite_can_represent_scev (TREE_OPERAND (scev, 0)) - && graphite_can_represent_scev (TREE_OPERAND (scev, 1)); + return graphite_can_represent_scev (scop, TREE_OPERAND (scev, 0)) + && graphite_can_represent_scev (scop, TREE_OPERAND (scev, 1)); case MULT_EXPR: return !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 0))) @@ -959,18 +959,20 @@ scop_detection::graphite_can_represent_scev (tree scev) && !(chrec_contains_symbols (TREE_OPERAND (scev, 0)) && chrec_contains_symbols (TREE_OPERAND (scev, 1))) && graphite_can_represent_init (scev) - && graphite_can_represent_scev (TREE_OPERAND (scev, 0)) - && graphite_can_represent_scev (TREE_OPERAND (scev, 1)); + && graphite_can_represent_scev (scop, TREE_OPERAND (scev, 0)) + && graphite_can_represent_scev (scop, TREE_OPERAND (scev, 1)); case POLYNOMIAL_CHREC: /* Check for constant strides. With a non constant stride of 'n' we would have a value of 'iv * n'. Also check that the initial value can represented: for example 'n * m' cannot be represented. */ + gcc_assert (loop_in_sese_p (get_loop (cfun, + CHREC_VARIABLE (scev)), scop)); if (!evolution_function_right_is_integer_cst (scev) || !graphite_can_represent_init (scev)) return false; - return graphite_can_represent_scev (CHREC_LEFT (scev)); + return graphite_can_represent_scev (scop, CHREC_LEFT (scev)); default: break; @@ -994,7 +996,7 @@ scop_detection::graphite_can_represent_expr (sese_l scop, loop_p loop, tree expr) { tree scev = scalar_evolution_in_region (scop, loop, expr); - return graphite_can_represent_scev (scev); + return graphite_can_represent_scev (scop, scev); } /* Return true if the data references of STMT can be represented by Graphite. @@ -1003,12 +1005,15 @@ scop_detection::graphite_can_represent_expr (sese_l scop, loop_p loop, bool scop_detection::stmt_has_simple_data_refs_p (sese_l scop, gimple *stmt) { - loop_p nest; + edge nest; loop_p loop = loop_containing_stmt (stmt); if (!loop_in_sese_p (loop, scop)) - nest = loop; + { + nest = scop.entry; + loop = NULL; + } else - nest = outermost_loop_in_sese (scop, gimple_bb (stmt)); + nest = loop_preheader_edge (outermost_loop_in_sese (scop, gimple_bb (stmt))); auto_vec drs; if (! graphite_find_data_references_in_stmt (nest, loop, stmt, &drs)) @@ -1019,7 +1024,7 @@ scop_detection::stmt_has_simple_data_refs_p (sese_l scop, gimple *stmt) FOR_EACH_VEC_ELT (drs, j, dr) { for (unsigned i = 0; i < DR_NUM_DIMENSIONS (dr); ++i) - if (! graphite_can_represent_scev (DR_ACCESS_FN (dr, i))) + if (! graphite_can_represent_scev (scop, DR_ACCESS_FN (dr, i))) return false; } @@ -1376,12 +1381,15 @@ try_generate_gimple_bb (scop_p scop, basic_block bb) vec reads = vNULL; sese_l region = scop->scop_info->region; - loop_p nest; + edge nest; loop_p loop = bb->loop_father; if (!loop_in_sese_p (loop, region)) - nest = loop; + { + nest = region.entry; + loop = NULL; + } else - nest = outermost_loop_in_sese (region, bb); + nest = loop_preheader_edge (outermost_loop_in_sese (region, bb)); for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c index 50b6fe8dbb2..ed6cbeccca1 100644 --- a/gcc/graphite-sese-to-poly.c +++ b/gcc/graphite-sese-to-poly.c @@ -86,7 +86,7 @@ extract_affine_chrec (scop_p s, tree e, __isl_take isl_space *space) isl_pw_aff *lhs = extract_affine (s, CHREC_LEFT (e), isl_space_copy (space)); isl_pw_aff *rhs = extract_affine (s, CHREC_RIGHT (e), isl_space_copy (space)); isl_local_space *ls = isl_local_space_from_space (space); - unsigned pos = sese_loop_depth (s->scop_info->region, get_chrec_loop (e)); + unsigned pos = sese_loop_depth (s->scop_info->region, get_chrec_loop (e)) - 1; isl_aff *loop = isl_aff_set_coefficient_si (isl_aff_zero_on_domain (ls), isl_dim_in, pos, 1); isl_pw_aff *l = isl_pw_aff_from_aff (loop); @@ -763,10 +763,10 @@ add_loop_constraints (scop_p scop, __isl_take isl_set *domain, loop_p loop, return domain; const sese_l ®ion = scop->scop_info->region; if (!loop_in_sese_p (loop, region)) - ; - else - /* Recursion all the way up to the context loop. */ - domain = add_loop_constraints (scop, domain, loop_outer (loop), context); + return domain; + + /* Recursion all the way up to the context loop. */ + domain = add_loop_constraints (scop, domain, loop_outer (loop), context); /* Then, build constraints over the loop in post-order: outer to inner. */ @@ -777,21 +777,6 @@ add_loop_constraints (scop_p scop, __isl_take isl_set *domain, loop_p loop, domain = add_iter_domain_dimension (domain, loop, scop); isl_space *space = isl_set_get_space (domain); - if (!loop_in_sese_p (loop, region)) - { - /* 0 == loop_i */ - isl_local_space *ls = isl_local_space_from_space (space); - isl_constraint *c = isl_equality_alloc (ls); - c = isl_constraint_set_coefficient_si (c, isl_dim_set, loop_index, 1); - if (dump_file) - { - fprintf (dump_file, "[sese-to-poly] adding constraint to the domain: "); - print_isl_constraint (dump_file, c); - } - domain = isl_set_add_constraint (domain, c); - return domain; - } - /* 0 <= loop_i */ isl_local_space *ls = isl_local_space_from_space (isl_space_copy (space)); isl_constraint *c = isl_inequality_alloc (ls); diff --git a/gcc/sese.c b/gcc/sese.c index d6702ada5f4..8aa8015290d 100644 --- a/gcc/sese.c +++ b/gcc/sese.c @@ -461,7 +461,6 @@ scalar_evolution_in_region (const sese_l ®ion, loop_p loop, tree t) { gimple *def; struct loop *def_loop; - basic_block before = region.entry->src; /* SCOP parameters. */ if (TREE_CODE (t) == SSA_NAME @@ -472,7 +471,7 @@ scalar_evolution_in_region (const sese_l ®ion, loop_p loop, tree t) || loop_in_sese_p (loop, region)) /* FIXME: we would need instantiate SCEV to work on a region, and be more flexible wrt. memory loads that may be invariant in the region. */ - return instantiate_scev (before, loop, + return instantiate_scev (region.entry, loop, analyze_scalar_evolution (loop, t)); def = SSA_NAME_DEF_STMT (t); @@ -494,7 +493,7 @@ scalar_evolution_in_region (const sese_l ®ion, loop_p loop, tree t) if (has_vdefs) return chrec_dont_know; - return instantiate_scev (before, loop, t); + return instantiate_scev (region.entry, loop, t); } /* Return true if BB is empty, contains only DEBUG_INSNs. */ diff --git a/gcc/sese.h b/gcc/sese.h index 190deeda8af..faefd806d9d 100644 --- a/gcc/sese.h +++ b/gcc/sese.h @@ -334,6 +334,8 @@ gbb_loop_at_index (gimple_poly_bb_p gbb, sese_l ®ion, int index) while (--depth > index) loop = loop_outer (loop); + gcc_assert (loop_in_sese_p (loop, region)); + return loop; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 874ede28bd3..a830453eabd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2017-10-13 Richard Biener + + PR tree-optimization/82451 + * gcc.dg/graphite/pr82451.c: New testcase. + * gfortran.dg/graphite/id-27.f90: Likewise. + * gfortran.dg/graphite/pr82451.f: Likewise. + 2017-10-13 Richard Biener PR tree-optimization/82525 diff --git a/gcc/testsuite/gcc.dg/graphite/fuse-1.c b/gcc/testsuite/gcc.dg/graphite/fuse-1.c index e3bf7bcf99b..204d3b20703 100644 --- a/gcc/testsuite/gcc.dg/graphite/fuse-1.c +++ b/gcc/testsuite/gcc.dg/graphite/fuse-1.c @@ -1,15 +1,15 @@ /* Check that the two loops are fused and that we manage to fold the two xor operations. */ -/* { dg-options "-O2 -floop-nest-optimize -fdump-tree-forwprop4-all -fdump-tree-graphite-all" } */ +/* { dg-options "-O2 -floop-nest-optimize -fdump-tree-forwprop-all -fdump-tree-graphite-all" } */ /* Make sure we fuse the loops like this: AST generated by isl: for (int c0 = 0; c0 <= 99; c0 += 1) { - S_3(0, c0); - S_6(0, c0); - S_9(0, c0); + S_3(c0); + S_6(c0); + S_9(c0); } */ -/* { dg-final { scan-tree-dump-times "AST generated by isl:.*for \\(int c0 = 0; c0 <= 99; c0 \\+= 1\\) \\{.*S_.*\\(0, c0\\);.*S_.*\\(0, c0\\);.*S_.*\\(0, c0\\);.*\\}" 1 "graphite" } } */ +/* { dg-final { scan-tree-dump-times "AST generated by isl:.*for \\(int c0 = 0; c0 <= 99; c0 \\+= 1\\) \\{.*S_.*\\(c0\\);.*S_.*\\(c0\\);.*S_.*\\(c0\\);.*\\}" 1 "graphite" } } */ /* Check that after fusing the loops, the scalar computation is also fused. */ /* { dg-final { scan-tree-dump-times "gimple_simplified to\[^\\n\]*\\^ 12" 1 "forwprop4" } } */ diff --git a/gcc/testsuite/gcc.dg/graphite/fuse-2.c b/gcc/testsuite/gcc.dg/graphite/fuse-2.c index dc0a9b2b61c..f4cea4360d9 100644 --- a/gcc/testsuite/gcc.dg/graphite/fuse-2.c +++ b/gcc/testsuite/gcc.dg/graphite/fuse-2.c @@ -3,13 +3,13 @@ /* Make sure we fuse the loops like this: AST generated by isl: for (int c0 = 0; c0 <= 99; c0 += 1) { - S_3(0, c0); - S_6(0, c0); - S_9(0, c0); + S_3(c0); + S_6(c0); + S_9(c0); } */ -/* { dg-final { scan-tree-dump-times "AST generated by isl:.*for \\(int c0 = 0; c0 <= 99; c0 \\+= 1\\) \\{.*S_.*\\(0, c0\\);.*S_.*\\(0, c0\\);.*S_.*\\(0, c0\\);.*\\}" 1 "graphite" } } */ +/* { dg-final { scan-tree-dump-times "AST generated by isl:.*for \\(int c0 = 0; c0 <= 99; c0 \\+= 1\\) \\{.*S_.*\\(c0\\);.*S_.*\\(c0\\);.*S_.*\\(c0\\);.*\\}" 1 "graphite" } } */ #define MAX 100 int A[MAX], B[MAX], C[MAX]; diff --git a/gcc/testsuite/gcc.dg/graphite/pr82451.c b/gcc/testsuite/gcc.dg/graphite/pr82451.c new file mode 100644 index 00000000000..802b931fddd --- /dev/null +++ b/gcc/testsuite/gcc.dg/graphite/pr82451.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O -floop-parallelize-all" } */ + +static int a[]; +int b[1]; +int c; +static void +d (int *f, int *g) +{ + int e; + for (e = 0; e < 2; e++) + g[e] = 1; + for (e = 0; e < 2; e++) + g[e] = f[e] + f[e + 1]; +} +void +h () +{ + for (;; c += 8) + d (&a[c], b); +} diff --git a/gcc/testsuite/gfortran.dg/graphite/id-27.f90 b/gcc/testsuite/gfortran.dg/graphite/id-27.f90 new file mode 100644 index 00000000000..e1e7ec0951f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/graphite/id-27.f90 @@ -0,0 +1,40 @@ +! { dg-additional-options "-Ofast" } +MODULE module_ra_gfdleta + INTEGER, PARAMETER :: NBLY=15 + REAL , SAVE :: EM1(28,180),EM1WDE(28,180),TABLE1(28,180), & + TABLE2(28,180),TABLE3(28,180),EM3(28,180), & + SOURCE(28,NBLY), DSRCE(28,NBLY) +CONTAINS + SUBROUTINE TABLE + INTEGER, PARAMETER :: NBLX=47 + INTEGER , PARAMETER:: NBLW = 163 + REAL :: & + SUM(28,180),PERTSM(28,180),SUM3(28,180), & + SUMWDE(28,180),SRCWD(28,NBLX),SRC1NB(28,NBLW), & + DBDTNB(28,NBLW) + REAL :: & + ZMASS(181),ZROOT(181),SC(28),DSC(28),XTEMV(28), & + TFOUR(28),FORTCU(28),X(28),X1(28),X2(180),SRCS(28), & + R1T(28),R2(28),S2(28),T3(28),R1WD(28) + REAL :: EXPO(180),FAC(180) + I = 0 + DO 417 J=121,180 + FAC(J)=ZMASS(J)*(ONE-(ONE+X2(J))*EXPO(J))/(X2(J)*X2(J)) +417 CONTINUE + DO 421 J=121,180 + SUM3(I,J)=SUM3(I,J)+DBDTNB(I,N)*FAC(J) +421 CONTINUE + IF (CENT.GT.160. .AND. CENT.LT.560.) THEN + DO 420 J=1,180 + DO 420 I=1,28 + SUMWDE(I,J)=SUMWDE(I,J)+SRC1NB(I,N)*EXPO(J) +420 CONTINUE + ENDIF + DO 433 J=121,180 + EM3(I,J)=SUM3(I,J)/FORTCU(I) +433 CONTINUE + DO 501 I=1,28 + EM1WDE(I,J)=SUMWDE(I,J)/TFOUR(I) +501 CONTINUE + END SUBROUTINE TABLE + END MODULE module_RA_GFDLETA diff --git a/gcc/testsuite/gfortran.dg/graphite/pr82451.f b/gcc/testsuite/gfortran.dg/graphite/pr82451.f new file mode 100644 index 00000000000..88ff85b1a99 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/graphite/pr82451.f @@ -0,0 +1,39 @@ +! { dg-do compile } +! { dg-options "-O2 -floop-nest-optimize" } + MODULE LES3D_DATA + PARAMETER ( NSCHEME = 4, ICHEM = 0, ISGSK = 0, IVISC = 1 ) + DOUBLE PRECISION DT, TIME, STATTIME, CFL, RELNO, TSTND, ALREF + INTEGER IDYN, IMAX, JMAX, KMAX + PARAMETER( RUNIV = 8.3145D3, + > TPRANDLT = 0.91D0) + DOUBLE PRECISION,ALLOCATABLE,DIMENSION(:,:,:) :: + > U, V, W, P, T, H, EK, + > UAV, VAV, WAV, PAV, TAV, HAV, EKAV + DOUBLE PRECISION,ALLOCATABLE,DIMENSION(:,:,:,:) :: + > CONC, HF, QAV, COAV, HFAV, DU + DOUBLE PRECISION,ALLOCATABLE,DIMENSION(:,:,:,:,:) :: + > Q + END MODULE LES3D_DATA + SUBROUTINE FLUXJ() + USE LES3D_DATA + ALLOCATABLE QS(:), FSJ(:,:,:) + ALLOCATABLE DWDX(:),DWDY(:),DWDZ(:) + ALLOCATABLE DHDY(:), DKDY(:) + PARAMETER ( R12I = 1.0D0 / 12.0D0, + > TWO3 = 2.0D0 / 3.0D0 ) + ALLOCATE( QS(IMAX-1), FSJ(IMAX-1,0:JMAX-1,ND)) + ALLOCATE( DWDX(IMAX-1),DWDY(IMAX-1),DWDZ(IMAX-1)) + I1 = 1 + DO K = K1,K2 + DO J = J1,J2 + DO I = I1, I2 + FSJ(I,J,5) = FSJ(I,J,5) + PAV(I,J,K) * QS(I) + END DO + DO I = I1, I2 + DWDX(I) = DXI * R12I * (WAV(I-2,J,K) - WAV(I+2,J,K) + + > 8.0D0 * (WAV(I+1,J,K) - WAV(I-1,J,K))) + END DO + END DO + END DO + DEALLOCATE( QS, FSJ, DHDY, DKDY) + END diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c index 19cceb8dfd9..559a8e4b845 100644 --- a/gcc/tree-data-ref.c +++ b/gcc/tree-data-ref.c @@ -957,15 +957,14 @@ access_fn_component_p (tree op) } /* Determines the base object and the list of indices of memory reference - DR, analyzed in LOOP and instantiated in loop nest NEST. */ + DR, analyzed in LOOP and instantiated before NEST. */ static void -dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop) +dr_analyze_indices (struct data_reference *dr, edge nest, loop_p loop) { vec access_fns = vNULL; tree ref, op; tree base, off, access_fn; - basic_block before_loop; /* If analyzing a basic-block there are no indices to analyze and thus no access functions. */ @@ -977,7 +976,6 @@ dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop) } ref = DR_REF (dr); - before_loop = block_before_loop (nest); /* REALPART_EXPR and IMAGPART_EXPR can be handled like accesses into a two element array with a constant index. The base is @@ -1002,7 +1000,7 @@ dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop) { op = TREE_OPERAND (ref, 1); access_fn = analyze_scalar_evolution (loop, op); - access_fn = instantiate_scev (before_loop, loop, access_fn); + access_fn = instantiate_scev (nest, loop, access_fn); access_fns.safe_push (access_fn); } else if (TREE_CODE (ref) == COMPONENT_REF @@ -1034,7 +1032,7 @@ dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop) { op = TREE_OPERAND (ref, 0); access_fn = analyze_scalar_evolution (loop, op); - access_fn = instantiate_scev (before_loop, loop, access_fn); + access_fn = instantiate_scev (nest, loop, access_fn); if (TREE_CODE (access_fn) == POLYNOMIAL_CHREC) { tree orig_type; @@ -1139,7 +1137,7 @@ free_data_ref (data_reference_p dr) in which the data reference should be analyzed. */ struct data_reference * -create_data_ref (loop_p nest, loop_p loop, tree memref, gimple *stmt, +create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt, bool is_read, bool is_conditional_in_stmt) { struct data_reference *dr; @@ -4970,7 +4968,8 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt, FOR_EACH_VEC_ELT (references, i, ref) { - dr = create_data_ref (nest, loop_containing_stmt (stmt), ref->ref, + dr = create_data_ref (nest ? loop_preheader_edge (nest) : NULL, + loop_containing_stmt (stmt), ref->ref, stmt, ref->is_read, ref->is_conditional_in_stmt); gcc_assert (dr != NULL); datarefs->safe_push (dr); @@ -4986,7 +4985,7 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt, should be analyzed. */ bool -graphite_find_data_references_in_stmt (loop_p nest, loop_p loop, gimple *stmt, +graphite_find_data_references_in_stmt (edge nest, loop_p loop, gimple *stmt, vec *datarefs) { unsigned i; diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h index a66d335f4a0..d9d297ad970 100644 --- a/gcc/tree-data-ref.h +++ b/gcc/tree-data-ref.h @@ -436,11 +436,11 @@ extern void free_data_ref (data_reference_p); extern void free_data_refs (vec ); extern bool find_data_references_in_stmt (struct loop *, gimple *, vec *); -extern bool graphite_find_data_references_in_stmt (loop_p, loop_p, gimple *, +extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *, vec *); tree find_data_references_in_loop (struct loop *, vec *); bool loop_nest_has_data_refs (loop_p loop); -struct data_reference *create_data_ref (loop_p, loop_p, tree, gimple *, bool, +struct data_reference *create_data_ref (edge, loop_p, tree, gimple *, bool, bool); extern bool find_loop_nest (struct loop *, vec *); extern struct data_dependence_relation *initialize_data_dependence_relation diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c index c693be9fe28..b6c1fcef6a1 100644 --- a/gcc/tree-scalar-evolution.c +++ b/gcc/tree-scalar-evolution.c @@ -2095,6 +2095,10 @@ analyze_scalar_evolution (struct loop *loop, tree var) { tree res; + /* ??? Fix callers. */ + if (! loop) + return var; + if (dump_file && (dump_flags & TDF_SCEV)) { fprintf (dump_file, "(analyze_scalar_evolution \n"); @@ -2271,7 +2275,7 @@ eq_idx_scev_info (const void *e1, const void *e2) static unsigned get_instantiated_value_entry (instantiate_cache_type &cache, - tree name, basic_block instantiate_below) + tree name, edge instantiate_below) { if (!cache.map) { @@ -2281,7 +2285,7 @@ get_instantiated_value_entry (instantiate_cache_type &cache, scev_info_str e; e.name_version = SSA_NAME_VERSION (name); - e.instantiated_below = instantiate_below->index; + e.instantiated_below = instantiate_below->dest->index; void **slot = htab_find_slot_with_hash (cache.map, &e, scev_info_hasher::hash (&e), INSERT); if (!*slot) @@ -2325,7 +2329,7 @@ loop_closed_phi_def (tree var) return NULL_TREE; } -static tree instantiate_scev_r (basic_block, struct loop *, struct loop *, +static tree instantiate_scev_r (edge, struct loop *, struct loop *, tree, bool *, int); /* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW @@ -2344,7 +2348,7 @@ static tree instantiate_scev_r (basic_block, struct loop *, struct loop *, instantiated, and to stop if it exceeds some limit. */ static tree -instantiate_scev_name (basic_block instantiate_below, +instantiate_scev_name (edge instantiate_below, struct loop *evolution_loop, struct loop *inner_loop, tree chrec, bool *fold_conversions, @@ -2358,7 +2362,7 @@ instantiate_scev_name (basic_block instantiate_below, evolutions in outer loops), nothing to do. */ if (!def_bb || loop_depth (def_bb->loop_father) == 0 - || dominated_by_p (CDI_DOMINATORS, instantiate_below, def_bb)) + || ! dominated_by_p (CDI_DOMINATORS, def_bb, instantiate_below->dest)) return chrec; /* We cache the value of instantiated variable to avoid exponential @@ -2380,6 +2384,51 @@ instantiate_scev_name (basic_block instantiate_below, def_loop = find_common_loop (evolution_loop, def_bb->loop_father); + if (! dominated_by_p (CDI_DOMINATORS, + def_loop->header, instantiate_below->dest)) + { + gimple *def = SSA_NAME_DEF_STMT (chrec); + if (gassign *ass = dyn_cast (def)) + { + switch (gimple_assign_rhs_class (ass)) + { + case GIMPLE_UNARY_RHS: + { + tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, + inner_loop, gimple_assign_rhs1 (ass), + fold_conversions, size_expr); + if (op0 == chrec_dont_know) + return chrec_dont_know; + res = fold_build1 (gimple_assign_rhs_code (ass), + TREE_TYPE (chrec), op0); + break; + } + case GIMPLE_BINARY_RHS: + { + tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, + inner_loop, gimple_assign_rhs1 (ass), + fold_conversions, size_expr); + if (op0 == chrec_dont_know) + return chrec_dont_know; + tree op1 = instantiate_scev_r (instantiate_below, evolution_loop, + inner_loop, gimple_assign_rhs2 (ass), + fold_conversions, size_expr); + if (op1 == chrec_dont_know) + return chrec_dont_know; + res = fold_build2 (gimple_assign_rhs_code (ass), + TREE_TYPE (chrec), op0, op1); + break; + } + default: + res = chrec_dont_know; + } + } + else + res = chrec_dont_know; + global_cache->set (si, res); + return res; + } + /* If the analysis yields a parametric chrec, instantiate the result again. */ res = analyze_scalar_evolution (def_loop, chrec); @@ -2411,8 +2460,9 @@ instantiate_scev_name (basic_block instantiate_below, inner_loop, res, fold_conversions, size_expr); } - else if (!dominated_by_p (CDI_DOMINATORS, instantiate_below, - gimple_bb (SSA_NAME_DEF_STMT (res)))) + else if (dominated_by_p (CDI_DOMINATORS, + gimple_bb (SSA_NAME_DEF_STMT (res)), + instantiate_below->dest)) res = chrec_dont_know; } @@ -2450,7 +2500,7 @@ instantiate_scev_name (basic_block instantiate_below, instantiated, and to stop if it exceeds some limit. */ static tree -instantiate_scev_poly (basic_block instantiate_below, +instantiate_scev_poly (edge instantiate_below, struct loop *evolution_loop, struct loop *, tree chrec, bool *fold_conversions, int size_expr) { @@ -2495,7 +2545,7 @@ instantiate_scev_poly (basic_block instantiate_below, instantiated, and to stop if it exceeds some limit. */ static tree -instantiate_scev_binary (basic_block instantiate_below, +instantiate_scev_binary (edge instantiate_below, struct loop *evolution_loop, struct loop *inner_loop, tree chrec, enum tree_code code, tree type, tree c0, tree c1, @@ -2538,43 +2588,6 @@ instantiate_scev_binary (basic_block instantiate_below, return chrec ? chrec : fold_build2 (code, type, c0, c1); } -/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW - and EVOLUTION_LOOP, that were left under a symbolic form. - - "CHREC" is an array reference to be instantiated. - - CACHE is the cache of already instantiated values. - - Variable pointed by FOLD_CONVERSIONS is set to TRUE when the - conversions that may wrap in signed/pointer type are folded, as long - as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL - then we don't do such fold. - - SIZE_EXPR is used for computing the size of the expression to be - instantiated, and to stop if it exceeds some limit. */ - -static tree -instantiate_array_ref (basic_block instantiate_below, - struct loop *evolution_loop, struct loop *inner_loop, - tree chrec, bool *fold_conversions, int size_expr) -{ - tree res; - tree index = TREE_OPERAND (chrec, 1); - tree op1 = instantiate_scev_r (instantiate_below, evolution_loop, - inner_loop, index, - fold_conversions, size_expr); - - if (op1 == chrec_dont_know) - return chrec_dont_know; - - if (chrec && op1 == index) - return chrec; - - res = unshare_expr (chrec); - TREE_OPERAND (res, 1) = op1; - return res; -} - /* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW and EVOLUTION_LOOP, that were left under a symbolic form. @@ -2592,7 +2605,7 @@ instantiate_array_ref (basic_block instantiate_below, instantiated, and to stop if it exceeds some limit. */ static tree -instantiate_scev_convert (basic_block instantiate_below, +instantiate_scev_convert (edge instantiate_below, struct loop *evolution_loop, struct loop *inner_loop, tree chrec, tree type, tree op, bool *fold_conversions, int size_expr) @@ -2643,7 +2656,7 @@ instantiate_scev_convert (basic_block instantiate_below, instantiated, and to stop if it exceeds some limit. */ static tree -instantiate_scev_not (basic_block instantiate_below, +instantiate_scev_not (edge instantiate_below, struct loop *evolution_loop, struct loop *inner_loop, tree chrec, enum tree_code code, tree type, tree op, @@ -2678,130 +2691,6 @@ instantiate_scev_not (basic_block instantiate_below, return chrec ? chrec : fold_build1 (code, type, op0); } -/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW - and EVOLUTION_LOOP, that were left under a symbolic form. - - CHREC is an expression with 3 operands to be instantiated. - - CACHE is the cache of already instantiated values. - - Variable pointed by FOLD_CONVERSIONS is set to TRUE when the - conversions that may wrap in signed/pointer type are folded, as long - as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL - then we don't do such fold. - - SIZE_EXPR is used for computing the size of the expression to be - instantiated, and to stop if it exceeds some limit. */ - -static tree -instantiate_scev_3 (basic_block instantiate_below, - struct loop *evolution_loop, struct loop *inner_loop, - tree chrec, - bool *fold_conversions, int size_expr) -{ - tree op1, op2; - tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, - inner_loop, TREE_OPERAND (chrec, 0), - fold_conversions, size_expr); - if (op0 == chrec_dont_know) - return chrec_dont_know; - - op1 = instantiate_scev_r (instantiate_below, evolution_loop, - inner_loop, TREE_OPERAND (chrec, 1), - fold_conversions, size_expr); - if (op1 == chrec_dont_know) - return chrec_dont_know; - - op2 = instantiate_scev_r (instantiate_below, evolution_loop, - inner_loop, TREE_OPERAND (chrec, 2), - fold_conversions, size_expr); - if (op2 == chrec_dont_know) - return chrec_dont_know; - - if (op0 == TREE_OPERAND (chrec, 0) - && op1 == TREE_OPERAND (chrec, 1) - && op2 == TREE_OPERAND (chrec, 2)) - return chrec; - - return fold_build3 (TREE_CODE (chrec), - TREE_TYPE (chrec), op0, op1, op2); -} - -/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW - and EVOLUTION_LOOP, that were left under a symbolic form. - - CHREC is an expression with 2 operands to be instantiated. - - CACHE is the cache of already instantiated values. - - Variable pointed by FOLD_CONVERSIONS is set to TRUE when the - conversions that may wrap in signed/pointer type are folded, as long - as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL - then we don't do such fold. - - SIZE_EXPR is used for computing the size of the expression to be - instantiated, and to stop if it exceeds some limit. */ - -static tree -instantiate_scev_2 (basic_block instantiate_below, - struct loop *evolution_loop, struct loop *inner_loop, - tree chrec, - bool *fold_conversions, int size_expr) -{ - tree op1; - tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, - inner_loop, TREE_OPERAND (chrec, 0), - fold_conversions, size_expr); - if (op0 == chrec_dont_know) - return chrec_dont_know; - - op1 = instantiate_scev_r (instantiate_below, evolution_loop, - inner_loop, TREE_OPERAND (chrec, 1), - fold_conversions, size_expr); - if (op1 == chrec_dont_know) - return chrec_dont_know; - - if (op0 == TREE_OPERAND (chrec, 0) - && op1 == TREE_OPERAND (chrec, 1)) - return chrec; - - return fold_build2 (TREE_CODE (chrec), TREE_TYPE (chrec), op0, op1); -} - -/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW - and EVOLUTION_LOOP, that were left under a symbolic form. - - CHREC is an expression with 2 operands to be instantiated. - - CACHE is the cache of already instantiated values. - - Variable pointed by FOLD_CONVERSIONS is set to TRUE when the - conversions that may wrap in signed/pointer type are folded, as long - as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL - then we don't do such fold. - - SIZE_EXPR is used for computing the size of the expression to be - instantiated, and to stop if it exceeds some limit. */ - -static tree -instantiate_scev_1 (basic_block instantiate_below, - struct loop *evolution_loop, struct loop *inner_loop, - tree chrec, - bool *fold_conversions, int size_expr) -{ - tree op0 = instantiate_scev_r (instantiate_below, evolution_loop, - inner_loop, TREE_OPERAND (chrec, 0), - fold_conversions, size_expr); - - if (op0 == chrec_dont_know) - return chrec_dont_know; - - if (op0 == TREE_OPERAND (chrec, 0)) - return chrec; - - return fold_build1 (TREE_CODE (chrec), TREE_TYPE (chrec), op0); -} - /* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW and EVOLUTION_LOOP, that were left under a symbolic form. @@ -2818,7 +2707,7 @@ instantiate_scev_1 (basic_block instantiate_below, instantiated, and to stop if it exceeds some limit. */ static tree -instantiate_scev_r (basic_block instantiate_below, +instantiate_scev_r (edge instantiate_below, struct loop *evolution_loop, struct loop *inner_loop, tree chrec, bool *fold_conversions, int size_expr) @@ -2870,50 +2759,20 @@ instantiate_scev_r (basic_block instantiate_below, fold_conversions, size_expr); case ADDR_EXPR: + if (is_gimple_min_invariant (chrec)) + return chrec; + /* Fallthru. */ case SCEV_NOT_KNOWN: return chrec_dont_know; case SCEV_KNOWN: return chrec_known; - case ARRAY_REF: - return instantiate_array_ref (instantiate_below, evolution_loop, - inner_loop, chrec, - fold_conversions, size_expr); - default: - break; - } - - if (VL_EXP_CLASS_P (chrec)) - return chrec_dont_know; - - switch (TREE_CODE_LENGTH (TREE_CODE (chrec))) - { - case 3: - return instantiate_scev_3 (instantiate_below, evolution_loop, - inner_loop, chrec, - fold_conversions, size_expr); - - case 2: - return instantiate_scev_2 (instantiate_below, evolution_loop, - inner_loop, chrec, - fold_conversions, size_expr); - - case 1: - return instantiate_scev_1 (instantiate_below, evolution_loop, - inner_loop, chrec, - fold_conversions, size_expr); - - case 0: - return chrec; - - default: - break; + if (CONSTANT_CLASS_P (chrec)) + return chrec; + return chrec_dont_know; } - - /* Too complicated to handle. */ - return chrec_dont_know; } /* Analyze all the parameters of the chrec that were left under a @@ -2923,7 +2782,7 @@ instantiate_scev_r (basic_block instantiate_below, a function parameter. */ tree -instantiate_scev (basic_block instantiate_below, struct loop *evolution_loop, +instantiate_scev (edge instantiate_below, struct loop *evolution_loop, tree chrec) { tree res; @@ -2931,8 +2790,10 @@ instantiate_scev (basic_block instantiate_below, struct loop *evolution_loop, if (dump_file && (dump_flags & TDF_SCEV)) { fprintf (dump_file, "(instantiate_scev \n"); - fprintf (dump_file, " (instantiate_below = %d)\n", instantiate_below->index); - fprintf (dump_file, " (evolution_loop = %d)\n", evolution_loop->num); + fprintf (dump_file, " (instantiate_below = %d -> %d)\n", + instantiate_below->src->index, instantiate_below->dest->index); + if (evolution_loop) + fprintf (dump_file, " (evolution_loop = %d)\n", evolution_loop->num); fprintf (dump_file, " (chrec = "); print_generic_expr (dump_file, chrec); fprintf (dump_file, ")\n"); @@ -2980,7 +2841,7 @@ resolve_mixers (struct loop *loop, tree chrec, bool *folded_casts) destr = true; } - tree ret = instantiate_scev_r (block_before_loop (loop), loop, NULL, + tree ret = instantiate_scev_r (loop_preheader_edge (loop), loop, NULL, chrec, &fold_conversions, 0); if (folded_casts && !*folded_casts) diff --git a/gcc/tree-scalar-evolution.h b/gcc/tree-scalar-evolution.h index c3980d0fbb2..55b8ca49fae 100644 --- a/gcc/tree-scalar-evolution.h +++ b/gcc/tree-scalar-evolution.h @@ -30,7 +30,7 @@ extern void scev_reset (void); extern void scev_reset_htab (void); extern void scev_finalize (void); extern tree analyze_scalar_evolution (struct loop *, tree); -extern tree instantiate_scev (basic_block, struct loop *, tree); +extern tree instantiate_scev (edge, struct loop *, tree); extern tree resolve_mixers (struct loop *, tree, bool *); extern void gather_stats_on_scev_database (void); extern void final_value_replacement_loop (struct loop *); @@ -60,7 +60,7 @@ block_before_loop (loop_p loop) static inline tree instantiate_parameters (struct loop *loop, tree chrec) { - return instantiate_scev (block_before_loop (loop), loop, chrec); + return instantiate_scev (loop_preheader_edge (loop), loop, chrec); } /* Returns the loop of the polynomial chrec CHREC. */ diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c index ecf14d108fe..67767e1516a 100644 --- a/gcc/tree-ssa-loop-prefetch.c +++ b/gcc/tree-ssa-loop-prefetch.c @@ -1632,7 +1632,8 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs, for (gr = refs; gr; gr = gr->next) for (ref = gr->refs; ref; ref = ref->next) { - dr = create_data_ref (nest, loop_containing_stmt (ref->stmt), + dr = create_data_ref (loop_preheader_edge (nest), + loop_containing_stmt (ref->stmt), ref->mem, ref->stmt, !ref->write_p, false); if (dr)