1 /* Tracking equivalence classes and constraints at a point on an execution path.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
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/>. */
21 #ifndef GCC_ANALYZER_CONSTRAINT_MANAGER_H
22 #define GCC_ANALYZER_CONSTRAINT_MANAGER_H
26 class constraint_manager
;
34 /* One of the end-points of a range. */
38 bound () : m_constant (NULL_TREE
), m_closed (false) {}
39 bound (tree constant
, bool closed
)
40 : m_constant (constant
), m_closed (closed
) {}
42 void ensure_closed (enum bound_kind bound_kind
);
44 const char * get_relation_as_str () const;
50 /* A range of values, used for determining if a value has been
51 constrained to just one possible constant value. */
56 range () : m_lower_bound (), m_upper_bound () {}
57 range (const bound
&lower
, const bound
&upper
)
58 : m_lower_bound (lower
), m_upper_bound (upper
) {}
60 void dump_to_pp (pretty_printer
*pp
) const;
63 tree
constrained_to_single_element ();
65 tristate
eval_condition (enum tree_code op
,
66 tree rhs_const
) const;
67 bool below_lower_bound (tree rhs_const
) const;
68 bool above_upper_bound (tree rhs_const
) const;
70 bool add_bound (bound b
, enum bound_kind bound_kind
);
71 bool add_bound (enum tree_code op
, tree rhs_const
);
78 /* A closed range of values with constant integer bounds
79 e.g. [3, 5] for the set {3, 4, 5}. */
83 bounded_range (const_tree lower
, const_tree upper
);
85 void dump_to_pp (pretty_printer
*pp
, bool show_types
) const;
86 void dump (bool show_types
) const;
88 json::object
*to_json () const;
90 std::unique_ptr
<text_art::widget
>
91 make_dump_widget (const text_art::dump_widget_info
&dwi
) const;
93 bool contains_p (tree cst
) const;
95 bool intersects_p (const bounded_range
&other
,
96 bounded_range
*out
) const;
98 bool operator== (const bounded_range
&other
) const;
99 bool operator!= (const bounded_range
&other
) const
101 return !(*this == other
);
104 static int cmp (const bounded_range
&a
, const bounded_range
&b
);
106 bool singleton_p () const
108 return tree_int_cst_equal (m_lower
, m_upper
);
115 static void set_json_attr (json::object
*obj
, const char *name
, tree value
);
118 /* A collection of bounded_range instances, suitable
119 for representing the ranges on a case label within a switch
122 struct bounded_ranges
125 typedef bounded_ranges key_t
;
127 bounded_ranges (const bounded_range
&range
);
128 bounded_ranges (const vec
<bounded_range
> &ranges
);
129 bounded_ranges (enum tree_code op
, tree rhs_const
);
131 bool operator== (const bounded_ranges
&other
) const;
133 hashval_t
get_hash () const { return m_hash
; }
135 void dump_to_pp (pretty_printer
*pp
, bool show_types
) const;
136 void dump (bool show_types
) const;
138 json::value
*to_json () const;
140 void add_to_dump_widget (text_art::tree_widget
&parent
,
141 const text_art::dump_widget_info
&dwi
) const;
143 tristate
eval_condition (enum tree_code op
,
145 bounded_ranges_manager
*mgr
) const;
147 bool contain_p (tree cst
) const;
148 bool empty_p () const { return m_ranges
.length () == 0; }
150 static int cmp (const bounded_ranges
*a
, const bounded_ranges
*b
);
152 unsigned get_count () const { return m_ranges
.length (); }
153 const bounded_range
&get_range (unsigned idx
) const { return m_ranges
[idx
]; }
156 void canonicalize ();
157 void validate () const;
159 friend class bounded_ranges_manager
;
161 auto_vec
<bounded_range
> m_ranges
;
167 template <> struct default_hash_traits
<bounded_ranges::key_t
>
168 : public member_function_hash_traits
<bounded_ranges::key_t
>
170 static const bool empty_zero_p
= true;
175 /* An object to own and consolidate bounded_ranges instances.
176 This also caches the mapping from switch_cfg_superedge
177 bounded_ranges instances, so that get_or_create_ranges_for_switch is
180 class bounded_ranges_manager
183 ~bounded_ranges_manager ();
185 const bounded_ranges
*
186 get_or_create_ranges_for_switch (const switch_cfg_superedge
*edge
,
187 const gswitch
*switch_stmt
);
189 const bounded_ranges
*get_or_create_empty ();
190 const bounded_ranges
*get_or_create_point (const_tree value
);
191 const bounded_ranges
*get_or_create_range (const_tree lower_bound
,
192 const_tree upper_bound
);
193 const bounded_ranges
*
194 get_or_create_union (const vec
<const bounded_ranges
*> &others
);
195 const bounded_ranges
*
196 get_or_create_intersection (const bounded_ranges
*a
,
197 const bounded_ranges
*b
);
198 const bounded_ranges
*
199 get_or_create_inverse (const bounded_ranges
*other
, tree type
);
201 void log_stats (logger
*logger
, bool show_objs
) const;
204 const bounded_ranges
*
205 create_ranges_for_switch (const switch_cfg_superedge
&edge
,
206 const gswitch
*switch_stmt
);
208 const bounded_ranges
*
209 make_case_label_ranges (const gswitch
*switch_stmt
,
212 const bounded_ranges
*consolidate (bounded_ranges
*);
214 struct hash_traits_t
: public typed_noop_remove
<bounded_ranges
*>
216 typedef bounded_ranges
*key_type
;
217 typedef bounded_ranges
*value_type
;
220 equal (const key_type
&k1
, const key_type
&k2
)
224 static inline hashval_t
225 hash (const key_type
&k
)
227 return k
->get_hash ();
229 static inline bool is_empty (key_type k
) { return k
== NULL
; }
230 static inline void mark_empty (key_type
&k
) { k
= NULL
; }
231 static inline bool is_deleted (key_type k
)
233 return k
== reinterpret_cast<key_type
> (1);
236 static const bool empty_zero_p
= true;
238 struct traits_t
: public simple_hashmap_traits
<hash_traits_t
,
242 typedef hash_map
<bounded_ranges
*, bounded_ranges
*, traits_t
> map_t
;
245 typedef hash_map
<const switch_cfg_superedge
*,
246 const bounded_ranges
*> edge_cache_t
;
247 edge_cache_t m_edge_cache
;
250 /* An equivalence class within a constraint manager: a set of
251 svalues that are known to all be equal to each other,
252 together with an optional tree constant that they are equal to. */
258 equiv_class (const equiv_class
&other
);
260 hashval_t
hash () const;
261 bool operator== (const equiv_class
&other
);
263 void add (const svalue
*sval
);
264 bool del (const svalue
*sval
);
266 tree
get_any_constant () const { return m_constant
; }
268 const svalue
*get_representative () const;
270 void canonicalize ();
272 void print (pretty_printer
*pp
) const;
274 json::object
*to_json () const;
276 std::unique_ptr
<text_art::tree_widget
>
277 make_dump_widget (const text_art::dump_widget_info
&dwi
,
280 bool contains_non_constant_p () const;
282 /* An equivalence class can contain multiple constants (e.g. multiple
283 different zeroes, for different types); these are just for the last
286 const svalue
*m_cst_sval
;
288 // TODO: should this be a set rather than a vec?
289 auto_vec
<const svalue
*> m_vars
;
292 /* The various kinds of constraint. */
301 const char *constraint_op_code (enum constraint_op c_op
);
303 /* An ID for an equiv_class within a constraint_manager. Internally, this
304 is an index into a vector of equiv_class * within the constraint_manager. */
309 static equiv_class_id
null () { return equiv_class_id (-1); }
311 equiv_class_id (unsigned idx
) : m_idx (idx
) {}
312 const equiv_class
&get_obj (const constraint_manager
&cm
) const;
313 equiv_class
&get_obj (constraint_manager
&cm
) const;
315 bool operator== (const equiv_class_id
&other
) const
317 return m_idx
== other
.m_idx
;
319 bool operator!= (const equiv_class_id
&other
) const
321 return m_idx
!= other
.m_idx
;
324 bool null_p () const { return m_idx
== -1; }
326 static equiv_class_id
from_int (int idx
) { return equiv_class_id (idx
); }
327 int as_int () const { return m_idx
; }
329 void print (pretty_printer
*pp
) const;
331 void update_for_removal (equiv_class_id other
)
333 if (m_idx
> other
.m_idx
)
340 /* A relationship between two equivalence classes in a constraint_manager. */
345 constraint (equiv_class_id lhs
, enum constraint_op c_op
, equiv_class_id rhs
)
346 : m_lhs (lhs
), m_op (c_op
), m_rhs (rhs
)
348 gcc_assert (!lhs
.null_p ());
349 gcc_assert (!rhs
.null_p ());
352 void print (pretty_printer
*pp
, const constraint_manager
&cm
) const;
354 json::object
*to_json () const;
356 std::unique_ptr
<text_art::widget
>
357 make_dump_widget (const text_art::dump_widget_info
&dwi
,
358 const constraint_manager
&cm
) const;
360 hashval_t
hash () const;
361 bool operator== (const constraint
&other
) const;
363 /* Is this an ordering, rather than a "!=". */
364 bool is_ordering_p () const
366 return m_op
!= CONSTRAINT_NE
;
369 bool implied_by (const constraint
&other
,
370 const constraint_manager
&cm
) const;
372 equiv_class_id m_lhs
;
373 enum constraint_op m_op
;
374 equiv_class_id m_rhs
;
377 /* An abstract base class for use with constraint_manager::for_each_fact. */
382 virtual ~fact_visitor () {}
383 virtual void on_fact (const svalue
*lhs
,
385 const svalue
*rhs
) = 0;
386 virtual void on_ranges (const svalue
*lhs
,
387 const bounded_ranges
*ranges
) = 0;
390 class bounded_ranges_constraint
393 bounded_ranges_constraint (equiv_class_id ec_id
,
394 const bounded_ranges
*ranges
)
395 : m_ec_id (ec_id
), m_ranges (ranges
)
399 void print (pretty_printer
*pp
, const constraint_manager
&cm
) const;
401 json::object
*to_json () const;
403 bool operator== (const bounded_ranges_constraint
&other
) const;
404 bool operator!= (const bounded_ranges_constraint
&other
) const
406 return !(*this == other
);
409 void add_to_hash (inchash::hash
*hstate
) const;
411 std::unique_ptr
<text_art::tree_widget
>
412 make_dump_widget (const text_art::dump_widget_info
&dwi
) const;
414 equiv_class_id m_ec_id
;
415 const bounded_ranges
*m_ranges
;
418 /* A collection of equivalence classes and constraints on them.
420 Given N svalues, this can be thought of as representing a subset of
421 N-dimensional space. When we call add_constraint,
422 we are effectively taking an intersection with that constraint. */
424 class constraint_manager
427 constraint_manager (region_model_manager
*mgr
) : m_mgr (mgr
) {}
428 constraint_manager (const constraint_manager
&other
);
429 virtual ~constraint_manager () {}
431 constraint_manager
& operator= (const constraint_manager
&other
);
433 hashval_t
hash () const;
434 bool operator== (const constraint_manager
&other
) const;
435 bool operator!= (const constraint_manager
&other
) const
437 return !(*this == other
);
440 void print (pretty_printer
*pp
) const;
441 void dump_to_pp (pretty_printer
*pp
, bool multiline
) const;
442 void dump (FILE *fp
) const;
445 json::object
*to_json () const;
447 std::unique_ptr
<text_art::tree_widget
>
448 make_dump_widget (const text_art::dump_widget_info
&dwi
) const;
450 const equiv_class
&get_equiv_class_by_index (unsigned idx
) const
452 return *m_equiv_classes
[idx
];
454 equiv_class
&get_equiv_class_by_index (unsigned idx
)
456 return *m_equiv_classes
[idx
];
459 equiv_class
&get_equiv_class (const svalue
*sval
)
461 equiv_class_id ec_id
= get_or_add_equiv_class (sval
);
462 return ec_id
.get_obj (*this);
465 bool add_constraint (const svalue
*lhs
,
469 bool add_constraint (equiv_class_id lhs_ec_id
,
471 equiv_class_id rhs_ec_id
);
473 void add_unknown_constraint (equiv_class_id lhs_ec_id
,
475 equiv_class_id rhs_ec_id
);
477 bool add_bounded_ranges (const svalue
*sval
,
478 const bounded_ranges
*ranges
);
480 bool get_equiv_class_by_svalue (const svalue
*sval
,
481 equiv_class_id
*out
) const;
482 bool sval_constrained_p (const svalue
*sval
) const;
483 equiv_class_id
get_or_add_equiv_class (const svalue
*sval
);
484 tristate
eval_condition (equiv_class_id lhs
,
486 equiv_class_id rhs
) const;
487 tristate
eval_condition (equiv_class_id lhs_ec
,
489 tree rhs_const
) const;
490 tristate
eval_condition (const svalue
*lhs
,
492 const svalue
*rhs
) const;
493 range
get_ec_bounds (equiv_class_id ec_id
) const;
495 /* PurgeCriteria should have:
496 bool should_purge_p (const svalue *sval) const. */
497 template <typename PurgeCriteria
>
498 void purge (const PurgeCriteria
&p
, purge_stats
*stats
);
500 void on_liveness_change (const svalue_set
&live_svalues
,
501 const region_model
*model
);
502 void purge_state_involving (const svalue
*sval
);
504 void canonicalize ();
506 static void merge (const constraint_manager
&cm_a
,
507 const constraint_manager
&cm_b
,
508 constraint_manager
*out
);
510 void for_each_fact (fact_visitor
*) const;
512 void validate () const;
514 bounded_ranges_manager
*get_range_manager () const;
516 bool replay_call_summary (call_summary_replay
&r
,
517 const constraint_manager
&summary
);
519 auto_delete_vec
<equiv_class
> m_equiv_classes
;
520 auto_vec
<constraint
> m_constraints
;
521 auto_vec
<bounded_ranges_constraint
> m_bounded_ranges_constraints
;
524 void add_constraint_internal (equiv_class_id lhs_id
,
525 enum constraint_op c_op
,
526 equiv_class_id rhs_id
);
527 bool impossible_derived_conditions_p (const svalue
*lhs
,
528 const svalue
*rhs
) const;
530 region_model_manager
*m_mgr
;
535 #endif /* GCC_ANALYZER_CONSTRAINT_MANAGER_H */