1 /* Gimple ranger SSA cache implementation.
2 Copyright (C) 2017-2021 Free Software Foundation, Inc.
3 Contributed by Andrew MacLeod <amacleod@redhat.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "insn-codes.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "ssa.h"
29 #include "gimple-pretty-print.h"
30 #include "gimple-range.h"
31
32 // During contructor, allocate the vector of ssa_names.
33
non_null_ref()34 non_null_ref::non_null_ref ()
35 {
36 m_nn.create (0);
37 m_nn.safe_grow_cleared (num_ssa_names);
38 bitmap_obstack_initialize (&m_bitmaps);
39 }
40
41 // Free any bitmaps which were allocated,a swell as the vector itself.
42
~non_null_ref()43 non_null_ref::~non_null_ref ()
44 {
45 bitmap_obstack_release (&m_bitmaps);
46 m_nn.release ();
47 }
48
49 // Return true if NAME has a non-null dereference in block bb. If this is the
50 // first query for NAME, calculate the summary first.
51
52 bool
non_null_deref_p(tree name,basic_block bb)53 non_null_ref::non_null_deref_p (tree name, basic_block bb)
54 {
55 if (!POINTER_TYPE_P (TREE_TYPE (name)))
56 return false;
57
58 unsigned v = SSA_NAME_VERSION (name);
59 if (!m_nn[v])
60 process_name (name);
61
62 return bitmap_bit_p (m_nn[v], bb->index);
63 }
64
65 // Allocate an populate the bitmap for NAME. An ON bit for a block
66 // index indicates there is a non-null reference in that block. In
67 // order to populate the bitmap, a quick run of all the immediate uses
68 // are made and the statement checked to see if a non-null dereference
69 // is made on that statement.
70
71 void
process_name(tree name)72 non_null_ref::process_name (tree name)
73 {
74 unsigned v = SSA_NAME_VERSION (name);
75 use_operand_p use_p;
76 imm_use_iterator iter;
77 bitmap b;
78
79 // Only tracked for pointers.
80 if (!POINTER_TYPE_P (TREE_TYPE (name)))
81 return;
82
83 // Already processed if a bitmap has been allocated.
84 if (m_nn[v])
85 return;
86
87 b = BITMAP_ALLOC (&m_bitmaps);
88
89 // Loop over each immediate use and see if it implies a non-null value.
90 FOR_EACH_IMM_USE_FAST (use_p, iter, name)
91 {
92 gimple *s = USE_STMT (use_p);
93 unsigned index = gimple_bb (s)->index;
94
95 // If bit is already set for this block, dont bother looking again.
96 if (bitmap_bit_p (b, index))
97 continue;
98
99 // If we can infer a nonnull range, then set the bit for this BB
100 if (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name)
101 && infer_nonnull_range (s, name))
102 bitmap_set_bit (b, index);
103 }
104
105 m_nn[v] = b;
106 }
107
108 // -------------------------------------------------------------------------
109
110 // This class represents the API into a cache of ranges for an SSA_NAME.
111 // Routines must be implemented to set, get, and query if a value is set.
112
113 class ssa_block_ranges
114 {
115 public:
116 virtual bool set_bb_range (const basic_block bb, const irange &r) = 0;
117 virtual bool get_bb_range (irange &r, const basic_block bb) = 0;
118 virtual bool bb_range_p (const basic_block bb) = 0;
119
120 void dump(FILE *f);
121 };
122
123 // Print the list of known ranges for file F in a nice format.
124
125 void
dump(FILE * f)126 ssa_block_ranges::dump (FILE *f)
127 {
128 basic_block bb;
129 int_range_max r;
130
131 FOR_EACH_BB_FN (bb, cfun)
132 if (get_bb_range (r, bb))
133 {
134 fprintf (f, "BB%d -> ", bb->index);
135 r.dump (f);
136 fprintf (f, "\n");
137 }
138 }
139
140 // This class implements the range cache as a linear vector, indexed by BB.
141 // It caches a varying and undefined range which are used instead of
142 // allocating new ones each time.
143
144 class sbr_vector : public ssa_block_ranges
145 {
146 public:
147 sbr_vector (tree t, irange_allocator *allocator);
148
149 virtual bool set_bb_range (const basic_block bb, const irange &r) OVERRIDE;
150 virtual bool get_bb_range (irange &r, const basic_block bb) OVERRIDE;
151 virtual bool bb_range_p (const basic_block bb) OVERRIDE;
152 protected:
153 irange **m_tab; // Non growing vector.
154 int m_tab_size;
155 int_range<2> m_varying;
156 int_range<2> m_undefined;
157 tree m_type;
158 irange_allocator *m_irange_allocator;
159 };
160
161
162 // Initialize a block cache for an ssa_name of type T.
163
sbr_vector(tree t,irange_allocator * allocator)164 sbr_vector::sbr_vector (tree t, irange_allocator *allocator)
165 {
166 gcc_checking_assert (TYPE_P (t));
167 m_type = t;
168 m_irange_allocator = allocator;
169 m_tab_size = last_basic_block_for_fn (cfun) + 1;
170 m_tab = (irange **)allocator->get_memory (m_tab_size * sizeof (irange *));
171 memset (m_tab, 0, m_tab_size * sizeof (irange *));
172
173 // Create the cached type range.
174 m_varying.set_varying (t);
175 m_undefined.set_undefined ();
176 }
177
178 // Set the range for block BB to be R.
179
180 bool
set_bb_range(const basic_block bb,const irange & r)181 sbr_vector::set_bb_range (const basic_block bb, const irange &r)
182 {
183 irange *m;
184 gcc_checking_assert (bb->index < m_tab_size);
185 if (r.varying_p ())
186 m = &m_varying;
187 else if (r.undefined_p ())
188 m = &m_undefined;
189 else
190 m = m_irange_allocator->allocate (r);
191 m_tab[bb->index] = m;
192 return true;
193 }
194
195 // Return the range associated with block BB in R. Return false if
196 // there is no range.
197
198 bool
get_bb_range(irange & r,const basic_block bb)199 sbr_vector::get_bb_range (irange &r, const basic_block bb)
200 {
201 gcc_checking_assert (bb->index < m_tab_size);
202 irange *m = m_tab[bb->index];
203 if (m)
204 {
205 r = *m;
206 return true;
207 }
208 return false;
209 }
210
211 // Return true if a range is present.
212
213 bool
bb_range_p(const basic_block bb)214 sbr_vector::bb_range_p (const basic_block bb)
215 {
216 gcc_checking_assert (bb->index < m_tab_size);
217 return m_tab[bb->index] != NULL;
218 }
219
220 // This class implements the on entry cache via a sparse bitmap.
221 // It uses the quad bit routines to access 4 bits at a time.
222 // A value of 0 (the default) means there is no entry, and a value of
223 // 1 thru SBR_NUM represents an element in the m_range vector.
224 // Varying is given the first value (1) and pre-cached.
225 // SBR_NUM + 1 represents the value of UNDEFINED, and is never stored.
226 // SBR_NUM is the number of values that can be cached.
227 // Indexes are 1..SBR_NUM and are stored locally at m_range[0..SBR_NUM-1]
228
229 #define SBR_NUM 14
230 #define SBR_UNDEF SBR_NUM + 1
231 #define SBR_VARYING 1
232
233 class sbr_sparse_bitmap : public ssa_block_ranges
234 {
235 public:
236 sbr_sparse_bitmap (tree t, irange_allocator *allocator, bitmap_obstack *bm);
237 virtual bool set_bb_range (const basic_block bb, const irange &r) OVERRIDE;
238 virtual bool get_bb_range (irange &r, const basic_block bb) OVERRIDE;
239 virtual bool bb_range_p (const basic_block bb) OVERRIDE;
240 private:
241 void bitmap_set_quad (bitmap head, int quad, int quad_value);
242 int bitmap_get_quad (const_bitmap head, int quad);
243 irange_allocator *m_irange_allocator;
244 irange *m_range[SBR_NUM];
245 bitmap bitvec;
246 tree m_type;
247 };
248
249 // Initialize a block cache for an ssa_name of type T.
250
sbr_sparse_bitmap(tree t,irange_allocator * allocator,bitmap_obstack * bm)251 sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, irange_allocator *allocator,
252 bitmap_obstack *bm)
253 {
254 gcc_checking_assert (TYPE_P (t));
255 m_type = t;
256 bitvec = BITMAP_ALLOC (bm);
257 m_irange_allocator = allocator;
258 // Pre-cache varying.
259 m_range[0] = m_irange_allocator->allocate (2);
260 m_range[0]->set_varying (t);
261 // Pre-cache zero and non-zero values for pointers.
262 if (POINTER_TYPE_P (t))
263 {
264 m_range[1] = m_irange_allocator->allocate (2);
265 m_range[1]->set_nonzero (t);
266 m_range[2] = m_irange_allocator->allocate (2);
267 m_range[2]->set_zero (t);
268 }
269 else
270 m_range[1] = m_range[2] = NULL;
271 // Clear SBR_NUM entries.
272 for (int x = 3; x < SBR_NUM; x++)
273 m_range[x] = 0;
274 }
275
276 // Set 4 bit values in a sparse bitmap. This allows a bitmap to
277 // function as a sparse array of 4 bit values.
278 // QUAD is the index, QUAD_VALUE is the 4 bit value to set.
279
280 inline void
bitmap_set_quad(bitmap head,int quad,int quad_value)281 sbr_sparse_bitmap::bitmap_set_quad (bitmap head, int quad, int quad_value)
282 {
283 bitmap_set_aligned_chunk (head, quad, 4, (BITMAP_WORD) quad_value);
284 }
285
286 // Get a 4 bit value from a sparse bitmap. This allows a bitmap to
287 // function as a sparse array of 4 bit values.
288 // QUAD is the index.
289 inline int
bitmap_get_quad(const_bitmap head,int quad)290 sbr_sparse_bitmap::bitmap_get_quad (const_bitmap head, int quad)
291 {
292 return (int) bitmap_get_aligned_chunk (head, quad, 4);
293 }
294
295 // Set the range on entry to basic block BB to R.
296
297 bool
set_bb_range(const basic_block bb,const irange & r)298 sbr_sparse_bitmap::set_bb_range (const basic_block bb, const irange &r)
299 {
300 if (r.undefined_p ())
301 {
302 bitmap_set_quad (bitvec, bb->index, SBR_UNDEF);
303 return true;
304 }
305
306 // Loop thru the values to see if R is already present.
307 for (int x = 0; x < SBR_NUM; x++)
308 if (!m_range[x] || r == *(m_range[x]))
309 {
310 if (!m_range[x])
311 m_range[x] = m_irange_allocator->allocate (r);
312 bitmap_set_quad (bitvec, bb->index, x + 1);
313 return true;
314 }
315 // All values are taken, default to VARYING.
316 bitmap_set_quad (bitvec, bb->index, SBR_VARYING);
317 return false;
318 }
319
320 // Return the range associated with block BB in R. Return false if
321 // there is no range.
322
323 bool
get_bb_range(irange & r,const basic_block bb)324 sbr_sparse_bitmap::get_bb_range (irange &r, const basic_block bb)
325 {
326 int value = bitmap_get_quad (bitvec, bb->index);
327
328 if (!value)
329 return false;
330
331 gcc_checking_assert (value <= SBR_UNDEF);
332 if (value == SBR_UNDEF)
333 r.set_undefined ();
334 else
335 r = *(m_range[value - 1]);
336 return true;
337 }
338
339 // Return true if a range is present.
340
341 bool
bb_range_p(const basic_block bb)342 sbr_sparse_bitmap::bb_range_p (const basic_block bb)
343 {
344 return (bitmap_get_quad (bitvec, bb->index) != 0);
345 }
346
347 // -------------------------------------------------------------------------
348
349 // Initialize the block cache.
350
block_range_cache()351 block_range_cache::block_range_cache ()
352 {
353 bitmap_obstack_initialize (&m_bitmaps);
354 m_ssa_ranges.create (0);
355 m_ssa_ranges.safe_grow_cleared (num_ssa_names);
356 m_irange_allocator = new irange_allocator;
357 }
358
359 // Remove any m_block_caches which have been created.
360
~block_range_cache()361 block_range_cache::~block_range_cache ()
362 {
363 delete m_irange_allocator;
364 // Release the vector itself.
365 m_ssa_ranges.release ();
366 bitmap_obstack_release (&m_bitmaps);
367 }
368
369 // Set the range for NAME on entry to block BB to R.
370 // If it has not been // accessed yet, allocate it first.
371
372 bool
set_bb_range(tree name,const basic_block bb,const irange & r)373 block_range_cache::set_bb_range (tree name, const basic_block bb,
374 const irange &r)
375 {
376 unsigned v = SSA_NAME_VERSION (name);
377 if (v >= m_ssa_ranges.length ())
378 m_ssa_ranges.safe_grow_cleared (num_ssa_names + 1);
379
380 if (!m_ssa_ranges[v])
381 {
382 // Use sparse representation if there are too many basic blocks.
383 if (last_basic_block_for_fn (cfun) > param_evrp_sparse_threshold)
384 {
385 void *r = m_irange_allocator->get_memory (sizeof (sbr_sparse_bitmap));
386 m_ssa_ranges[v] = new (r) sbr_sparse_bitmap (TREE_TYPE (name),
387 m_irange_allocator,
388 &m_bitmaps);
389 }
390 else
391 {
392 // Otherwise use the default vector implemntation.
393 void *r = m_irange_allocator->get_memory (sizeof (sbr_vector));
394 m_ssa_ranges[v] = new (r) sbr_vector (TREE_TYPE (name),
395 m_irange_allocator);
396 }
397 }
398 return m_ssa_ranges[v]->set_bb_range (bb, r);
399 }
400
401
402 // Return a pointer to the ssa_block_cache for NAME. If it has not been
403 // accessed yet, return NULL.
404
405 inline ssa_block_ranges *
query_block_ranges(tree name)406 block_range_cache::query_block_ranges (tree name)
407 {
408 unsigned v = SSA_NAME_VERSION (name);
409 if (v >= m_ssa_ranges.length () || !m_ssa_ranges[v])
410 return NULL;
411 return m_ssa_ranges[v];
412 }
413
414
415
416 // Return the range for NAME on entry to BB in R. Return true if there
417 // is one.
418
419 bool
get_bb_range(irange & r,tree name,const basic_block bb)420 block_range_cache::get_bb_range (irange &r, tree name, const basic_block bb)
421 {
422 ssa_block_ranges *ptr = query_block_ranges (name);
423 if (ptr)
424 return ptr->get_bb_range (r, bb);
425 return false;
426 }
427
428 // Return true if NAME has a range set in block BB.
429
430 bool
bb_range_p(tree name,const basic_block bb)431 block_range_cache::bb_range_p (tree name, const basic_block bb)
432 {
433 ssa_block_ranges *ptr = query_block_ranges (name);
434 if (ptr)
435 return ptr->bb_range_p (bb);
436 return false;
437 }
438
439 // Print all known block caches to file F.
440
441 void
dump(FILE * f)442 block_range_cache::dump (FILE *f)
443 {
444 unsigned x;
445 for (x = 0; x < m_ssa_ranges.length (); ++x)
446 {
447 if (m_ssa_ranges[x])
448 {
449 fprintf (f, " Ranges for ");
450 print_generic_expr (f, ssa_name (x), TDF_NONE);
451 fprintf (f, ":\n");
452 m_ssa_ranges[x]->dump (f);
453 fprintf (f, "\n");
454 }
455 }
456 }
457
458 // Print all known ranges on entry to blobk BB to file F.
459
460 void
dump(FILE * f,basic_block bb,bool print_varying)461 block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
462 {
463 unsigned x;
464 int_range_max r;
465 bool summarize_varying = false;
466 for (x = 1; x < m_ssa_ranges.length (); ++x)
467 {
468 if (!gimple_range_ssa_p (ssa_name (x)))
469 continue;
470 if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
471 {
472 if (!print_varying && r.varying_p ())
473 {
474 summarize_varying = true;
475 continue;
476 }
477 print_generic_expr (f, ssa_name (x), TDF_NONE);
478 fprintf (f, "\t");
479 r.dump(f);
480 fprintf (f, "\n");
481 }
482 }
483 // If there were any varying entries, lump them all together.
484 if (summarize_varying)
485 {
486 fprintf (f, "VARYING_P on entry : ");
487 for (x = 1; x < num_ssa_names; ++x)
488 {
489 if (!gimple_range_ssa_p (ssa_name (x)))
490 continue;
491 if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
492 {
493 if (r.varying_p ())
494 {
495 print_generic_expr (f, ssa_name (x), TDF_NONE);
496 fprintf (f, " ");
497 }
498 }
499 }
500 fprintf (f, "\n");
501 }
502 }
503
504 // -------------------------------------------------------------------------
505
506 // Initialize a global cache.
507
ssa_global_cache()508 ssa_global_cache::ssa_global_cache ()
509 {
510 m_tab.create (0);
511 m_tab.safe_grow_cleared (num_ssa_names);
512 m_irange_allocator = new irange_allocator;
513 }
514
515 // Deconstruct a global cache.
516
~ssa_global_cache()517 ssa_global_cache::~ssa_global_cache ()
518 {
519 m_tab.release ();
520 delete m_irange_allocator;
521 }
522
523 // Retrieve the global range of NAME from cache memory if it exists.
524 // Return the value in R.
525
526 bool
get_global_range(irange & r,tree name) const527 ssa_global_cache::get_global_range (irange &r, tree name) const
528 {
529 unsigned v = SSA_NAME_VERSION (name);
530 if (v >= m_tab.length ())
531 return false;
532
533 irange *stow = m_tab[v];
534 if (!stow)
535 return false;
536 r = *stow;
537 return true;
538 }
539
540 // Set the range for NAME to R in the global cache.
541 // Return TRUE if there was already a range set, otherwise false.
542
543 bool
set_global_range(tree name,const irange & r)544 ssa_global_cache::set_global_range (tree name, const irange &r)
545 {
546 unsigned v = SSA_NAME_VERSION (name);
547 if (v >= m_tab.length ())
548 m_tab.safe_grow_cleared (num_ssa_names + 1);
549
550 irange *m = m_tab[v];
551 if (m && m->fits_p (r))
552 *m = r;
553 else
554 m_tab[v] = m_irange_allocator->allocate (r);
555 return m != NULL;
556 }
557
558 // Set the range for NAME to R in the glonbal cache.
559
560 void
clear_global_range(tree name)561 ssa_global_cache::clear_global_range (tree name)
562 {
563 unsigned v = SSA_NAME_VERSION (name);
564 if (v >= m_tab.length ())
565 m_tab.safe_grow_cleared (num_ssa_names + 1);
566 m_tab[v] = NULL;
567 }
568
569 // Clear the global cache.
570
571 void
clear()572 ssa_global_cache::clear ()
573 {
574 memset (m_tab.address(), 0, m_tab.length () * sizeof (irange *));
575 }
576
577 // Dump the contents of the global cache to F.
578
579 void
dump(FILE * f)580 ssa_global_cache::dump (FILE *f)
581 {
582 unsigned x;
583 int_range_max r;
584 fprintf (f, "Non-varying global ranges:\n");
585 fprintf (f, "=========================:\n");
586 for ( x = 1; x < num_ssa_names; x++)
587 if (gimple_range_ssa_p (ssa_name (x)) &&
588 get_global_range (r, ssa_name (x)) && !r.varying_p ())
589 {
590 print_generic_expr (f, ssa_name (x), TDF_NONE);
591 fprintf (f, " : ");
592 r.dump (f);
593 fprintf (f, "\n");
594 }
595 fputc ('\n', f);
596 }
597
598 // --------------------------------------------------------------------------
599
600
601 // This struct provides a timestamp for a global range calculation.
602 // it contains the time counter, as well as a limited number of ssa-names
603 // that it is dependent upon. If the timestamp for any of the dependent names
604 // Are newer, then this range could need updating.
605
606 struct range_timestamp
607 {
608 unsigned time;
609 unsigned ssa1;
610 unsigned ssa2;
611 };
612
613 // This class will manage the timestamps for each ssa_name.
614 // When a value is calcualted, its timestamp is set to the current time.
615 // The ssanames it is dependent on have already been calculated, so they will
616 // have older times. If one fo those values is ever calculated again, it
617 // will get a newer timestamp, and the "current_p" check will fail.
618
619 class temporal_cache
620 {
621 public:
622 temporal_cache ();
623 ~temporal_cache ();
624 bool current_p (tree name) const;
625 void set_timestamp (tree name);
626 void set_dependency (tree name, tree dep);
627 void set_always_current (tree name);
628 private:
629 unsigned temporal_value (unsigned ssa) const;
630 const range_timestamp *get_timestamp (unsigned ssa) const;
631 range_timestamp *get_timestamp (unsigned ssa);
632
633 unsigned m_current_time;
634 vec <range_timestamp> m_timestamp;
635 };
636
637
638 inline
temporal_cache()639 temporal_cache::temporal_cache ()
640 {
641 m_current_time = 1;
642 m_timestamp.create (0);
643 m_timestamp.safe_grow_cleared (num_ssa_names);
644 }
645
646 inline
~temporal_cache()647 temporal_cache::~temporal_cache ()
648 {
649 m_timestamp.release ();
650 }
651
652 // Return a pointer to the timetamp for ssa-name at index SSA, if there is
653 // one, otherwise return NULL.
654
655 inline const range_timestamp *
get_timestamp(unsigned ssa) const656 temporal_cache::get_timestamp (unsigned ssa) const
657 {
658 if (ssa >= m_timestamp.length ())
659 return NULL;
660 return &(m_timestamp[ssa]);
661 }
662
663 // Return a reference to the timetamp for ssa-name at index SSA. If the index
664 // is past the end of the vector, extend the vector.
665
666 inline range_timestamp *
get_timestamp(unsigned ssa)667 temporal_cache::get_timestamp (unsigned ssa)
668 {
669 if (ssa >= m_timestamp.length ())
670 m_timestamp.safe_grow_cleared (num_ssa_names + 20);
671 return &(m_timestamp[ssa]);
672 }
673
674 // This routine will fill NAME's next operand slot with DEP if DEP is a valid
675 // SSA_NAME and there is a free slot.
676
677 inline void
set_dependency(tree name,tree dep)678 temporal_cache::set_dependency (tree name, tree dep)
679 {
680 if (dep && TREE_CODE (dep) == SSA_NAME)
681 {
682 gcc_checking_assert (get_timestamp (SSA_NAME_VERSION (name)));
683 range_timestamp& ts = *(get_timestamp (SSA_NAME_VERSION (name)));
684 if (!ts.ssa1)
685 ts.ssa1 = SSA_NAME_VERSION (dep);
686 else if (!ts.ssa2 && ts.ssa1 != SSA_NAME_VERSION (name))
687 ts.ssa2 = SSA_NAME_VERSION (dep);
688 }
689 }
690
691 // Return the timestamp value for SSA, or 0 if there isnt one.
692 inline unsigned
temporal_value(unsigned ssa) const693 temporal_cache::temporal_value (unsigned ssa) const
694 {
695 const range_timestamp *ts = get_timestamp (ssa);
696 return ts ? ts->time : 0;
697 }
698
699 // Return TRUE if the timestampe for NAME is newer than any of its dependents.
700
701 bool
current_p(tree name) const702 temporal_cache::current_p (tree name) const
703 {
704 const range_timestamp *ts = get_timestamp (SSA_NAME_VERSION (name));
705 if (!ts || ts->time == 0)
706 return true;
707 // Any non-registered dependencies will have a value of 0 and thus be older.
708 // Return true if time is newer than either dependent.
709 return ts->time > temporal_value (ts->ssa1)
710 && ts->time > temporal_value (ts->ssa2);
711 }
712
713 // This increments the global timer and sets the timestamp for NAME.
714
715 inline void
set_timestamp(tree name)716 temporal_cache::set_timestamp (tree name)
717 {
718 gcc_checking_assert (get_timestamp (SSA_NAME_VERSION (name)));
719 get_timestamp (SSA_NAME_VERSION (name))->time = ++m_current_time;
720 }
721
722 // Set the timestamp to 0, marking it as "always up to date".
723
724 inline void
set_always_current(tree name)725 temporal_cache::set_always_current (tree name)
726 {
727 gcc_checking_assert (get_timestamp (SSA_NAME_VERSION (name)));
728 get_timestamp (SSA_NAME_VERSION (name))->time = 0;
729 }
730
731
732 // --------------------------------------------------------------------------
733
ranger_cache(gimple_ranger & q)734 ranger_cache::ranger_cache (gimple_ranger &q) : query (q)
735 {
736 m_workback.create (0);
737 m_workback.safe_grow_cleared (last_basic_block_for_fn (cfun));
738 m_update_list.create (0);
739 m_update_list.safe_grow_cleared (last_basic_block_for_fn (cfun));
740 m_update_list.truncate (0);
741 m_poor_value_list.create (0);
742 m_poor_value_list.safe_grow_cleared (20);
743 m_poor_value_list.truncate (0);
744 m_temporal = new temporal_cache;
745 m_propfail = BITMAP_ALLOC (NULL);
746 }
747
~ranger_cache()748 ranger_cache::~ranger_cache ()
749 {
750 BITMAP_FREE (m_propfail);
751 delete m_temporal;
752 m_poor_value_list.release ();
753 m_workback.release ();
754 m_update_list.release ();
755 }
756
757 // Dump the global caches to file F. if GORI_DUMP is true, dump the
758 // gori map as well.
759
760 void
dump(FILE * f,bool gori_dump)761 ranger_cache::dump (FILE *f, bool gori_dump)
762 {
763 m_globals.dump (f);
764 if (gori_dump)
765 {
766 fprintf (f, "\nDUMPING GORI MAP\n");
767 gori_compute::dump (f);
768 }
769 fprintf (f, "\n");
770 }
771
772 // Dump the caches for basic block BB to file F.
773
774 void
dump(FILE * f,basic_block bb)775 ranger_cache::dump (FILE *f, basic_block bb)
776 {
777 m_on_entry.dump (f, bb);
778 }
779
780 // Get the global range for NAME, and return in R. Return false if the
781 // global range is not set.
782
783 bool
get_global_range(irange & r,tree name) const784 ranger_cache::get_global_range (irange &r, tree name) const
785 {
786 return m_globals.get_global_range (r, name);
787 }
788
789 // Get the global range for NAME, and return in R if the value is not stale.
790 // If the range is set, but is stale, mark it current and return false.
791 // If it is not set pick up the legacy global value, mark it current, and
792 // return false.
793 // Note there is always a value returned in R. The return value indicates
794 // whether that value is an up-to-date calculated value or not..
795
796 bool
get_non_stale_global_range(irange & r,tree name)797 ranger_cache::get_non_stale_global_range (irange &r, tree name)
798 {
799 if (m_globals.get_global_range (r, name))
800 {
801 if (m_temporal->current_p (name))
802 return true;
803 }
804 else
805 {
806 // Global has never been accessed, so pickup the legacy global value.
807 r = gimple_range_global (name);
808 m_globals.set_global_range (name, r);
809 }
810 // After a stale check failure, mark the value as always current until a
811 // new one is set.
812 m_temporal->set_always_current (name);
813 return false;
814 }
815 // Set the global range of NAME to R.
816
817 void
set_global_range(tree name,const irange & r)818 ranger_cache::set_global_range (tree name, const irange &r)
819 {
820 if (m_globals.set_global_range (name, r))
821 {
822 // If there was already a range set, propagate the new value.
823 basic_block bb = gimple_bb (SSA_NAME_DEF_STMT (name));
824 if (!bb)
825 bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
826
827 if (DEBUG_RANGE_CACHE)
828 fprintf (dump_file, " GLOBAL :");
829
830 propagate_updated_value (name, bb);
831 }
832 // Mark the value as up-to-date.
833 m_temporal->set_timestamp (name);
834 }
835
836 // Register a dependency on DEP to name. If the timestamp for DEP is ever
837 // greateer than the timestamp for NAME, then it is newer and NAMEs value
838 // becomes stale.
839
840 void
register_dependency(tree name,tree dep)841 ranger_cache::register_dependency (tree name, tree dep)
842 {
843 m_temporal->set_dependency (name, dep);
844 }
845
846 // Push a request for a new lookup in block BB of name. Return true if
847 // the request is actually made (ie, isn't a duplicate).
848
849 bool
push_poor_value(basic_block bb,tree name)850 ranger_cache::push_poor_value (basic_block bb, tree name)
851 {
852 // Disable poor value processing for GCC 11. It has been disabled in GCC 12
853 // as adding too much churn/compile time for too little benefit.
854 return false;
855 }
856
857 // Provide lookup for the gori-computes class to access the best known range
858 // of an ssa_name in any given basic block. Note, this does no additonal
859 // lookups, just accesses the data that is already known.
860
861 void
ssa_range_in_bb(irange & r,tree name,basic_block bb)862 ranger_cache::ssa_range_in_bb (irange &r, tree name, basic_block bb)
863 {
864 gimple *s = SSA_NAME_DEF_STMT (name);
865 basic_block def_bb = ((s && gimple_bb (s)) ? gimple_bb (s) :
866 ENTRY_BLOCK_PTR_FOR_FN (cfun));
867 if (bb == def_bb)
868 {
869 // NAME is defined in this block, so request its current value
870 if (!m_globals.get_global_range (r, name))
871 {
872 // If it doesn't have a value calculated, it means it's a
873 // "poor" value being used in some calculation. Queue it up
874 // as a poor value to be improved later.
875 r = gimple_range_global (name);
876 if (push_poor_value (bb, name))
877 {
878 if (DEBUG_RANGE_CACHE)
879 {
880 fprintf (dump_file,
881 "*CACHE* no global def in bb %d for ", bb->index);
882 print_generic_expr (dump_file, name, TDF_SLIM);
883 fprintf (dump_file, " depth : %d\n",
884 m_poor_value_list.length ());
885 }
886 }
887 }
888 }
889 // Look for the on-entry value of name in BB from the cache.
890 else if (!m_on_entry.get_bb_range (r, name, bb))
891 {
892 // If it has no entry but should, then mark this as a poor value.
893 // Its not a poor value if it does not have *any* edge ranges,
894 // Then global range is as good as it gets.
895 if (has_edge_range_p (name) && push_poor_value (bb, name))
896 {
897 if (DEBUG_RANGE_CACHE)
898 {
899 fprintf (dump_file,
900 "*CACHE* no on entry range in bb %d for ", bb->index);
901 print_generic_expr (dump_file, name, TDF_SLIM);
902 fprintf (dump_file, " depth : %d\n", m_poor_value_list.length ());
903 }
904 }
905 // Try to pick up any known global value as a best guess for now.
906 if (!m_globals.get_global_range (r, name))
907 r = gimple_range_global (name);
908 }
909
910 // Check if pointers have any non-null dereferences. Non-call
911 // exceptions mean we could throw in the middle of the block, so just
912 // punt for now on those.
913 if (r.varying_p () && m_non_null.non_null_deref_p (name, bb) &&
914 !cfun->can_throw_non_call_exceptions)
915 r = range_nonzero (TREE_TYPE (name));
916 }
917
918 // Return a static range for NAME on entry to basic block BB in R. If
919 // calc is true, fill any cache entries required between BB and the
920 // def block for NAME. Otherwise, return false if the cache is empty.
921
922 bool
block_range(irange & r,basic_block bb,tree name,bool calc)923 ranger_cache::block_range (irange &r, basic_block bb, tree name, bool calc)
924 {
925 gcc_checking_assert (gimple_range_ssa_p (name));
926
927 // If there are no range calculations anywhere in the IL, global range
928 // applies everywhere, so don't bother caching it.
929 if (!has_edge_range_p (name))
930 return false;
931
932 if (calc)
933 {
934 gimple *def_stmt = SSA_NAME_DEF_STMT (name);
935 basic_block def_bb = NULL;
936 if (def_stmt)
937 def_bb = gimple_bb (def_stmt);;
938 if (!def_bb)
939 {
940 // If we get to the entry block, this better be a default def
941 // or range_on_entry was called for a block not dominated by
942 // the def.
943 gcc_checking_assert (SSA_NAME_IS_DEFAULT_DEF (name));
944 def_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
945 }
946
947 // There is no range on entry for the definition block.
948 if (def_bb == bb)
949 return false;
950
951 // Otherwise, go figure out what is known in predecessor blocks.
952 fill_block_cache (name, bb, def_bb);
953 gcc_checking_assert (m_on_entry.bb_range_p (name, bb));
954 }
955 return m_on_entry.get_bb_range (r, name, bb);
956 }
957
958 // Add BB to the list of blocks to update, unless it's already in the list.
959
960 void
add_to_update(basic_block bb)961 ranger_cache::add_to_update (basic_block bb)
962 {
963 // If propagation has failed for BB, or its already in the list, don't
964 // add it again.
965 if (!bitmap_bit_p (m_propfail, bb->index) && !m_update_list.contains (bb))
966 m_update_list.quick_push (bb);
967 }
968
969 // If there is anything in the propagation update_list, continue
970 // processing NAME until the list of blocks is empty.
971
972 void
propagate_cache(tree name)973 ranger_cache::propagate_cache (tree name)
974 {
975 basic_block bb;
976 edge_iterator ei;
977 edge e;
978 int_range_max new_range;
979 int_range_max current_range;
980 int_range_max e_range;
981
982 gcc_checking_assert (bitmap_empty_p (m_propfail));
983 // Process each block by seeing if its calculated range on entry is
984 // the same as its cached value. If there is a difference, update
985 // the cache to reflect the new value, and check to see if any
986 // successors have cache entries which may need to be checked for
987 // updates.
988
989 while (m_update_list.length () > 0)
990 {
991 bb = m_update_list.pop ();
992 gcc_checking_assert (m_on_entry.bb_range_p (name, bb));
993 m_on_entry.get_bb_range (current_range, name, bb);
994
995 // Calculate the "new" range on entry by unioning the pred edges.
996 new_range.set_undefined ();
997 FOR_EACH_EDGE (e, ei, bb->preds)
998 {
999 if (DEBUG_RANGE_CACHE)
1000 fprintf (dump_file, " edge %d->%d :", e->src->index, bb->index);
1001 // Get whatever range we can for this edge.
1002 if (!outgoing_edge_range_p (e_range, e, name))
1003 {
1004 ssa_range_in_bb (e_range, name, e->src);
1005 if (DEBUG_RANGE_CACHE)
1006 {
1007 fprintf (dump_file, "No outgoing edge range, picked up ");
1008 e_range.dump(dump_file);
1009 fprintf (dump_file, "\n");
1010 }
1011 }
1012 else
1013 {
1014 if (DEBUG_RANGE_CACHE)
1015 {
1016 fprintf (dump_file, "outgoing range :");
1017 e_range.dump(dump_file);
1018 fprintf (dump_file, "\n");
1019 }
1020 }
1021 new_range.union_ (e_range);
1022 if (new_range.varying_p ())
1023 break;
1024 }
1025
1026 if (DEBUG_RANGE_CACHE)
1027 {
1028 fprintf (dump_file, "FWD visiting block %d for ", bb->index);
1029 print_generic_expr (dump_file, name, TDF_SLIM);
1030 fprintf (dump_file, " starting range : ");
1031 current_range.dump (dump_file);
1032 fprintf (dump_file, "\n");
1033 }
1034
1035 // If the range on entry has changed, update it.
1036 if (new_range != current_range)
1037 {
1038 bool ok_p = m_on_entry.set_bb_range (name, bb, new_range);
1039 // If the cache couldn't set the value, mark it as failed.
1040 if (!ok_p)
1041 bitmap_set_bit (m_propfail, bb->index);
1042 if (DEBUG_RANGE_CACHE)
1043 {
1044 if (!ok_p)
1045 fprintf (dump_file, " Cache failure to store value.");
1046 else
1047 {
1048 fprintf (dump_file, " Updating range to ");
1049 new_range.dump (dump_file);
1050 }
1051 fprintf (dump_file, "\n Updating blocks :");
1052 }
1053 // Mark each successor that has a range to re-check its range
1054 FOR_EACH_EDGE (e, ei, bb->succs)
1055 if (m_on_entry.bb_range_p (name, e->dest))
1056 {
1057 if (DEBUG_RANGE_CACHE)
1058 fprintf (dump_file, " bb%d",e->dest->index);
1059 add_to_update (e->dest);
1060 }
1061 if (DEBUG_RANGE_CACHE)
1062 fprintf (dump_file, "\n");
1063 }
1064 }
1065 if (DEBUG_RANGE_CACHE)
1066 {
1067 fprintf (dump_file, "DONE visiting blocks for ");
1068 print_generic_expr (dump_file, name, TDF_SLIM);
1069 fprintf (dump_file, "\n");
1070 }
1071 bitmap_clear (m_propfail);
1072 }
1073
1074 // Check to see if an update to the value for NAME in BB has any effect
1075 // on values already in the on-entry cache for successor blocks.
1076 // If it does, update them. Don't visit any blocks which dont have a cache
1077 // entry.
1078
1079 void
propagate_updated_value(tree name,basic_block bb)1080 ranger_cache::propagate_updated_value (tree name, basic_block bb)
1081 {
1082 edge e;
1083 edge_iterator ei;
1084
1085 // The update work list should be empty at this point.
1086 gcc_checking_assert (m_update_list.length () == 0);
1087 gcc_checking_assert (bb);
1088
1089 if (DEBUG_RANGE_CACHE)
1090 {
1091 fprintf (dump_file, " UPDATE cache for ");
1092 print_generic_expr (dump_file, name, TDF_SLIM);
1093 fprintf (dump_file, " in BB %d : successors : ", bb->index);
1094 }
1095 FOR_EACH_EDGE (e, ei, bb->succs)
1096 {
1097 // Only update active cache entries.
1098 if (m_on_entry.bb_range_p (name, e->dest))
1099 {
1100 add_to_update (e->dest);
1101 if (DEBUG_RANGE_CACHE)
1102 fprintf (dump_file, " UPDATE: bb%d", e->dest->index);
1103 }
1104 }
1105 if (m_update_list.length () != 0)
1106 {
1107 if (DEBUG_RANGE_CACHE)
1108 fprintf (dump_file, "\n");
1109 propagate_cache (name);
1110 }
1111 else
1112 {
1113 if (DEBUG_RANGE_CACHE)
1114 fprintf (dump_file, " : No updates!\n");
1115 }
1116 }
1117
1118 // Make sure that the range-on-entry cache for NAME is set for block BB.
1119 // Work back through the CFG to DEF_BB ensuring the range is calculated
1120 // on the block/edges leading back to that point.
1121
1122 void
fill_block_cache(tree name,basic_block bb,basic_block def_bb)1123 ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
1124 {
1125 edge_iterator ei;
1126 edge e;
1127 int_range_max block_result;
1128 int_range_max undefined;
1129 unsigned poor_list_start = m_poor_value_list.length ();
1130
1131 // At this point we shouldn't be looking at the def, entry or exit block.
1132 gcc_checking_assert (bb != def_bb && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun) &&
1133 bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
1134
1135 // If the block cache is set, then we've already visited this block.
1136 if (m_on_entry.bb_range_p (name, bb))
1137 return;
1138
1139 // Visit each block back to the DEF. Initialize each one to UNDEFINED.
1140 // m_visited at the end will contain all the blocks that we needed to set
1141 // the range_on_entry cache for.
1142 m_workback.truncate (0);
1143 m_workback.quick_push (bb);
1144 undefined.set_undefined ();
1145 m_on_entry.set_bb_range (name, bb, undefined);
1146 gcc_checking_assert (m_update_list.length () == 0);
1147
1148 if (DEBUG_RANGE_CACHE)
1149 {
1150 fprintf (dump_file, "\n");
1151 print_generic_expr (dump_file, name, TDF_SLIM);
1152 fprintf (dump_file, " : ");
1153 }
1154
1155 while (m_workback.length () > 0)
1156 {
1157 basic_block node = m_workback.pop ();
1158 if (DEBUG_RANGE_CACHE)
1159 {
1160 fprintf (dump_file, "BACK visiting block %d for ", node->index);
1161 print_generic_expr (dump_file, name, TDF_SLIM);
1162 fprintf (dump_file, "\n");
1163 }
1164
1165 FOR_EACH_EDGE (e, ei, node->preds)
1166 {
1167 basic_block pred = e->src;
1168 int_range_max r;
1169
1170 if (DEBUG_RANGE_CACHE)
1171 fprintf (dump_file, " %d->%d ",e->src->index, e->dest->index);
1172
1173 // If the pred block is the def block add this BB to update list.
1174 if (pred == def_bb)
1175 {
1176 add_to_update (node);
1177 continue;
1178 }
1179
1180 // If the pred is entry but NOT def, then it is used before
1181 // defined, it'll get set to [] and no need to update it.
1182 if (pred == ENTRY_BLOCK_PTR_FOR_FN (cfun))
1183 {
1184 if (DEBUG_RANGE_CACHE)
1185 fprintf (dump_file, "entry: bail.");
1186 continue;
1187 }
1188
1189 // Regardless of whether we have visited pred or not, if the
1190 // pred has a non-null reference, revisit this block.
1191 if (m_non_null.non_null_deref_p (name, pred))
1192 {
1193 if (DEBUG_RANGE_CACHE)
1194 fprintf (dump_file, "nonnull: update ");
1195 add_to_update (node);
1196 }
1197
1198 // If the pred block already has a range, or if it can contribute
1199 // something new. Ie, the edge generates a range of some sort.
1200 if (m_on_entry.get_bb_range (r, name, pred))
1201 {
1202 if (DEBUG_RANGE_CACHE)
1203 fprintf (dump_file, "has cache, ");
1204 if (!r.undefined_p () || has_edge_range_p (name, e))
1205 {
1206 add_to_update (node);
1207 if (DEBUG_RANGE_CACHE)
1208 fprintf (dump_file, "update. ");
1209 }
1210 continue;
1211 }
1212
1213 if (DEBUG_RANGE_CACHE)
1214 fprintf (dump_file, "pushing undefined pred block. ");
1215 // If the pred hasn't been visited (has no range), add it to
1216 // the list.
1217 gcc_checking_assert (!m_on_entry.bb_range_p (name, pred));
1218 m_on_entry.set_bb_range (name, pred, undefined);
1219 m_workback.quick_push (pred);
1220 }
1221 }
1222
1223 if (DEBUG_RANGE_CACHE)
1224 fprintf (dump_file, "\n");
1225
1226 // Now fill in the marked blocks with values.
1227 propagate_cache (name);
1228 if (DEBUG_RANGE_CACHE)
1229 fprintf (dump_file, " Propagation update done.\n");
1230
1231 // Now that the cache has been updated, check to see if there were any
1232 // SSA_NAMES used in filling the cache which were "poor values".
1233 // Evaluate them, and inject any new values into the propagation
1234 // list, and see if it improves any on-entry values.
1235 if (poor_list_start != m_poor_value_list.length ())
1236 {
1237 gcc_checking_assert (poor_list_start < m_poor_value_list.length ());
1238 while (poor_list_start < m_poor_value_list.length ())
1239 {
1240 // Find a range for this unresolved value.
1241 // Note, this may spawn new cache filling cycles, but by the time it
1242 // is finished, the work vectors will all be back to the same state
1243 // as before the call. The update record vector will always be
1244 // returned to the current state upon return.
1245 struct update_record rec = m_poor_value_list.pop ();
1246 basic_block calc_bb = rec.bb;
1247 int_range_max tmp;
1248
1249 if (DEBUG_RANGE_CACHE)
1250 {
1251 fprintf (dump_file, "(%d:%d)Calculating ",
1252 m_poor_value_list.length () + 1, poor_list_start);
1253 print_generic_expr (dump_file, name, TDF_SLIM);
1254 fprintf (dump_file, " used POOR VALUE for ");
1255 print_generic_expr (dump_file, rec.calc, TDF_SLIM);
1256 fprintf (dump_file, " in bb%d, trying to improve:\n",
1257 calc_bb->index);
1258 }
1259
1260 // Calculate a range at the exit from the block so the caches feeding
1261 // this block will be filled, and we'll get a "better" value.
1262 query.range_on_exit (tmp, calc_bb, rec.calc);
1263
1264 // Then ask for NAME to be re-evaluated on outgoing edges and
1265 // use any new values.
1266 propagate_updated_value (name, calc_bb);
1267 }
1268 }
1269 }
1270
1271