00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "system.h"
00023 #include "coretypes.h"
00024 #include "tm.h"
00025 #include "tree.h"
00026 #include "rtl.h"
00027 #include "tm_p.h"
00028 #include "hard-reg-set.h"
00029 #include "basic-block.h"
00030 #include "output.h"
00031 #include "diagnostic.h"
00032 #include "tree-flow.h"
00033 #include "tree-dump.h"
00034 #include "timevar.h"
00035 #include "cfgloop.h"
00036 #include "varray.h"
00037 #include "expr.h"
00038 #include "tree-pass.h"
00039 #include "ggc.h"
00040 #include "insn-config.h"
00041 #include "recog.h"
00042 #include "hashtab.h"
00043 #include "tree-chrec.h"
00044 #include "tree-scalar-evolution.h"
00045 #include "toplev.h"
00046 #include "params.h"
00047 #include "langhooks.h"
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 #ifndef PREFETCH_LATENCY
00122 #define PREFETCH_LATENCY 200
00123 #endif
00124
00125
00126
00127 #ifndef SIMULTANEOUS_PREFETCHES
00128 #define SIMULTANEOUS_PREFETCHES 3
00129 #endif
00130
00131
00132
00133 #ifndef WRITE_CAN_USE_READ_PREFETCH
00134 #define WRITE_CAN_USE_READ_PREFETCH 1
00135 #endif
00136
00137
00138
00139 #ifndef READ_CAN_USE_WRITE_PREFETCH
00140 #define READ_CAN_USE_WRITE_PREFETCH 0
00141 #endif
00142
00143
00144
00145 #ifndef PREFETCH_BLOCK
00146 #define PREFETCH_BLOCK 32
00147 #endif
00148
00149
00150
00151 #ifndef HAVE_FORWARD_PREFETCH
00152 #define HAVE_FORWARD_PREFETCH 0
00153 #endif
00154
00155
00156
00157 #ifndef HAVE_BACKWARD_PREFETCH
00158 #define HAVE_BACKWARD_PREFETCH 0
00159 #endif
00160
00161
00162
00163
00164
00165
00166 #ifndef ACCEPTABLE_MISS_RATE
00167 #define ACCEPTABLE_MISS_RATE 50
00168 #endif
00169
00170 #ifndef HAVE_prefetch
00171 #define HAVE_prefetch 0
00172 #endif
00173
00174
00175
00176 struct mem_ref_group
00177 {
00178 tree base;
00179 HOST_WIDE_INT step;
00180 struct mem_ref *refs;
00181 struct mem_ref_group *next;
00182 };
00183
00184
00185
00186 #define PREFETCH_ALL (~(unsigned HOST_WIDE_INT) 0)
00187
00188
00189
00190 struct mem_ref
00191 {
00192 tree stmt;
00193 tree mem;
00194 HOST_WIDE_INT delta;
00195 bool write_p;
00196 struct mem_ref_group *group;
00197 unsigned HOST_WIDE_INT prefetch_mod;
00198
00199
00200 unsigned HOST_WIDE_INT prefetch_before;
00201
00202
00203 bool issue_prefetch_p;
00204 struct mem_ref *next;
00205 };
00206
00207
00208
00209 static void
00210 dump_mem_ref (FILE *file, struct mem_ref *ref)
00211 {
00212 fprintf (file, "Reference %p:\n", (void *) ref);
00213
00214 fprintf (file, " group %p (base ", (void *) ref->group);
00215 print_generic_expr (file, ref->group->base, TDF_SLIM);
00216 fprintf (file, ", step ");
00217 fprintf (file, HOST_WIDE_INT_PRINT_DEC, ref->group->step);
00218 fprintf (file, ")\n");
00219
00220 fprintf (dump_file, " delta ");
00221 fprintf (file, HOST_WIDE_INT_PRINT_DEC, ref->delta);
00222 fprintf (file, "\n");
00223
00224 fprintf (file, " %s\n", ref->write_p ? "write" : "read");
00225
00226 fprintf (file, "\n");
00227 }
00228
00229
00230
00231
00232 static struct mem_ref_group *
00233 find_or_create_group (struct mem_ref_group **groups, tree base,
00234 HOST_WIDE_INT step)
00235 {
00236 struct mem_ref_group *group;
00237
00238 for (; *groups; groups = &(*groups)->next)
00239 {
00240 if ((*groups)->step == step
00241 && operand_equal_p ((*groups)->base, base, 0))
00242 return *groups;
00243
00244
00245 if ((*groups)->step < step)
00246 break;
00247 }
00248
00249 group = xcalloc (1, sizeof (struct mem_ref_group));
00250 group->base = base;
00251 group->step = step;
00252 group->refs = NULL;
00253 group->next = *groups;
00254 *groups = group;
00255
00256 return group;
00257 }
00258
00259
00260
00261
00262 static void
00263 record_ref (struct mem_ref_group *group, tree stmt, tree mem,
00264 HOST_WIDE_INT delta, bool write_p)
00265 {
00266 struct mem_ref **aref;
00267
00268
00269 for (aref = &group->refs; *aref; aref = &(*aref)->next)
00270 {
00271
00272
00273 if (!WRITE_CAN_USE_READ_PREFETCH
00274 && write_p
00275 && !(*aref)->write_p)
00276 continue;
00277 if (!READ_CAN_USE_WRITE_PREFETCH
00278 && !write_p
00279 && (*aref)->write_p)
00280 continue;
00281
00282 if ((*aref)->delta == delta)
00283 return;
00284 }
00285
00286 (*aref) = xcalloc (1, sizeof (struct mem_ref));
00287 (*aref)->stmt = stmt;
00288 (*aref)->mem = mem;
00289 (*aref)->delta = delta;
00290 (*aref)->write_p = write_p;
00291 (*aref)->prefetch_before = PREFETCH_ALL;
00292 (*aref)->prefetch_mod = 1;
00293 (*aref)->issue_prefetch_p = false;
00294 (*aref)->group = group;
00295 (*aref)->next = NULL;
00296
00297 if (dump_file && (dump_flags & TDF_DETAILS))
00298 dump_mem_ref (dump_file, *aref);
00299 }
00300
00301
00302
00303 static void
00304 release_mem_refs (struct mem_ref_group *groups)
00305 {
00306 struct mem_ref_group *next_g;
00307 struct mem_ref *ref, *next_r;
00308
00309 for (; groups; groups = next_g)
00310 {
00311 next_g = groups->next;
00312 for (ref = groups->refs; ref; ref = next_r)
00313 {
00314 next_r = ref->next;
00315 free (ref);
00316 }
00317 free (groups);
00318 }
00319 }
00320
00321
00322
00323 struct ar_data
00324 {
00325 struct loop *loop;
00326 tree stmt;
00327 HOST_WIDE_INT *step;
00328 HOST_WIDE_INT *delta;
00329 };
00330
00331
00332
00333
00334 static bool
00335 idx_analyze_ref (tree base, tree *index, void *data)
00336 {
00337 struct ar_data *ar_data = data;
00338 tree ibase, step, stepsize;
00339 HOST_WIDE_INT istep, idelta = 0, imult = 1;
00340 affine_iv iv;
00341
00342 if (TREE_CODE (base) == MISALIGNED_INDIRECT_REF
00343 || TREE_CODE (base) == ALIGN_INDIRECT_REF)
00344 return false;
00345
00346 if (!simple_iv (ar_data->loop, ar_data->stmt, *index, &iv, false))
00347 return false;
00348 ibase = iv.base;
00349 step = iv.step;
00350
00351 if (zero_p (step))
00352 istep = 0;
00353 else
00354 {
00355 if (!cst_and_fits_in_hwi (step))
00356 return false;
00357 istep = int_cst_value (step);
00358 }
00359
00360 if (TREE_CODE (ibase) == PLUS_EXPR
00361 && cst_and_fits_in_hwi (TREE_OPERAND (ibase, 1)))
00362 {
00363 idelta = int_cst_value (TREE_OPERAND (ibase, 1));
00364 ibase = TREE_OPERAND (ibase, 0);
00365 }
00366 if (cst_and_fits_in_hwi (ibase))
00367 {
00368 idelta += int_cst_value (ibase);
00369 ibase = build_int_cst (TREE_TYPE (ibase), 0);
00370 }
00371
00372 if (TREE_CODE (base) == ARRAY_REF)
00373 {
00374 stepsize = array_ref_element_size (base);
00375 if (!cst_and_fits_in_hwi (stepsize))
00376 return false;
00377 imult = int_cst_value (stepsize);
00378
00379 istep *= imult;
00380 idelta *= imult;
00381 }
00382
00383 *ar_data->step += istep;
00384 *ar_data->delta += idelta;
00385 *index = ibase;
00386
00387 return true;
00388 }
00389
00390
00391
00392
00393
00394
00395 static bool
00396 analyze_ref (struct loop *loop, tree *ref_p, tree *base,
00397 HOST_WIDE_INT *step, HOST_WIDE_INT *delta,
00398 tree stmt)
00399 {
00400 struct ar_data ar_data;
00401 tree off;
00402 HOST_WIDE_INT bit_offset;
00403 tree ref = *ref_p;
00404
00405 *step = 0;
00406 *delta = 0;
00407
00408
00409 if (TREE_CODE (ref) == COMPONENT_REF
00410 && DECL_NONADDRESSABLE_P (TREE_OPERAND (ref, 1)))
00411 ref = TREE_OPERAND (ref, 0);
00412
00413 *ref_p = ref;
00414
00415 for (; TREE_CODE (ref) == COMPONENT_REF; ref = TREE_OPERAND (ref, 0))
00416 {
00417 off = DECL_FIELD_BIT_OFFSET (TREE_OPERAND (ref, 1));
00418 bit_offset = TREE_INT_CST_LOW (off);
00419 gcc_assert (bit_offset % BITS_PER_UNIT == 0);
00420
00421 *delta += bit_offset / BITS_PER_UNIT;
00422 }
00423
00424 *base = unshare_expr (ref);
00425 ar_data.loop = loop;
00426 ar_data.stmt = stmt;
00427 ar_data.step = step;
00428 ar_data.delta = delta;
00429 return for_each_index (base, idx_analyze_ref, &ar_data);
00430 }
00431
00432
00433
00434
00435 static void
00436 gather_memory_references_ref (struct loop *loop, struct mem_ref_group **refs,
00437 tree ref, bool write_p, tree stmt)
00438 {
00439 tree base;
00440 HOST_WIDE_INT step, delta;
00441 struct mem_ref_group *agrp;
00442
00443 if (!analyze_ref (loop, &ref, &base, &step, &delta, stmt))
00444 return;
00445
00446
00447
00448 agrp = find_or_create_group (refs, base, step);
00449 record_ref (agrp, stmt, ref, delta, write_p);
00450 }
00451
00452
00453
00454 static struct mem_ref_group *
00455 gather_memory_references (struct loop *loop)
00456 {
00457 basic_block *body = get_loop_body_in_dom_order (loop);
00458 basic_block bb;
00459 unsigned i;
00460 block_stmt_iterator bsi;
00461 tree stmt, lhs, rhs;
00462 struct mem_ref_group *refs = NULL;
00463
00464
00465
00466 for (i = 0; i < loop->num_nodes; i++)
00467 {
00468 bb = body[i];
00469 if (bb->loop_father != loop)
00470 continue;
00471
00472 for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
00473 {
00474 stmt = bsi_stmt (bsi);
00475 if (TREE_CODE (stmt) != MODIFY_EXPR)
00476 continue;
00477
00478 lhs = TREE_OPERAND (stmt, 0);
00479 rhs = TREE_OPERAND (stmt, 1);
00480
00481 if (REFERENCE_CLASS_P (rhs))
00482 gather_memory_references_ref (loop, &refs, rhs, false, stmt);
00483 if (REFERENCE_CLASS_P (lhs))
00484 gather_memory_references_ref (loop, &refs, lhs, true, stmt);
00485 }
00486 }
00487 free (body);
00488
00489 return refs;
00490 }
00491
00492
00493
00494 static void
00495 prune_ref_by_self_reuse (struct mem_ref *ref)
00496 {
00497 HOST_WIDE_INT step = ref->group->step;
00498 bool backward = step < 0;
00499
00500 if (step == 0)
00501 {
00502
00503 ref->prefetch_before = 1;
00504 return;
00505 }
00506
00507 if (backward)
00508 step = -step;
00509
00510 if (step > PREFETCH_BLOCK)
00511 return;
00512
00513 if ((backward && HAVE_BACKWARD_PREFETCH)
00514 || (!backward && HAVE_FORWARD_PREFETCH))
00515 {
00516 ref->prefetch_before = 1;
00517 return;
00518 }
00519
00520 ref->prefetch_mod = PREFETCH_BLOCK / step;
00521 }
00522
00523
00524
00525 static HOST_WIDE_INT
00526 ddown (HOST_WIDE_INT x, unsigned HOST_WIDE_INT by)
00527 {
00528 gcc_assert (by > 0);
00529
00530 if (x >= 0)
00531 return x / by;
00532 else
00533 return (x + by - 1) / by;
00534 }
00535
00536
00537
00538
00539 static void
00540 prune_ref_by_group_reuse (struct mem_ref *ref, struct mem_ref *by,
00541 bool by_is_before)
00542 {
00543 HOST_WIDE_INT step = ref->group->step;
00544 bool backward = step < 0;
00545 HOST_WIDE_INT delta_r = ref->delta, delta_b = by->delta;
00546 HOST_WIDE_INT delta = delta_b - delta_r;
00547 HOST_WIDE_INT hit_from;
00548 unsigned HOST_WIDE_INT prefetch_before, prefetch_block;
00549
00550 if (delta == 0)
00551 {
00552
00553
00554 if (by_is_before)
00555 ref->prefetch_before = 0;
00556
00557 return;
00558 }
00559
00560 if (!step)
00561 {
00562
00563
00564 if (!by_is_before)
00565 return;
00566
00567 if (ddown (ref->delta, PREFETCH_BLOCK)
00568 != ddown (by->delta, PREFETCH_BLOCK))
00569 return;
00570
00571 ref->prefetch_before = 0;
00572 return;
00573 }
00574
00575
00576 if (backward)
00577 {
00578 if (delta > 0)
00579 return;
00580
00581
00582
00583 delta = - delta;
00584 step = -step;
00585 delta_r = PREFETCH_BLOCK - 1 - delta_r;
00586 delta_b = PREFETCH_BLOCK - 1 - delta_b;
00587 }
00588 else
00589 {
00590 if (delta < 0)
00591 return;
00592 }
00593
00594
00595
00596
00597
00598 if (step <= PREFETCH_BLOCK)
00599 {
00600
00601 hit_from = ddown (delta_b, PREFETCH_BLOCK) * PREFETCH_BLOCK;
00602 prefetch_before = (hit_from - delta_r + step - 1) / step;
00603
00604 if (prefetch_before < ref->prefetch_before)
00605 ref->prefetch_before = prefetch_before;
00606
00607 return;
00608 }
00609
00610
00611
00612
00613 prefetch_block = PREFETCH_BLOCK;
00614 while ((step & 1) == 0
00615 && prefetch_block > 1)
00616 {
00617 step >>= 1;
00618 prefetch_block >>= 1;
00619 delta >>= 1;
00620 }
00621
00622
00623
00624
00625 prefetch_before = delta / step;
00626 delta %= step;
00627 if ((unsigned HOST_WIDE_INT) delta
00628 <= (prefetch_block * ACCEPTABLE_MISS_RATE / 1000))
00629 {
00630 if (prefetch_before < ref->prefetch_before)
00631 ref->prefetch_before = prefetch_before;
00632
00633 return;
00634 }
00635
00636
00637 prefetch_before++;
00638 delta = step - delta;
00639 if ((unsigned HOST_WIDE_INT) delta
00640 <= (prefetch_block * ACCEPTABLE_MISS_RATE / 1000))
00641 {
00642 if (prefetch_before < ref->prefetch_before)
00643 ref->prefetch_before = prefetch_before;
00644
00645 return;
00646 }
00647
00648
00649 return;
00650 }
00651
00652
00653
00654
00655 static void
00656 prune_ref_by_reuse (struct mem_ref *ref, struct mem_ref *refs)
00657 {
00658 struct mem_ref *prune_by;
00659 bool before = true;
00660
00661 prune_ref_by_self_reuse (ref);
00662
00663 for (prune_by = refs; prune_by; prune_by = prune_by->next)
00664 {
00665 if (prune_by == ref)
00666 {
00667 before = false;
00668 continue;
00669 }
00670
00671 if (!WRITE_CAN_USE_READ_PREFETCH
00672 && ref->write_p
00673 && !prune_by->write_p)
00674 continue;
00675 if (!READ_CAN_USE_WRITE_PREFETCH
00676 && !ref->write_p
00677 && prune_by->write_p)
00678 continue;
00679
00680 prune_ref_by_group_reuse (ref, prune_by, before);
00681 }
00682 }
00683
00684
00685
00686 static void
00687 prune_group_by_reuse (struct mem_ref_group *group)
00688 {
00689 struct mem_ref *ref_pruned;
00690
00691 for (ref_pruned = group->refs; ref_pruned; ref_pruned = ref_pruned->next)
00692 {
00693 prune_ref_by_reuse (ref_pruned, group->refs);
00694
00695 if (dump_file && (dump_flags & TDF_DETAILS))
00696 {
00697 fprintf (dump_file, "Reference %p:", (void *) ref_pruned);
00698
00699 if (ref_pruned->prefetch_before == PREFETCH_ALL
00700 && ref_pruned->prefetch_mod == 1)
00701 fprintf (dump_file, " no restrictions");
00702 else if (ref_pruned->prefetch_before == 0)
00703 fprintf (dump_file, " do not prefetch");
00704 else if (ref_pruned->prefetch_before <= ref_pruned->prefetch_mod)
00705 fprintf (dump_file, " prefetch once");
00706 else
00707 {
00708 if (ref_pruned->prefetch_before != PREFETCH_ALL)
00709 {
00710 fprintf (dump_file, " prefetch before ");
00711 fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC,
00712 ref_pruned->prefetch_before);
00713 }
00714 if (ref_pruned->prefetch_mod != 1)
00715 {
00716 fprintf (dump_file, " prefetch mod ");
00717 fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC,
00718 ref_pruned->prefetch_mod);
00719 }
00720 }
00721 fprintf (dump_file, "\n");
00722 }
00723 }
00724 }
00725
00726
00727
00728 static void
00729 prune_by_reuse (struct mem_ref_group *groups)
00730 {
00731 for (; groups; groups = groups->next)
00732 prune_group_by_reuse (groups);
00733 }
00734
00735
00736
00737 static bool
00738 should_issue_prefetch_p (struct mem_ref *ref)
00739 {
00740
00741
00742 if (ref->prefetch_before != PREFETCH_ALL)
00743 return false;
00744
00745 return true;
00746 }
00747
00748
00749
00750
00751
00752
00753
00754 static bool
00755 schedule_prefetches (struct mem_ref_group *groups, unsigned unroll_factor,
00756 unsigned ahead)
00757 {
00758 unsigned max_prefetches, n_prefetches;
00759 struct mem_ref *ref;
00760 bool any = false;
00761
00762 max_prefetches = (SIMULTANEOUS_PREFETCHES * unroll_factor) / ahead;
00763 if (max_prefetches > (unsigned) SIMULTANEOUS_PREFETCHES)
00764 max_prefetches = SIMULTANEOUS_PREFETCHES;
00765
00766 if (dump_file && (dump_flags & TDF_DETAILS))
00767 fprintf (dump_file, "Max prefetches to issue: %d.\n", max_prefetches);
00768
00769 if (!max_prefetches)
00770 return false;
00771
00772
00773
00774
00775
00776
00777 for (; groups; groups = groups->next)
00778 for (ref = groups->refs; ref; ref = ref->next)
00779 {
00780 if (!should_issue_prefetch_p (ref))
00781 continue;
00782
00783 ref->issue_prefetch_p = true;
00784
00785
00786
00787 n_prefetches = ((unroll_factor + ref->prefetch_mod - 1)
00788 / ref->prefetch_mod);
00789 if (max_prefetches <= n_prefetches)
00790 return true;
00791
00792 max_prefetches -= n_prefetches;
00793 any = true;
00794 }
00795
00796 return any;
00797 }
00798
00799
00800
00801
00802 static bool
00803 anything_to_prefetch_p (struct mem_ref_group *groups)
00804 {
00805 struct mem_ref *ref;
00806
00807 for (; groups; groups = groups->next)
00808 for (ref = groups->refs; ref; ref = ref->next)
00809 if (should_issue_prefetch_p (ref))
00810 return true;
00811
00812 return false;
00813 }
00814
00815
00816
00817
00818
00819 static void
00820 issue_prefetch_ref (struct mem_ref *ref, unsigned unroll_factor, unsigned ahead)
00821 {
00822 HOST_WIDE_INT delta;
00823 tree addr, addr_base, prefetch, params, write_p;
00824 block_stmt_iterator bsi;
00825 unsigned n_prefetches, ap;
00826
00827 if (dump_file && (dump_flags & TDF_DETAILS))
00828 fprintf (dump_file, "Issued prefetch for %p.\n", (void *) ref);
00829
00830 bsi = bsi_for_stmt (ref->stmt);
00831
00832 n_prefetches = ((unroll_factor + ref->prefetch_mod - 1)
00833 / ref->prefetch_mod);
00834 addr_base = build_fold_addr_expr_with_type (ref->mem, ptr_type_node);
00835 addr_base = force_gimple_operand_bsi (&bsi, unshare_expr (addr_base), true, NULL);
00836
00837 for (ap = 0; ap < n_prefetches; ap++)
00838 {
00839
00840 delta = (ahead + ap * ref->prefetch_mod) * ref->group->step;
00841 addr = fold_build2 (PLUS_EXPR, ptr_type_node,
00842 addr_base, build_int_cst (ptr_type_node, delta));
00843 addr = force_gimple_operand_bsi (&bsi, unshare_expr (addr), true, NULL);
00844
00845
00846 write_p = ref->write_p ? integer_one_node : integer_zero_node;
00847 params = tree_cons (NULL_TREE, addr,
00848 tree_cons (NULL_TREE, write_p, NULL_TREE));
00849
00850 prefetch = build_function_call_expr (built_in_decls[BUILT_IN_PREFETCH],
00851 params);
00852 bsi_insert_before (&bsi, prefetch, BSI_SAME_STMT);
00853 }
00854 }
00855
00856
00857
00858
00859
00860 static void
00861 issue_prefetches (struct mem_ref_group *groups,
00862 unsigned unroll_factor, unsigned ahead)
00863 {
00864 struct mem_ref *ref;
00865
00866 for (; groups; groups = groups->next)
00867 for (ref = groups->refs; ref; ref = ref->next)
00868 if (ref->issue_prefetch_p)
00869 issue_prefetch_ref (ref, unroll_factor, ahead);
00870 }
00871
00872
00873
00874
00875
00876 static bool
00877 should_unroll_loop_p (struct loop *loop, struct tree_niter_desc *desc,
00878 unsigned factor)
00879 {
00880 if (!can_unroll_loop_p (loop, factor, desc))
00881 return false;
00882
00883
00884
00885
00886
00887
00888 if (loop->num_nodes > 2)
00889 return false;
00890
00891 return true;
00892 }
00893
00894
00895
00896
00897
00898
00899
00900 static unsigned
00901 determine_unroll_factor (struct loop *loop, struct mem_ref_group *refs,
00902 unsigned ahead, unsigned ninsns,
00903 struct tree_niter_desc *desc)
00904 {
00905 unsigned upper_bound, size_factor, constraint_factor;
00906 unsigned factor, max_mod_constraint, ahead_factor;
00907 struct mem_ref_group *agp;
00908 struct mem_ref *ref;
00909
00910 upper_bound = PARAM_VALUE (PARAM_MAX_UNROLL_TIMES);
00911
00912
00913 size_factor = PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS) / ninsns;
00914 if (size_factor <= 1)
00915 return 1;
00916
00917 if (size_factor < upper_bound)
00918 upper_bound = size_factor;
00919
00920 max_mod_constraint = 1;
00921 for (agp = refs; agp; agp = agp->next)
00922 for (ref = agp->refs; ref; ref = ref->next)
00923 if (should_issue_prefetch_p (ref)
00924 && ref->prefetch_mod > max_mod_constraint)
00925 max_mod_constraint = ref->prefetch_mod;
00926
00927
00928
00929 constraint_factor = max_mod_constraint;
00930
00931
00932
00933
00934 ahead_factor = ((ahead + SIMULTANEOUS_PREFETCHES - 1)
00935 / SIMULTANEOUS_PREFETCHES);
00936
00937
00938 if (constraint_factor < ahead_factor)
00939 factor = ahead_factor;
00940 else
00941 factor = constraint_factor;
00942 if (factor > upper_bound)
00943 factor = upper_bound;
00944
00945 if (!should_unroll_loop_p (loop, desc, factor))
00946 return 1;
00947
00948 return factor;
00949 }
00950
00951
00952
00953
00954
00955 static bool
00956 loop_prefetch_arrays (struct loops *loops, struct loop *loop)
00957 {
00958 struct mem_ref_group *refs;
00959 unsigned ahead, ninsns, unroll_factor;
00960 struct tree_niter_desc desc;
00961 bool unrolled = false;
00962
00963
00964 refs = gather_memory_references (loop);
00965
00966
00967 prune_by_reuse (refs);
00968
00969 if (!anything_to_prefetch_p (refs))
00970 goto fail;
00971
00972
00973
00974
00975
00976 ninsns = tree_num_loop_insns (loop);
00977 ahead = (PREFETCH_LATENCY + ninsns - 1) / ninsns;
00978 unroll_factor = determine_unroll_factor (loop, refs, ahead, ninsns,
00979 &desc);
00980 if (dump_file && (dump_flags & TDF_DETAILS))
00981 fprintf (dump_file, "Ahead %d, unroll factor %d\n", ahead, unroll_factor);
00982
00983
00984
00985 if (unroll_factor > 1
00986 && cst_and_fits_in_hwi (desc.niter)
00987 && (unsigned HOST_WIDE_INT) int_cst_value (desc.niter) < unroll_factor)
00988 goto fail;
00989
00990
00991 if (!schedule_prefetches (refs, unroll_factor, ahead))
00992 goto fail;
00993
00994
00995
00996 if (unroll_factor != 1)
00997 {
00998 tree_unroll_loop (loops, loop, unroll_factor,
00999 single_dom_exit (loop), &desc);
01000 unrolled = true;
01001 }
01002
01003
01004 issue_prefetches (refs, unroll_factor, ahead);
01005
01006 fail:
01007 release_mem_refs (refs);
01008 return unrolled;
01009 }
01010
01011
01012
01013 unsigned int
01014 tree_ssa_prefetch_arrays (struct loops *loops)
01015 {
01016 unsigned i;
01017 struct loop *loop;
01018 bool unrolled = false;
01019 int todo_flags = 0;
01020
01021 if (!HAVE_prefetch
01022
01023
01024
01025
01026 || PREFETCH_BLOCK == 0)
01027 return 0;
01028
01029 initialize_original_copy_tables ();
01030
01031 if (!built_in_decls[BUILT_IN_PREFETCH])
01032 {
01033 tree type = build_function_type (void_type_node,
01034 tree_cons (NULL_TREE,
01035 const_ptr_type_node,
01036 NULL_TREE));
01037 tree decl = lang_hooks.builtin_function ("__builtin_prefetch", type,
01038 BUILT_IN_PREFETCH, BUILT_IN_NORMAL,
01039 NULL, NULL_TREE);
01040 DECL_IS_NOVOPS (decl) = true;
01041 built_in_decls[BUILT_IN_PREFETCH] = decl;
01042 }
01043
01044
01045
01046 gcc_assert ((PREFETCH_BLOCK & (PREFETCH_BLOCK - 1)) == 0);
01047
01048 for (i = loops->num - 1; i > 0; i--)
01049 {
01050 loop = loops->parray[i];
01051
01052 if (dump_file && (dump_flags & TDF_DETAILS))
01053 fprintf (dump_file, "Processing loop %d:\n", loop->num);
01054
01055 if (loop)
01056 unrolled |= loop_prefetch_arrays (loops, loop);
01057
01058 if (dump_file && (dump_flags & TDF_DETAILS))
01059 fprintf (dump_file, "\n\n");
01060 }
01061
01062 if (unrolled)
01063 {
01064 scev_reset ();
01065 todo_flags |= TODO_cleanup_cfg;
01066 }
01067
01068 free_original_copy_tables ();
01069 return todo_flags;
01070 }