]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/graphite.c
Update copyright years.
[thirdparty/gcc.git] / gcc / graphite.c
CommitLineData
f8bf9252 1/* Gimple Represented as Polyhedra.
7adcbafe 2 Copyright (C) 2006-2022 Free Software Foundation, Inc.
f8bf9252
SP
3 Contributed by Sebastian Pop <sebastian.pop@inria.fr>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21/* This pass converts GIMPLE to GRAPHITE, performs some loop
22 transformations and then converts the resulting representation back
204b560f 23 to GIMPLE.
f8bf9252
SP
24
25 An early description of this pass can be found in the GCC Summit'06
26 paper "GRAPHITE: Polyhedral Analyses and Optimizations for GCC".
27 The wiki page http://gcc.gnu.org/wiki/Graphite contains pointers to
d6bb5ccf 28 the related work. */
f8bf9252 29
deda4625 30#define INCLUDE_ISL
33ad93b9 31
4d776011 32#include "config.h"
f8bf9252
SP
33#include "system.h"
34#include "coretypes.h"
c7131fb2 35#include "backend.h"
9c358739
AM
36#include "diagnostic-core.h"
37#include "cfgloop.h"
38#include "tree-pass.h"
7009b073 39#include "pretty-print.h"
b25f84d0 40#include "cfganal.h"
9c358739
AM
41
42#ifdef HAVE_isl
9fdcd34e 43#include "cfghooks.h"
40e23961 44#include "tree.h"
c7131fb2 45#include "gimple.h"
ab0e5308 46#include "ssa.h"
c7131fb2 47#include "fold-const.h"
5be5c238 48#include "gimple-iterator.h"
442b4905
AM
49#include "tree-cfg.h"
50#include "tree-ssa-loop.h"
f8bf9252
SP
51#include "tree-data-ref.h"
52#include "tree-scalar-evolution.h"
6a7441f5 53#include "dbgcnt.h"
c1bf2a39 54#include "tree-parloops.h"
4484a35a 55#include "tree-cfgcleanup.h"
558b3185 56#include "tree-vectorizer.h"
ab0e5308 57#include "tree-ssa-loop-manip.h"
6fe00fb7
RB
58#include "tree-ssa.h"
59#include "tree-into-ssa.h"
cf98f0f4 60#include "graphite.h"
57d598f7 61
204b560f 62/* Print global statistics to FILE. */
4d6c7237
SP
63
64static void
204b560f 65print_global_statistics (FILE* file)
4d6c7237 66{
204b560f
SP
67 long n_bbs = 0;
68 long n_loops = 0;
69 long n_stmts = 0;
70 long n_conditions = 0;
3995f3a2
JH
71 profile_count n_p_bbs = profile_count::zero ();
72 profile_count n_p_loops = profile_count::zero ();
73 profile_count n_p_stmts = profile_count::zero ();
74 profile_count n_p_conditions = profile_count::zero ();
4d6c7237 75
204b560f 76 basic_block bb;
4d6c7237 77
04a90bec 78 FOR_ALL_BB_FN (bb, cfun)
204b560f
SP
79 {
80 gimple_stmt_iterator psi;
4d6c7237 81
204b560f 82 n_bbs++;
3995f3a2
JH
83 if (bb->count.initialized_p ())
84 n_p_bbs += bb->count;
4d6c7237 85
204b560f
SP
86 /* Ignore artificial surrounding loop. */
87 if (bb == bb->loop_father->header
88 && bb->index != 0)
4d6c7237 89 {
204b560f
SP
90 n_loops++;
91 n_p_loops += bb->count;
4d6c7237 92 }
4d6c7237 93
d630245f 94 if (EDGE_COUNT (bb->succs) > 1)
204b560f
SP
95 {
96 n_conditions++;
3995f3a2
JH
97 if (bb->count.initialized_p ())
98 n_p_conditions += bb->count;
204b560f 99 }
4d6c7237 100
204b560f
SP
101 for (psi = gsi_start_bb (bb); !gsi_end_p (psi); gsi_next (&psi))
102 {
103 n_stmts++;
3995f3a2
JH
104 if (bb->count.initialized_p ())
105 n_p_stmts += bb->count;
204b560f 106 }
4d6c7237
SP
107 }
108
204b560f
SP
109 fprintf (file, "\nGlobal statistics (");
110 fprintf (file, "BBS:%ld, ", n_bbs);
111 fprintf (file, "LOOPS:%ld, ", n_loops);
112 fprintf (file, "CONDITIONS:%ld, ", n_conditions);
113 fprintf (file, "STMTS:%ld)\n", n_stmts);
c46bd472 114 fprintf (file, "Global profiling statistics (");
3995f3a2
JH
115 fprintf (file, "BBS:");
116 n_p_bbs.dump (file);
117 fprintf (file, ", LOOPS:");
118 n_p_loops.dump (file);
119 fprintf (file, ", CONDITIONS:");
120 n_p_conditions.dump (file);
121 fprintf (file, ", STMTS:");
122 n_p_stmts.dump (file);
c46bd472 123 fprintf (file, ")\n\n");
f8bf9252
SP
124}
125
204b560f 126/* Print statistics for SCOP to FILE. */
f8bf9252
SP
127
128static void
204b560f 129print_graphite_scop_statistics (FILE* file, scop_p scop)
f8bf9252 130{
204b560f
SP
131 long n_bbs = 0;
132 long n_loops = 0;
133 long n_stmts = 0;
134 long n_conditions = 0;
3995f3a2
JH
135 profile_count n_p_bbs = profile_count::zero ();
136 profile_count n_p_loops = profile_count::zero ();
137 profile_count n_p_stmts = profile_count::zero ();
138 profile_count n_p_conditions = profile_count::zero ();
f8bf9252 139
204b560f 140 basic_block bb;
f8bf9252 141
04a90bec 142 FOR_ALL_BB_FN (bb, cfun)
f8bf9252 143 {
204b560f
SP
144 gimple_stmt_iterator psi;
145 loop_p loop = bb->loop_father;
f8bf9252 146
d37fc3aa 147 if (!bb_in_sese_p (bb, scop->scop_info->region))
204b560f 148 continue;
f8bf9252 149
204b560f 150 n_bbs++;
3995f3a2
JH
151 if (bb->count.initialized_p ())
152 n_p_bbs += bb->count;
f8bf9252 153
d630245f 154 if (EDGE_COUNT (bb->succs) > 1)
f8bf9252 155 {
204b560f
SP
156 n_conditions++;
157 n_p_conditions += bb->count;
f8bf9252 158 }
f8bf9252 159
204b560f 160 for (psi = gsi_start_bb (bb); !gsi_end_p (psi); gsi_next (&psi))
f8bf9252 161 {
204b560f
SP
162 n_stmts++;
163 n_p_stmts += bb->count;
f8bf9252 164 }
f8bf9252 165
d37fc3aa 166 if (loop->header == bb && loop_in_sese_p (loop, scop->scop_info->region))
204b560f
SP
167 {
168 n_loops++;
169 n_p_loops += bb->count;
170 }
171 }
6a114766 172
7009b073
SP
173 fprintf (file, "\nFunction Name: %s\n", current_function_name ());
174
d37fc3aa
AK
175 edge scop_begin = scop->scop_info->region.entry;
176 edge scop_end = scop->scop_info->region.exit;
7009b073
SP
177
178 fprintf (file, "\nSCoP (entry_edge (bb_%d, bb_%d), ",
179 scop_begin->src->index, scop_begin->dest->index);
180 fprintf (file, "exit_edge (bb_%d, bb_%d))",
181 scop_end->src->index, scop_end->dest->index);
182
204b560f
SP
183 fprintf (file, "\nSCoP statistics (");
184 fprintf (file, "BBS:%ld, ", n_bbs);
185 fprintf (file, "LOOPS:%ld, ", n_loops);
186 fprintf (file, "CONDITIONS:%ld, ", n_conditions);
187 fprintf (file, "STMTS:%ld)\n", n_stmts);
c46bd472 188 fprintf (file, "SCoP profiling statistics (");
3995f3a2
JH
189 fprintf (file, "BBS:");
190 n_p_bbs.dump (file);
191 fprintf (file, ", LOOPS:");
192 n_p_loops.dump (file);
193 fprintf (file, ", CONDITIONS:");
194 n_p_conditions.dump (file);
195 fprintf (file, ", STMTS:");
196 n_p_stmts.dump (file);
c46bd472 197 fprintf (file, ")\n\n");
f8bf9252
SP
198}
199
204b560f 200/* Print statistics for SCOPS to FILE. */
f8bf9252 201
204b560f 202static void
9771b263 203print_graphite_statistics (FILE* file, vec<scop_p> scops)
f8bf9252 204{
f8bf9252 205 int i;
204b560f 206 scop_p scop;
f8bf9252 207
9771b263 208 FOR_EACH_VEC_ELT (scops, i, scop)
204b560f 209 print_graphite_scop_statistics (file, scop);
f8bf9252
SP
210}
211
124f4f57
RB
212struct seir_cache_key
213{
214 hashval_t hash;
215 int entry_dest;
216 int exit_src;
217 int loop_num;
218 tree expr;
219};
220
221struct sese_scev_hash : typed_noop_remove <seir_cache_key>
222{
223 typedef seir_cache_key value_type;
224 typedef seir_cache_key compare_type;
225 static hashval_t hash (const seir_cache_key &key) { return key.hash; }
226 static bool
227 equal (const seir_cache_key &key1, const seir_cache_key &key2)
228 {
229 return (key1.hash == key2.hash
230 && key1.entry_dest == key2.entry_dest
231 && key1.exit_src == key2.exit_src
232 && key1.loop_num == key2.loop_num
233 && operand_equal_p (key1.expr, key2.expr, 0));
234 }
235 static void mark_deleted (seir_cache_key &key) { key.expr = NULL_TREE; }
7ca50de0 236 static const bool empty_zero_p = false;
124f4f57
RB
237 static void mark_empty (seir_cache_key &key) { key.entry_dest = 0; }
238 static bool is_deleted (const seir_cache_key &key) { return !key.expr; }
239 static bool is_empty (const seir_cache_key &key) { return key.entry_dest == 0; }
240};
241
242static hash_map<sese_scev_hash, tree> *seir_cache;
243
244/* Same as scalar_evolution_in_region but caches results so we avoid
245 re-computing evolutions during transform phase. */
246
247tree
248cached_scalar_evolution_in_region (const sese_l &region, loop_p loop,
249 tree expr)
250{
251 seir_cache_key key;
252 key.entry_dest = region.entry->dest->index;
253 key.exit_src = region.exit->src->index;
254 key.loop_num = loop->num;
255 key.expr = expr;
256 inchash::hash hstate (0);
257 hstate.add_int (key.entry_dest);
258 hstate.add_int (key.exit_src);
259 hstate.add_int (key.loop_num);
260 inchash::add_expr (key.expr, hstate);
261 key.hash = hstate.end ();
262
263 bool existed;
264 tree &chrec = seir_cache->get_or_insert (key, &existed);
265 if (!existed)
266 chrec = scalar_evolution_in_region (region, loop, expr);
267 return chrec;
268}
269
87ccab5d
AK
270/* Deletes all scops in SCOPS. */
271
272static void
273free_scops (vec<scop_p> scops)
274{
275 int i;
276 scop_p scop;
277
278 FOR_EACH_VEC_ELT (scops, i, scop)
279 free_scop (scop);
280
281 scops.release ();
282}
283
ab0e5308
RB
284/* Transforms LOOP to the canonical loop closed SSA form. */
285
286static void
82c066f5 287canonicalize_loop_closed_ssa (loop_p loop, edge e)
ab0e5308 288{
ab0e5308 289 basic_block bb;
4d6e2f33 290 gphi_iterator psi;
ab0e5308 291
ab0e5308
RB
292 bb = e->dest;
293
4d6e2f33
RB
294 /* Make the loop-close PHI node BB contain only PHIs and have a
295 single predecessor. */
ab0e5308
RB
296 if (single_pred_p (bb))
297 {
298 e = split_block_after_labels (bb);
4d6e2f33 299 bb = e->src;
ab0e5308
RB
300 }
301 else
302 {
ab0e5308
RB
303 basic_block close = split_edge (e);
304 e = single_succ_edge (close);
305 for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi))
306 {
307 gphi *phi = psi.phi ();
308 use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
309 tree arg = USE_FROM_PTR (use_p);
310
311 /* Only add close phi nodes for SSA_NAMEs defined in LOOP. */
312 if (TREE_CODE (arg) != SSA_NAME
621e5370
RB
313 || SSA_NAME_IS_DEFAULT_DEF (arg)
314 || ! flow_bb_inside_loop_p (loop,
315 gimple_bb (SSA_NAME_DEF_STMT (arg))))
ab0e5308
RB
316 continue;
317
318 tree res = copy_ssa_name (arg);
319 gphi *close_phi = create_phi_node (res, close);
320 add_phi_arg (close_phi, arg, gimple_phi_arg_edge (close_phi, 0),
321 UNKNOWN_LOCATION);
322 SET_USE (use_p, res);
323 }
4d6e2f33
RB
324 bb = close;
325 }
326
327 /* Eliminate duplicates. This relies on processing loops from
328 innermost to outer. */
329 for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi))
330 {
331 gphi_iterator gsi = psi;
332 gphi *phi = psi.phi ();
333
334 /* At this point, PHI should be a close phi in normal form. */
335 gcc_assert (gimple_phi_num_args (phi) == 1);
ab0e5308 336
4d6e2f33
RB
337 /* Iterate over the next phis and remove duplicates. */
338 gsi_next (&gsi);
339 while (!gsi_end_p (gsi))
340 if (gimple_phi_arg_def (phi, 0) == gimple_phi_arg_def (gsi.phi (), 0))
341 {
342 replace_uses_by (gimple_phi_result (gsi.phi ()),
343 gimple_phi_result (phi));
344 remove_phi_node (&gsi, true);
345 }
346 else
347 gsi_next (&gsi);
ab0e5308
RB
348 }
349}
350
351/* Converts the current loop closed SSA form to a canonical form
352 expected by the Graphite code generation.
353
354 The loop closed SSA form has the following invariant: a variable
355 defined in a loop that is used outside the loop appears only in the
356 phi nodes in the destination of the loop exit. These phi nodes are
357 called close phi nodes.
358
359 The canonical loop closed SSA form contains the extra invariants:
360
361 - when the loop contains only one exit, the close phi nodes contain
362 only one argument. That implies that the basic block that contains
363 the close phi nodes has only one predecessor, that is a basic block
364 in the loop.
365
366 - the basic block containing the close phi nodes does not contain
367 other statements.
368
369 - there exist only one phi node per definition in the loop.
82c066f5
RB
370
371 In addition to that we also make sure that loop exit edges are
372 first in the successor edge vector. This is to make RPO order
373 as computed by pre_and_rev_post_order_compute be consistent with
374 what initial schedule generation expects.
ab0e5308
RB
375*/
376
377static void
82c066f5 378canonicalize_loop_form (void)
ab0e5308 379{
e41ba804 380 for (auto loop : loops_list (cfun, LI_FROM_INNERMOST))
82c066f5
RB
381 {
382 edge e = single_exit (loop);
b0bd3e52 383 if (!e || (e->flags & (EDGE_COMPLEX|EDGE_FAKE)))
82c066f5
RB
384 continue;
385
386 canonicalize_loop_closed_ssa (loop, e);
387
388 /* If the exit is not first in the edge vector make it so. */
389 if (e != EDGE_SUCC (e->src, 0))
390 {
391 unsigned ei;
392 for (ei = 0; EDGE_SUCC (e->src, ei) != e; ++ei)
393 ;
394 std::swap (EDGE_SUCC (e->src, ei), EDGE_SUCC (e->src, 0));
395 }
396 }
ab0e5308 397
b33086c0
RB
398 /* We can end up releasing duplicate exit PHIs and also introduce
399 additional copies so the cached information isn't correct anymore. */
400 scev_reset ();
401
ab0e5308
RB
402 checking_verify_loop_closed_ssa (true);
403}
404
33ad93b9
RG
405isl_ctx *the_isl_ctx;
406
f8bf9252
SP
407/* Perform a set of linear transforms on the loops of the current
408 function. */
409
410void
411graphite_transform_loops (void)
412{
413 int i;
414 scop_p scop;
6fe00fb7 415 bool changed = false;
6e1aa848 416 vec<scop_p> scops = vNULL;
33ad93b9 417 isl_ctx *ctx;
f8bf9252 418
62e0a1ed
RG
419 /* If a function is parallel it was most probably already run through graphite
420 once. No need to run again. */
421 if (parallelized_function_p (cfun->decl))
422 return;
423
6fe00fb7 424 calculate_dominance_info (CDI_DOMINATORS);
f8bf9252 425
b25f84d0
RB
426 /* We rely on post-dominators during merging of SESE regions so those
427 have to be meaningful. */
428 connect_infinite_loops_to_exit ();
429
ab0e5308
RB
430 ctx = isl_ctx_alloc ();
431 isl_options_set_on_error (ctx, ISL_ON_ERROR_ABORT);
33ad93b9 432 the_isl_ctx = ctx;
ab0e5308 433
26993e95 434 sort_sibling_loops (cfun);
82c066f5 435 canonicalize_loop_form ();
ab0e5308 436
c46bd472
RB
437 /* Print the loop structure. */
438 if (dump_file && (dump_flags & TDF_DETAILS))
439 {
440 print_loops (dump_file, 2);
441 print_loops (dump_file, 3);
442 }
443
124f4f57
RB
444 seir_cache = new hash_map<sese_scev_hash, tree>;
445
ab0e5308 446 calculate_dominance_info (CDI_POST_DOMINATORS);
204b560f 447 build_scops (&scops);
ab0e5308 448 free_dominance_info (CDI_POST_DOMINATORS);
f8bf9252 449
b25f84d0
RB
450 /* Remove the fake exits before transform given they are not reflected
451 in loop structures we end up verifying. */
452 remove_fake_exit_edges ();
453
f8bf9252 454 if (dump_file && (dump_flags & TDF_DETAILS))
f8bf9252 455 {
204b560f
SP
456 print_graphite_statistics (dump_file, scops);
457 print_global_statistics (dump_file);
458 }
0b040072 459
9771b263 460 FOR_EACH_VEC_ELT (scops, i, scop)
6a7441f5
SP
461 if (dbg_cnt (graphite_scop))
462 {
8e4dc590 463 scop->isl_context = ctx;
36f40be0
AK
464 if (!build_poly_scop (scop))
465 continue;
466
467 if (!apply_poly_transforms (scop))
468 continue;
469
6fe00fb7 470 changed = true;
bbeeac91
DM
471 if (graphite_regenerate_ast_isl (scop)
472 && dump_enabled_p ())
e33507e3 473 {
4f5b9c80 474 dump_user_location_t loc = find_loop_location
e33507e3
RB
475 (scops[i]->scop_info->region.entry->dest->loop_father);
476 dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
477 "loop nest optimized\n");
478 }
efa21390 479 }
f8bf9252 480
124f4f57
RB
481 delete seir_cache;
482 seir_cache = NULL;
483
6fe00fb7
RB
484 if (changed)
485 {
486 mark_virtual_operands_for_renaming (cfun);
487 update_ssa (TODO_update_ssa);
488 checking_verify_ssa (true, true);
489 rewrite_into_loop_closed_ssa (NULL, 0);
490 scev_reset ();
491 checking_verify_loop_structure ();
492 }
493
4d6e2f33
RB
494 if (dump_file && (dump_flags & TDF_DETAILS))
495 {
4d6e2f33
RB
496 int num_no_dependency = 0;
497
e41ba804 498 for (auto loop : loops_list (cfun, 0))
4d6e2f33
RB
499 if (loop->can_be_parallel)
500 num_no_dependency++;
501
502 fprintf (dump_file, "%d loops carried no dependency.\n",
503 num_no_dependency);
504 }
505
204b560f 506 free_scops (scops);
33ad93b9
RG
507 the_isl_ctx = NULL;
508 isl_ctx_free (ctx);
6fe00fb7
RB
509
510 if (changed)
511 {
512 cleanup_tree_cfg ();
513 profile_status_for_fn (cfun) = PROFILE_ABSENT;
514 release_recorded_exits (cfun);
515 tree_estimate_probability (false);
516 }
f8bf9252
SP
517}
518
e357a5e0 519#else /* If isl is not available: #ifndef HAVE_isl. */
f8bf9252 520
c1bf2a39 521static void
f8bf9252
SP
522graphite_transform_loops (void)
523{
e357a5e0 524 sorry ("Graphite loop optimizations cannot be used (isl is not available).");
f8bf9252
SP
525}
526
527#endif
c1bf2a39
AM
528
529
530static unsigned int
726338f4 531graphite_transforms (struct function *fun)
c1bf2a39 532{
726338f4 533 if (number_of_loops (fun) <= 1)
c1bf2a39
AM
534 return 0;
535
536 graphite_transform_loops ();
537
538 return 0;
539}
540
541static bool
542gate_graphite_transforms (void)
543{
544 /* Enable -fgraphite pass if any one of the graphite optimization flags
545 is turned on. */
d6bb5ccf 546 if (flag_graphite_identity
c1bf2a39 547 || flag_loop_parallelize_all
84c36240 548 || flag_loop_nest_optimize)
c1bf2a39
AM
549 flag_graphite = 1;
550
551 return flag_graphite != 0;
552}
553
17795822
TS
554namespace {
555
556const pass_data pass_data_graphite =
c1bf2a39
AM
557{
558 GIMPLE_PASS, /* type */
559 "graphite0", /* name */
560 OPTGROUP_LOOP, /* optinfo_flags */
c1bf2a39
AM
561 TV_GRAPHITE, /* tv_id */
562 ( PROP_cfg | PROP_ssa ), /* properties_required */
563 0, /* properties_provided */
564 0, /* properties_destroyed */
565 0, /* todo_flags_start */
566 0, /* todo_flags_finish */
567};
568
17795822 569class pass_graphite : public gimple_opt_pass
c1bf2a39
AM
570{
571public:
572 pass_graphite (gcc::context *ctxt)
573 : gimple_opt_pass (pass_data_graphite, ctxt)
574 {}
575
576 /* opt_pass methods: */
1a3d085c 577 virtual bool gate (function *) { return gate_graphite_transforms (); }
c1bf2a39
AM
578
579}; // class pass_graphite
580
17795822
TS
581} // anon namespace
582
c1bf2a39
AM
583gimple_opt_pass *
584make_pass_graphite (gcc::context *ctxt)
585{
586 return new pass_graphite (ctxt);
587}
588
17795822
TS
589namespace {
590
591const pass_data pass_data_graphite_transforms =
c1bf2a39
AM
592{
593 GIMPLE_PASS, /* type */
594 "graphite", /* name */
595 OPTGROUP_LOOP, /* optinfo_flags */
c1bf2a39
AM
596 TV_GRAPHITE_TRANSFORMS, /* tv_id */
597 ( PROP_cfg | PROP_ssa ), /* properties_required */
598 0, /* properties_provided */
599 0, /* properties_destroyed */
600 0, /* todo_flags_start */
601 0, /* todo_flags_finish */
602};
603
17795822 604class pass_graphite_transforms : public gimple_opt_pass
c1bf2a39
AM
605{
606public:
607 pass_graphite_transforms (gcc::context *ctxt)
608 : gimple_opt_pass (pass_data_graphite_transforms, ctxt)
609 {}
610
611 /* opt_pass methods: */
1a3d085c 612 virtual bool gate (function *) { return gate_graphite_transforms (); }
726338f4 613 virtual unsigned int execute (function *fun) { return graphite_transforms (fun); }
c1bf2a39
AM
614
615}; // class pass_graphite_transforms
616
17795822
TS
617} // anon namespace
618
c1bf2a39
AM
619gimple_opt_pass *
620make_pass_graphite_transforms (gcc::context *ctxt)
621{
622 return new pass_graphite_transforms (ctxt);
623}
624
625