summaryrefslogtreecommitdiff
path: root/gcc/gimple-range-cache.h
blob: 946fbc514650ad71dfd0af59f288914ea1cfc124 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* Header file for gimple ranger SSA cache.
   Copyright (C) 2017-2023 Free Software Foundation, Inc.
   Contributed by Andrew MacLeod <amacleod@redhat.com>.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#ifndef GCC_SSA_RANGE_CACHE_H
#define GCC_SSA_RANGE_CACHE_H

#include "gimple-range-gori.h" 
#include "gimple-range-infer.h"

// This class manages a vector of pointers to ssa_block ranges.  It
// provides the basis for the "range on entry" cache for all
// SSA names.

class block_range_cache
{
public:
  block_range_cache ();
  ~block_range_cache ();

  bool set_bb_range (tree name, const_basic_block bb, const vrange &v);
  bool get_bb_range (vrange &v, tree name, const_basic_block bb);
  bool bb_range_p (tree name, const_basic_block bb);

  void dump (FILE *f);
  void dump (FILE *f, basic_block bb, bool print_varying = true);
private:
  vec<class ssa_block_ranges *> m_ssa_ranges;
  ssa_block_ranges &get_block_ranges (tree name);
  ssa_block_ranges *query_block_ranges (tree name);
  class vrange_allocator *m_range_allocator;
  bitmap_obstack m_bitmaps;
};

// This global cache is used with the range engine as markers for what
// has been visited during this incarnation.  Once the ranger evaluates
// a name, it is typically not re-evaluated again.

class ssa_cache
{
public:
  ssa_cache ();
  ~ssa_cache ();
  bool has_range (tree name) const;
  bool get_range (vrange &r, tree name) const;
  bool set_range (tree name, const vrange &r);
  void clear_range (tree name);
  void clear ();
  void dump (FILE *f = stderr);
protected:
  virtual bool dump_range_query (vrange &r, tree name) const;
  vec<vrange_storage *> m_tab;
  vrange_allocator *m_range_allocator;
};

// This is the same as global cache, except it maintains an active bitmap
// rather than depending on a zero'd out vector of pointers.  This is better
// for sparsely/lightly used caches.
// It could be made a fully derived class, but at this point there doesnt seem
// to be a need to take the performance hit for it.

class ssa_lazy_cache : protected ssa_cache
{
public:
  inline ssa_lazy_cache () { active_p = BITMAP_ALLOC (NULL); }
  inline ~ssa_lazy_cache () { BITMAP_FREE (active_p); }
  bool set_range (tree name, const vrange &r);
  inline bool get_range (vrange &r, tree name) const;
  inline void clear_range (tree name)
    { bitmap_clear_bit (active_p, SSA_NAME_VERSION (name)); } ;
  inline void clear () { bitmap_clear (active_p); }
  inline void dump (FILE *f = stderr) { ssa_cache::dump (f); }
protected:
  virtual bool dump_range_query (vrange &r, tree name) const;
  bitmap active_p;
};

// Return TRUE if NAME has a range, and return it in R.

bool
ssa_lazy_cache::get_range (vrange &r, tree name) const
{
  if (!bitmap_bit_p (active_p, SSA_NAME_VERSION (name)))
    return false;
  return ssa_cache::get_range (r, name);
}

// This class provides all the caches a global ranger may need, and makes 
// them available for gori-computes to query so outgoing edges can be
// properly calculated.

class ranger_cache : public range_query
{
public:
  ranger_cache (int not_executable_flag, bool use_imm_uses);
  ~ranger_cache ();

  bool range_of_expr (vrange &r, tree name, gimple *stmt) final override;
  bool range_on_edge (vrange &r, edge e, tree expr) final override;
  bool block_range (vrange &r, basic_block bb, tree name, bool calc = true);

  bool get_global_range (vrange &r, tree name) const;
  bool get_global_range (vrange &r, tree name, bool &current_p);
  void set_global_range (tree name, const vrange &r);

  void propagate_updated_value (tree name, basic_block bb);

  void register_inferred_value (const vrange &r, tree name, basic_block bb);
  void apply_inferred_ranges (gimple *s);
  gori_compute m_gori;
  infer_range_manager m_exit;

  void dump_bb (FILE *f, basic_block bb);
  virtual void dump (FILE *f) override;
private:
  ssa_cache m_globals;
  block_range_cache m_on_entry;
  class temporal_cache *m_temporal;
  void fill_block_cache (tree name, basic_block bb, basic_block def_bb);
  void propagate_cache (tree name);

  enum rfd_mode
    {
      RFD_NONE,		// Only look at current block cache.
      RFD_READ_ONLY,	// Scan DOM tree, do not write to cache.
      RFD_FILL		// Scan DOM tree, updating important nodes.
    };
  bool range_from_dom (vrange &r, tree name, basic_block bb, enum rfd_mode);
  void resolve_dom (vrange &r, tree name, basic_block bb);
  void range_of_def (vrange &r, tree name, basic_block bb = NULL);
  void entry_range (vrange &r, tree expr, basic_block bb, enum rfd_mode);
  void exit_range (vrange &r, tree expr, basic_block bb, enum rfd_mode);
  bool edge_range (vrange &r, edge e, tree name, enum rfd_mode);

  vec<basic_block> m_workback;
  class update_list *m_update;
};

#endif // GCC_SSA_RANGE_CACHE_H