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