analyzer: fix feasibility false +ve on jumps through function ptrs [PR107582]
[platform/upstream/gcc.git] / gcc / range-op.h
1 /* Header file for range operator class.
2    Copyright (C) 2017-2022 Free Software Foundation, Inc.
3    Contributed by Andrew MacLeod <amacleod@redhat.com>
4    and Aldy Hernandez <aldyh@redhat.com>.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16  for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3.  If not see
20 <http://www.gnu.org/licenses/>.  */
21
22 #ifndef GCC_RANGE_OP_H
23 #define GCC_RANGE_OP_H
24
25 // This class is implemented for each kind of operator supported by
26 // the range generator.  It serves various purposes.
27 //
28 // 1 - Generates range information for the specific operation between
29 //     two ranges.  This provides the ability to fold ranges for an
30 //     expression.
31 //
32 // 2 - Performs range algebra on the expression such that a range can be
33 //     adjusted in terms of one of the operands:
34 //
35 //       def = op1 + op2
36 //
37 //     Given a range for def, we can adjust the range so that it is in
38 //     terms of either operand.
39 //
40 //     op1_range (def_range, op2) will adjust the range in place so it
41 //     is in terms of op1.  Since op1 = def - op2, it will subtract
42 //     op2 from each element of the range.
43 //
44 // 3 - Creates a range for an operand based on whether the result is 0 or
45 //     non-zero.  This is mostly for logical true false, but can serve other
46 //     purposes.
47 //       ie   0 = op1 - op2 implies op2 has the same range as op1.
48
49 class range_operator
50 {
51   friend class range_op_table;
52 public:
53   range_operator () : m_code (ERROR_MARK) { }
54   // Perform an operation between 2 ranges and return it.
55   virtual bool fold_range (irange &r, tree type,
56                            const irange &lh,
57                            const irange &rh,
58                            relation_trio = TRIO_VARYING) const;
59
60   // Return the range for op[12] in the general case.  LHS is the range for
61   // the LHS of the expression, OP[12]is the range for the other
62   //
63   // The operand and the result is returned in R.
64   //
65   // TYPE is the expected type of the range.
66   //
67   // Return TRUE if the operation is performed and a valid range is available.
68   //
69   // i.e.  [LHS] = ??? + OP2
70   // is re-formed as R = [LHS] - OP2.
71   virtual bool op1_range (irange &r, tree type,
72                           const irange &lhs,
73                           const irange &op2,
74                           relation_trio = TRIO_VARYING) const;
75   virtual bool op2_range (irange &r, tree type,
76                           const irange &lhs,
77                           const irange &op1,
78                           relation_trio = TRIO_VARYING) const;
79
80   // The following routines are used to represent relations between the
81   // various operations.  If the caller knows where the symbolics are,
82   // it can query for relationships between them given known ranges.
83   // the optional relation passed in is the relation between op1 and op2.
84   virtual relation_kind lhs_op1_relation (const irange &lhs,
85                                           const irange &op1,
86                                           const irange &op2,
87                                           relation_kind = VREL_VARYING) const;
88   virtual relation_kind lhs_op2_relation (const irange &lhs,
89                                           const irange &op1,
90                                           const irange &op2,
91                                           relation_kind = VREL_VARYING) const;
92   virtual relation_kind op1_op2_relation (const irange &lhs) const;
93 protected:
94   // Perform an integral operation between 2 sub-ranges and return it.
95   virtual void wi_fold (irange &r, tree type,
96                         const wide_int &lh_lb,
97                         const wide_int &lh_ub,
98                         const wide_int &rh_lb,
99                         const wide_int &rh_ub) const;
100   // Effect of relation for generic fold_range clients.
101   virtual bool op1_op2_relation_effect (irange &lhs_range, tree type,
102                                         const irange &op1_range,
103                                         const irange &op2_range,
104                                         relation_kind rel) const;
105   // Called by fold range to split small subranges into parts.
106   void wi_fold_in_parts (irange &r, tree type,
107                          const wide_int &lh_lb,
108                          const wide_int &lh_ub,
109                          const wide_int &rh_lb,
110                          const wide_int &rh_ub) const;
111
112   // Tree code of the range operator or ERROR_MARK if unknown.
113   tree_code m_code;
114 };
115
116 // Like range_operator above, but for floating point operators.
117
118 class range_operator_float
119 {
120 public:
121   virtual bool fold_range (frange &r, tree type,
122                            const frange &lh,
123                            const frange &rh,
124                            relation_trio = TRIO_VARYING) const;
125   virtual void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub,
126                         bool &maybe_nan,
127                         tree type,
128                         const REAL_VALUE_TYPE &lh_lb,
129                         const REAL_VALUE_TYPE &lh_ub,
130                         const REAL_VALUE_TYPE &rh_lb,
131                         const REAL_VALUE_TYPE &rh_ub,
132                         relation_kind) const;
133   // Unary operations have the range of the LHS as op2.
134   virtual bool fold_range (irange &r, tree type,
135                            const frange &lh,
136                            const irange &rh,
137                            relation_trio = TRIO_VARYING) const;
138   virtual bool fold_range (irange &r, tree type,
139                            const frange &lh,
140                            const frange &rh,
141                            relation_trio = TRIO_VARYING) const;
142   virtual bool op1_range (frange &r, tree type,
143                           const frange &lhs,
144                           const frange &op2,
145                           relation_trio = TRIO_VARYING) const;
146   virtual bool op1_range (frange &r, tree type,
147                           const irange &lhs,
148                           const frange &op2,
149                           relation_trio = TRIO_VARYING) const;
150   virtual bool op2_range (frange &r, tree type,
151                           const frange &lhs,
152                           const frange &op1,
153                           relation_trio = TRIO_VARYING) const;
154   virtual bool op2_range (frange &r, tree type,
155                           const irange &lhs,
156                           const frange &op1,
157                           relation_trio = TRIO_VARYING) const;
158
159   virtual relation_kind lhs_op1_relation (const frange &lhs,
160                                           const frange &op1,
161                                           const frange &op2,
162                                           relation_kind = VREL_VARYING) const;
163   virtual relation_kind lhs_op1_relation (const irange &lhs,
164                                           const frange &op1,
165                                           const frange &op2,
166                                           relation_kind = VREL_VARYING) const;
167   virtual relation_kind lhs_op2_relation (const frange &lhs,
168                                           const frange &op1,
169                                           const frange &op2,
170                                           relation_kind = VREL_VARYING) const;
171   virtual relation_kind lhs_op2_relation (const irange &lhs,
172                                           const frange &op1,
173                                           const frange &op2,
174                                           relation_kind = VREL_VARYING) const;
175   virtual relation_kind op1_op2_relation (const irange &lhs) const;
176   virtual relation_kind op1_op2_relation (const frange &lhs) const;
177 };
178
179 class range_op_handler
180 {
181 public:
182   range_op_handler ();
183   range_op_handler (enum tree_code code, tree type);
184   inline operator bool () const { return m_valid; }
185
186   bool fold_range (vrange &r, tree type,
187                    const vrange &lh,
188                    const vrange &rh,
189                    relation_trio = TRIO_VARYING) const;
190   bool op1_range (vrange &r, tree type,
191                   const vrange &lhs,
192                   const vrange &op2,
193                   relation_trio = TRIO_VARYING) const;
194   bool op2_range (vrange &r, tree type,
195                   const vrange &lhs,
196                   const vrange &op1,
197                   relation_trio = TRIO_VARYING) const;
198   relation_kind lhs_op1_relation (const vrange &lhs,
199                                   const vrange &op1,
200                                   const vrange &op2,
201                                   relation_kind = VREL_VARYING) const;
202   relation_kind lhs_op2_relation (const vrange &lhs,
203                                   const vrange &op1,
204                                   const vrange &op2,
205                                   relation_kind = VREL_VARYING) const;
206   relation_kind op1_op2_relation (const vrange &lhs) const;
207 protected:
208   void set_op_handler (enum tree_code code, tree type);
209   bool m_valid;
210   range_operator *m_int;
211   range_operator_float *m_float;
212 };
213
214 extern bool range_cast (vrange &, tree type);
215 extern void wi_set_zero_nonzero_bits (tree type,
216                                       const wide_int &, const wide_int &,
217                                       wide_int &maybe_nonzero,
218                                       wide_int &mustbe_nonzero);
219
220 // op1_op2_relation methods that are the same across irange and frange.
221 relation_kind equal_op1_op2_relation (const irange &lhs);
222 relation_kind not_equal_op1_op2_relation (const irange &lhs);
223 relation_kind lt_op1_op2_relation (const irange &lhs);
224 relation_kind le_op1_op2_relation (const irange &lhs);
225 relation_kind gt_op1_op2_relation (const irange &lhs);
226 relation_kind ge_op1_op2_relation (const irange &lhs);
227
228 enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
229 bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type);
230
231 // If the range of either op1 or op2 is undefined, set the result to
232 // varying and return TRUE.  If the caller truely cares about a result,
233 // they should pass in a varying if it has an undefined that it wants
234 // treated as a varying.
235
236 inline bool
237 empty_range_varying (vrange &r, tree type,
238                      const vrange &op1, const vrange & op2)
239 {
240   if (op1.undefined_p () || op2.undefined_p ())
241     {
242       r.set_varying (type);
243       return true;
244     }
245   else
246     return false;
247 }
248
249 // For relation opcodes, first try to see if the supplied relation
250 // forces a true or false result, and return that.
251 // Then check for undefined operands.  If none of this applies,
252 // return false.
253
254 inline bool
255 relop_early_resolve (irange &r, tree type, const vrange &op1,
256                      const vrange &op2, relation_trio trio,
257                      relation_kind my_rel)
258 {
259   relation_kind rel = trio.op1_op2 ();
260   // If known relation is a complete subset of this relation, always true.
261   if (relation_union (rel, my_rel) == my_rel)
262     {
263       r = range_true (type);
264       return true;
265     }
266
267   // If known relation has no subset of this relation, always false.
268   if (relation_intersect (rel, my_rel) == VREL_UNDEFINED)
269     {
270       r = range_false (type);
271       return true;
272     }
273
274   // If either operand is undefined, return VARYING.
275   if (empty_range_varying (r, type, op1, op2))
276     return true;
277
278   return false;
279 }
280
281 // This implements the range operator tables as local objects.
282
283 class range_op_table
284 {
285 public:
286   range_operator *operator[] (enum tree_code code);
287 protected:
288   void set (enum tree_code code, range_operator &op);
289 private:
290   range_operator *m_range_tree[MAX_TREE_CODES];
291 };
292
293 // Like above, but for floating point operators.
294
295 class floating_op_table
296 {
297 public:
298   floating_op_table ();
299   range_operator_float *operator[] (enum tree_code code);
300 private:
301   void set (enum tree_code code, range_operator_float &op);
302   range_operator_float *m_range_tree[MAX_TREE_CODES];
303 };
304
305 // This holds the range op table for floating point operations.
306 extern floating_op_table *floating_tree_table;
307
308 #endif // GCC_RANGE_OP_H