summaryrefslogtreecommitdiff
path: root/gcc/ssa-range.h
blob: a64b8710ff5233028c3e3cb9f6b750da25d9f930 (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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/* Header file for SSA range interface.
   Copyright (C) 2017-2018 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_H
#define GCC_SSA_RANGE_H

#include "grange.h"
#include "ssa-range-gori.h"
#include "ssa-range-cache.h"

// This is the basic range generator interface. 
//
// This base class provides all the API entry points, but only provides 
// functionality at the statement level.  Ie, it can calculate ranges on 
// statements, but does no additonal lookup.
//
// All the range_of_* methods will return a range if the types is supported
// by the range engine. It may be the full range for the type, AKA varying_p
// or it may be a refined range.
// If the range type is not supported, then false is returned.
// The basic ssa_ranger class will also return false for range_on_entry and
// range_on_exit as those make no sense at the statement level.
//
// outgoing_edge_range_p will only return a range if the edge specified 
// defines a range for the specified name.  Otherwise false is returned.
//
//
class stmt_ranger
{
  public:
  
  bool range_of_expr (irange &r, tree expr, gimple *s = NULL);
  virtual irange range_of_ssa_name (tree name, gimple *s = NULL);
  virtual bool range_of_stmt (irange &r, gimple *s, tree name = NULL_TREE);
  virtual bool range_of_stmt_with_range (irange &r, gimple *s, tree name,
					 const irange &name_range);
protected:
  bool range_of_grange  (irange &r, grange *s, tree name = NULL_TREE,
			 const irange *name_range = NULL);

  virtual bool range_of_phi (irange &r, gphi *phi, tree name = NULL_TREE,
			     const irange *name_range = NULL);

  bool range_of_call (irange &r, gcall *call, tree name = NULL_TREE,
		      const irange *name_range = NULL);

  bool range_of_cond_expr (irange &r, gassign* call, tree name = NULL_TREE,
			   const irange *name_range = NULL);
};

class ssa_ranger : public stmt_ranger
{
  public:
  virtual void range_on_edge (irange &r, edge e, tree name);
  virtual void range_on_entry (irange &r, basic_block bb, tree name);
  virtual void range_on_exit (irange &r, basic_block bb, tree name);

  virtual bool outgoing_edge_range_p (irange &r, edge e, tree name,
				      irange *name_range = NULL);
  
protected:
  virtual bool range_of_phi (irange &r, gphi *phi, tree name = NULL_TREE,
			     const irange *name_range = NULL);
};

// This class utilizes the gori summary to query the range
// of SSA_NAMEs across multiple basic blocks and edges.  It builds a cache
// of range on entry to blocks.  All work is done on-demand so it is relatively
// lightweight until used.
//
// GORI stands for Generates Outgoing Range Info
// Itutilizes the engine from ssa-range-gori.h to build
// defintion chains on demand which enables the calculation of ranges for 
// various ssa names that are related to those that actually generate ranges.
//
// It is lightweight to declare in this case, but for each basic block that is
// queried, it will scan some or all of the statements in the block to
// determine what ssa-names can have range information generated for them and
// cache this information.  
//
// terminal_name () provides the "input" name to the chain of statements for
// name that can change the calculation of its range.  This is usually outside 
// the basic block the name is defind in..  ie,
// bb4:
//   a_2 = b_6 + 5
//   c_3 = (a_2 < 25)
// in this small example, b_6 is the
// "terminal_name" returned for both a_2 and c_3 since a change in the
// range of b_6 to calculate their results may produce a different range.


class global_ranger : public ssa_ranger
{
public:
  global_ranger ();
  ~global_ranger ();

  virtual irange range_of_ssa_name (tree name, gimple *s = NULL);
  virtual bool range_of_stmt (irange &r, gimple *s, tree name = NULL_TREE);
  virtual void range_on_entry (irange &r, basic_block bb, tree name);

  virtual bool outgoing_edge_range_p (irange &r, edge e, tree name,
				      irange *name_range = NULL);
  tree terminal_name (tree name);

  void export_global_ranges ();

  void dump (FILE *f);
  void calculate_and_dump (FILE *f);   /* Calculate all stmts and dump */

protected:
  gori_cache m_gori; 	  /* Generates Outgoing Range Info.  */
};

// FIXME: Forward declaration for loop_ranger.
class vr_values;

// A global ranger that uses SCEV/loop (if available) to refine PHI results.

class loop_ranger : public global_ranger
{
public:
  loop_ranger ();
  ~loop_ranger ();
private:
  void adjust_phi_with_loop_info (irange &r, gphi *phi);
  virtual bool range_of_phi (irange &r, gphi *phi, tree name,
			     const irange *name_range);

  vr_values *m_vr_values;
};

class trace_ranger : public loop_ranger
{
public:
  trace_ranger();

  virtual irange range_of_ssa_name (tree name, gimple *s = NULL);
  virtual bool range_of_stmt (irange &r, gimple *s, tree name = NULL_TREE);
  virtual void range_on_edge (irange &r, edge e, tree name);
  virtual void range_on_entry (irange &r, basic_block bb, tree name);
  virtual void range_on_exit (irange &r, basic_block bb, tree name);

  // Calculate a range on edge E only if it is defined by E.
  virtual bool outgoing_edge_range_p (irange &r, edge e, tree name,
				      irange *name_range = NULL);
private:
  typedef global_ranger super;  // Inherited from class for easy changing.
  static const unsigned bump = 2;
  unsigned indent;
  unsigned trace_count;		// Current trace index count.

  bool dumping (unsigned counter, bool trailing = false);
  bool trailer (unsigned counter, const char *caller, bool result, tree name,
		const irange &r);
};

  

// Like global_ranger::range_of_expr (), but make an on-the-fly ranger.
// Return TRUE if SSA as seen from within STMT has a known range the is not
// varying.  Set this range in R.
//
// NOTE: There is overhead involved with this function, so it
// should only be used for very lightweight or unrelated range
// queries.  This function is mostly meant for range queries that
// don't need caching in subsequent calls.  */

static inline bool
on_demand_get_range_on_stmt (irange &r, tree ssa, gimple *stmt)
{
  if (!cfun->cfg)
    return false;
  loop_ranger ranger;
  bool ret;
  ret = ranger.range_of_expr (r, ssa, stmt);
  if (ret && r.varying_p ())
    return false;
  return ret;
}
#endif // GCC_SSA_RANGE_H