diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 655f85fa10b..6d245742d97 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2012-10-09 Venkataramanan Kumar + + PR middle-end/53397 + * tree-ssa-loop-prefetch.c (gather_memory_references_ref): + Perform non constant step prefetching in inner loop, only + when it is invariant in the entire loop nest. + * tree-ssa-loop-prefetch.c (dump_mem_details): New function to dump + base, step and delta values of memeory reference analysed for + prefetching. + * tree-ssa-loop-prefetch.c (dump_mem_ref): Call dump_mem_details + to print base, step and delta values of memory reference. + * cfgloop.h (loop_outermost): New function that returns outermost + loop for a given loop in a loop nest. + * testsuite/gcc.dg/pr53397-1.c: New test case + Checks we are prefecthing for loop invariant steps + * testsuite/gcc.dg/pr53397-2.c: New test case + Checks we are not prefecthing for loop variant steps + 2012-10-09 Richard Guenther PR middle-end/54837 diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index 9d7b784174d..80af7d8dbc4 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -712,4 +712,18 @@ extern void move_loop_invariants (void); extern bool finite_loop_p (struct loop *); extern void scale_loop_profile (struct loop *loop, int scale, int iteration_bound); +/* Returns the outermost loop of the loop nest that contains LOOP.*/ +static inline struct loop * +loop_outermost (struct loop *loop) +{ + + unsigned n = VEC_length (loop_p, loop->superloops); + + if (n <= 1) + return loop; + + return VEC_index (loop_p, loop->superloops, 1); +} + + #endif /* GCC_CFGLOOP_H */ diff --git a/gcc/testsuite/gcc.dg/pr53397-1.c b/gcc/testsuite/gcc.dg/pr53397-1.c new file mode 100644 index 00000000000..abb83c6c584 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr53397-1.c @@ -0,0 +1,28 @@ +/* Prefetching when the step is loop invariant. */ +/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-require-effective-target sse2 } */ +/* { dg-options "-O3 -fprefetch-loop-arrays -fdump-tree-aprefetch-details --param min-insn-to-prefetch-ratio=3 --param simultaneous-prefetches=10 -fdump-tree-aprefetch-details" } */ + + +double data[16384]; +void prefetch_when_non_constant_step_is_invariant(int step, int n) +{ + int a; + int b; + for (a = 1; a < step; a++) { + for (b = 0; b < n; b += 2 * step) { + + int i = 2*(b + a); + int j = 2*(b + a + step); + + + data[j] = data[i]; + data[j+1] = data[i+1]; + } + } +} + +/* { dg-final { scan-tree-dump "Issued prefetch" "aprefetch" } } */ +/* { dg-final { scan-assembler "prefetcht0" } } */ + +/* { dg-final { cleanup-tree-dump "aprefetch" } } */ diff --git a/gcc/testsuite/gcc.dg/pr53397-2.c b/gcc/testsuite/gcc.dg/pr53397-2.c new file mode 100644 index 00000000000..4793ae0a6e6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr53397-2.c @@ -0,0 +1,28 @@ +/* Not prefetching when the step is loop variant. */ +/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-require-effective-target sse2 } */ +/* { dg-options "-O3 -fprefetch-loop-arrays -fdump-tree-aprefetch-details --param min-insn-to-prefetch-ratio=3 --param simultaneous-prefetches=10 -fdump-tree-aprefetch-details" } */ + +double data[16384]; +void donot_prefetch_when_non_constant_step_is_variant(int step, int n) +{ + int a; + int b; + for (a = 1; a < step; a++,step*=2) { + for (b = 0; b < n; b += 2 * step) { + + int i = 2*(b + a); + int j = 2*(b + a + step); + + + data[j] = data[i]; + data[j+1] = data[i+1]; + } + } +} + +/* { dg-final { scan-tree-dump "Not prefetching" "aprefetch" } } */ +/* { dg-final { scan-tree-dump "loop variant step" "aprefetch" } } */ + +/* { dg-final { cleanup-tree-dump "aprefetch" } } */ + diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c index fe4df9a06f7..dcc65e19abb 100644 --- a/gcc/tree-ssa-loop-prefetch.c +++ b/gcc/tree-ssa-loop-prefetch.c @@ -278,6 +278,26 @@ struct mem_ref nontemporal one. */ }; +/* Dumps information about memory reference */ +static void +dump_mem_details (FILE *file, tree base, tree step, + HOST_WIDE_INT delta, bool write_p) +{ + fprintf (file, "(base "); + print_generic_expr (file, base, TDF_SLIM); + fprintf (file, ", step "); + if (cst_and_fits_in_hwi (step)) + fprintf (file, HOST_WIDE_INT_PRINT_DEC, int_cst_value (step)); + else + print_generic_expr (file, step, TDF_TREE); + fprintf (file, ")\n"); + fprintf (file, " delta "); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, delta); + fprintf (file, "\n"); + fprintf (file, " %s\n", write_p ? "write" : "read"); + fprintf (file, "\n"); +} + /* Dumps information about reference REF to FILE. */ static void @@ -285,22 +305,10 @@ dump_mem_ref (FILE *file, struct mem_ref *ref) { fprintf (file, "Reference %p:\n", (void *) ref); - fprintf (file, " group %p (base ", (void *) ref->group); - print_generic_expr (file, ref->group->base, TDF_SLIM); - fprintf (file, ", step "); - if (cst_and_fits_in_hwi (ref->group->step)) - fprintf (file, HOST_WIDE_INT_PRINT_DEC, int_cst_value (ref->group->step)); - else - print_generic_expr (file, ref->group->step, TDF_TREE); - fprintf (file, ")\n"); + fprintf (file, " group %p ", (void *) ref->group); - fprintf (file, " delta "); - fprintf (file, HOST_WIDE_INT_PRINT_DEC, ref->delta); - fprintf (file, "\n"); - - fprintf (file, " %s\n", ref->write_p ? "write" : "read"); - - fprintf (file, "\n"); + dump_mem_details (file, ref->group->base, ref->group->step, ref->delta, + ref->write_p); } /* Finds a group with BASE and STEP in GROUPS, or creates one if it does not @@ -537,9 +545,44 @@ gather_memory_references_ref (struct loop *loop, struct mem_ref_group **refs, if (may_be_nonaddressable_p (base)) return false; - /* Limit non-constant step prefetching only to the innermost loops. */ - if (!cst_and_fits_in_hwi (step) && loop->inner != NULL) - return false; + /* Limit non-constant step prefetching only to the innermost loops and + only when the step is loop invariant in the entire loop nest. */ + if (!cst_and_fits_in_hwi (step)) + { + if (loop->inner != NULL) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Memory expression %p\n",(void *) ref ); + print_generic_expr (dump_file, ref, TDF_TREE); + fprintf (dump_file,":"); + dump_mem_details( dump_file, base, step, delta, write_p); + fprintf (dump_file, + "Ignoring %p, non-constant step prefetching is " + "limited to inner most loops \n", + (void *) ref); + } + return false; + } + else + { + if (!expr_invariant_in_loop_p (loop_outermost (loop), step)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Memory expression %p\n",(void *) ref ); + print_generic_expr (dump_file, ref, TDF_TREE); + fprintf (dump_file,":"); + dump_mem_details(dump_file, base, step, delta, write_p); + fprintf (dump_file, + "Not prefetching, ignoring %p due to " + "loop variant step\n", + (void *) ref); + } + return false; + } + } + } /* Now we know that REF = &BASE + STEP * iter + DELTA, where DELTA and STEP are integer constants. */