1 /* Tracking equivalence classes and constraints at a point on an execution path.
2 Copyright (C) 2019-2025 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/>. */
22 #define INCLUDE_VECTOR
24 #include "coretypes.h"
27 #include "basic-block.h"
29 #include "gimple-iterator.h"
30 #include "fold-const.h"
32 #include "diagnostic-core.h"
34 #include "analyzer/analyzer.h"
35 #include "ordered-hash-map.h"
40 #include "analyzer/supergraph.h"
43 #include "analyzer/analyzer-logging.h"
44 #include "analyzer/call-string.h"
45 #include "analyzer/program-point.h"
46 #include "analyzer/store.h"
47 #include "analyzer/region-model.h"
48 #include "analyzer/constraint-manager.h"
49 #include "analyzer/call-summary.h"
50 #include "analyzer/analyzer-selftests.h"
51 #include "tree-pretty-print.h"
52 #include "make-unique.h"
59 compare_constants (tree lhs_const
, enum tree_code op
, tree rhs_const
)
62 = fold_binary (op
, boolean_type_node
, lhs_const
, rhs_const
);
63 if (comparison
== boolean_true_node
)
64 return tristate (tristate::TS_TRUE
);
65 if (comparison
== boolean_false_node
)
66 return tristate (tristate::TS_FALSE
);
67 return tristate (tristate::TS_UNKNOWN
);
70 /* Return true iff CST is below the maximum value for its type. */
73 can_plus_one_p (tree cst
)
75 gcc_assert (CONSTANT_CLASS_P (cst
));
76 return tree_int_cst_lt (cst
, TYPE_MAX_VALUE (TREE_TYPE (cst
)));
79 /* Return (CST + 1). */
84 gcc_assert (CONSTANT_CLASS_P (cst
));
85 gcc_assert (can_plus_one_p (cst
));
86 tree result
= fold_build2 (PLUS_EXPR
, TREE_TYPE (cst
),
87 cst
, integer_one_node
);
88 gcc_assert (CONSTANT_CLASS_P (result
));
92 /* Return true iff CST is above the minimum value for its type. */
95 can_minus_one_p (tree cst
)
97 gcc_assert (CONSTANT_CLASS_P (cst
));
98 return tree_int_cst_lt (TYPE_MIN_VALUE (TREE_TYPE (cst
)), cst
);
101 /* Return (CST - 1). */
106 gcc_assert (CONSTANT_CLASS_P (cst
));
107 gcc_assert (can_minus_one_p (cst
));
108 tree result
= fold_build2 (MINUS_EXPR
, TREE_TYPE (cst
),
109 cst
, integer_one_node
);
110 gcc_assert (CONSTANT_CLASS_P (result
));
116 /* Ensure that this bound is closed by converting an open bound to a
120 bound::ensure_closed (enum bound_kind bound_kind
)
124 /* Offset by 1 in the appropriate direction.
125 For example, convert 3 < x into 4 <= x,
126 and convert x < 5 into x <= 4. */
127 gcc_assert (CONSTANT_CLASS_P (m_constant
));
128 gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (m_constant
)));
129 m_constant
= fold_build2 (bound_kind
== BK_UPPER
? MINUS_EXPR
: PLUS_EXPR
,
130 TREE_TYPE (m_constant
),
131 m_constant
, integer_one_node
);
132 gcc_assert (CONSTANT_CLASS_P (m_constant
));
133 gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (m_constant
)));
138 /* Get "<=" vs "<" for this bound. */
141 bound::get_relation_as_str () const
151 /* Dump this range to PP, which must support %E for tree. */
154 range::dump_to_pp (pretty_printer
*pp
) const
156 if (m_lower_bound
.m_constant
)
158 if (m_upper_bound
.m_constant
)
159 pp_printf (pp
, "%qE %s x %s %qE",
160 m_lower_bound
.m_constant
,
161 m_lower_bound
.get_relation_as_str (),
162 m_upper_bound
.get_relation_as_str (),
163 m_upper_bound
.m_constant
);
165 pp_printf (pp
, "%qE %s x",
166 m_lower_bound
.m_constant
,
167 m_lower_bound
.get_relation_as_str ());
171 if (m_upper_bound
.m_constant
)
172 pp_printf (pp
, "x %s %qE",
173 m_upper_bound
.get_relation_as_str (),
174 m_upper_bound
.m_constant
);
180 /* Dump this range to stderr. */
185 tree_dump_pretty_printer
pp (stderr
);
190 /* Determine if there is only one possible value for this range.
191 If so, return the constant; otherwise, return NULL_TREE. */
194 range::constrained_to_single_element ()
196 if (m_lower_bound
.m_constant
== NULL_TREE
197 || m_upper_bound
.m_constant
== NULL_TREE
)
200 if (!INTEGRAL_TYPE_P (TREE_TYPE (m_lower_bound
.m_constant
)))
202 if (!INTEGRAL_TYPE_P (TREE_TYPE (m_upper_bound
.m_constant
)))
205 /* Convert any open bounds to closed bounds. */
206 m_lower_bound
.ensure_closed (BK_LOWER
);
207 m_upper_bound
.ensure_closed (BK_UPPER
);
210 tree comparison
= fold_binary (EQ_EXPR
, boolean_type_node
,
211 m_lower_bound
.m_constant
,
212 m_upper_bound
.m_constant
);
213 if (comparison
== boolean_true_node
)
214 return m_lower_bound
.m_constant
;
219 /* Eval the condition "X OP RHS_CONST" for X within the range. */
222 range::eval_condition (enum tree_code op
, tree rhs_const
) const
225 if (tree single_element
= copy
.constrained_to_single_element ())
226 return compare_constants (single_element
, op
, rhs_const
);
231 if (below_lower_bound (rhs_const
))
232 return tristate (tristate::TS_FALSE
);
233 if (above_upper_bound (rhs_const
))
234 return tristate (tristate::TS_FALSE
);
239 /* Qn: "X </<= RHS_CONST". */
240 /* If RHS_CONST > upper bound, then it's true.
241 If RHS_CONST < lower bound, then it's false.
242 Otherwise unknown. */
243 if (above_upper_bound (rhs_const
))
244 return tristate (tristate::TS_TRUE
);
245 if (below_lower_bound (rhs_const
))
246 return tristate (tristate::TS_FALSE
);
250 /* Qn: "X != RHS_CONST". */
251 /* If RHS_CONST < lower bound, then it's true.
252 If RHS_CONST > upper bound, then it's false.
253 Otherwise unknown. */
254 if (below_lower_bound (rhs_const
))
255 return tristate (tristate::TS_TRUE
);
256 if (above_upper_bound (rhs_const
))
257 return tristate (tristate::TS_TRUE
);
262 /* Qn: "X >=/> RHS_CONST". */
263 if (above_upper_bound (rhs_const
))
264 return tristate (tristate::TS_FALSE
);
265 if (below_lower_bound (rhs_const
))
266 return tristate (tristate::TS_TRUE
);
273 return tristate (tristate::TS_UNKNOWN
);
276 /* Return true if RHS_CONST is below the lower bound of this range. */
279 range::below_lower_bound (tree rhs_const
) const
281 if (!m_lower_bound
.m_constant
)
284 return compare_constants (rhs_const
,
285 m_lower_bound
.m_closed
? LT_EXPR
: LE_EXPR
,
286 m_lower_bound
.m_constant
).is_true ();
289 /* Return true if RHS_CONST is above the upper bound of this range. */
292 range::above_upper_bound (tree rhs_const
) const
294 if (!m_upper_bound
.m_constant
)
297 return compare_constants (rhs_const
,
298 m_upper_bound
.m_closed
? GT_EXPR
: GE_EXPR
,
299 m_upper_bound
.m_constant
).is_true ();
302 /* Attempt to add B to the bound of the given kind of this range.
303 Return true if feasible; false if infeasible. */
306 range::add_bound (bound b
, enum bound_kind bound_kind
)
308 /* Bail out on floating point constants. */
309 if (!INTEGRAL_TYPE_P (TREE_TYPE (b
.m_constant
)))
312 b
.ensure_closed (bound_kind
);
319 /* Discard redundant bounds. */
320 if (m_lower_bound
.m_constant
)
322 m_lower_bound
.ensure_closed (BK_LOWER
);
323 if (tree_int_cst_le (b
.m_constant
,
324 m_lower_bound
.m_constant
))
327 if (m_upper_bound
.m_constant
)
329 m_upper_bound
.ensure_closed (BK_UPPER
);
330 /* Reject B <= V <= UPPER when B > UPPER. */
331 if (!tree_int_cst_le (b
.m_constant
,
332 m_upper_bound
.m_constant
))
339 /* Discard redundant bounds. */
340 if (m_upper_bound
.m_constant
)
342 m_upper_bound
.ensure_closed (BK_UPPER
);
343 if (!tree_int_cst_lt (b
.m_constant
,
344 m_upper_bound
.m_constant
))
347 if (m_lower_bound
.m_constant
)
349 m_lower_bound
.ensure_closed (BK_LOWER
);
350 /* Reject LOWER <= V <= B when LOWER > B. */
351 if (!tree_int_cst_le (m_lower_bound
.m_constant
,
362 /* Attempt to add (RANGE OP RHS_CONST) as a bound to this range.
363 Return true if feasible; false if infeasible. */
366 range::add_bound (enum tree_code op
, tree rhs_const
)
373 /* "V < RHS_CONST" */
374 return add_bound (bound (rhs_const
, false), BK_UPPER
);
376 /* "V <= RHS_CONST" */
377 return add_bound (bound (rhs_const
, true), BK_UPPER
);
379 /* "V >= RHS_CONST" */
380 return add_bound (bound (rhs_const
, true), BK_LOWER
);
382 /* "V > RHS_CONST" */
383 return add_bound (bound (rhs_const
, false), BK_LOWER
);
387 /* struct bounded_range. */
389 bounded_range::bounded_range (const_tree lower
, const_tree upper
)
390 : m_lower (const_cast<tree
> (lower
)),
391 m_upper (const_cast<tree
> (upper
))
395 gcc_assert (TREE_CODE (m_lower
) == INTEGER_CST
);
396 gcc_assert (TREE_CODE (m_upper
) == INTEGER_CST
);
397 /* We should have lower <= upper. */
398 gcc_assert (!tree_int_cst_lt (m_upper
, m_lower
));
402 /* Purely for pending on-stack values, for
404 gcc_assert (m_lower
== NULL_TREE
);
405 gcc_assert (m_lower
== NULL_TREE
);
410 dump_cst (pretty_printer
*pp
, tree cst
, bool show_types
)
415 pp_character (pp
, '(');
416 dump_generic_node (pp
, TREE_TYPE (cst
), 0, (dump_flags_t
)0, false);
417 pp_character (pp
, ')');
419 dump_generic_node (pp
, cst
, 0, (dump_flags_t
)0, false);
422 /* Dump this object to PP. */
425 bounded_range::dump_to_pp (pretty_printer
*pp
, bool show_types
) const
428 dump_cst (pp
, m_lower
, show_types
);
431 pp_character (pp
, '[');
432 dump_cst (pp
, m_lower
, show_types
);
433 pp_string (pp
, ", ");
434 dump_cst (pp
, m_upper
, show_types
);
435 pp_character (pp
, ']');
439 /* Dump this object to stderr. */
442 bounded_range::dump (bool show_types
) const
444 tree_dump_pretty_printer
pp (stderr
);
445 dump_to_pp (&pp
, show_types
);
449 std::unique_ptr
<json::object
>
450 bounded_range::to_json () const
452 auto range_obj
= ::make_unique
<json::object
> ();
453 set_json_attr (*range_obj
, "lower", m_lower
);
454 set_json_attr (*range_obj
, "upper", m_upper
);
458 std::unique_ptr
<text_art::widget
>
459 bounded_range::make_dump_widget (const text_art::dump_widget_info
&dwi
) const
461 using text_art::tree_widget
;
462 return tree_widget::from_fmt (dwi
, default_tree_printer
,
463 "%qE ... %qE", m_lower
, m_upper
);
466 /* Subroutine of bounded_range::to_json. */
469 bounded_range::set_json_attr (json::object
&obj
, const char *name
, tree value
)
472 pp_format_decoder (&pp
) = default_tree_printer
;
473 pp_printf (&pp
, "%E", value
);
474 obj
.set_string (name
, pp_formatted_text (&pp
));
478 /* Return true iff CST is within this range. */
481 bounded_range::contains_p (tree cst
) const
483 /* Reject if below lower bound. */
484 if (tree_int_cst_lt (cst
, m_lower
))
486 /* Reject if above lower bound. */
487 if (tree_int_cst_lt (m_upper
, cst
))
492 /* If this range intersects OTHER, return true, writing
493 the intersection to *OUT if OUT is non-NULL.
494 Return false if they do not intersect. */
497 bounded_range::intersects_p (const bounded_range
&other
,
498 bounded_range
*out
) const
501 = (tree_int_cst_le (m_lower
, other
.m_lower
)
502 ? other
.m_lower
: m_lower
);
503 gcc_assert (TREE_CODE (max_lower
) == INTEGER_CST
);
505 = (tree_int_cst_le (m_upper
, other
.m_upper
)
506 ? m_upper
: other
.m_upper
);
507 gcc_assert (TREE_CODE (min_upper
) == INTEGER_CST
);
509 if (tree_int_cst_le (max_lower
, min_upper
))
512 *out
= bounded_range (max_lower
, min_upper
);
520 bounded_range::operator== (const bounded_range
&other
) const
522 return (TREE_TYPE (m_lower
) == TREE_TYPE (other
.m_lower
)
523 && TREE_TYPE (m_upper
) == TREE_TYPE (other
.m_upper
)
524 && tree_int_cst_equal (m_lower
, other
.m_lower
)
525 && tree_int_cst_equal (m_upper
, other
.m_upper
));
529 bounded_range::cmp (const bounded_range
&br1
, const bounded_range
&br2
)
531 if (int cmp_lower
= tree_int_cst_compare (br1
.m_lower
,
534 return tree_int_cst_compare (br1
.m_upper
, br2
.m_upper
);
537 /* struct bounded_ranges. */
539 /* Construct a bounded_ranges instance from a single range. */
541 bounded_ranges::bounded_ranges (const bounded_range
&range
)
544 m_ranges
.quick_push (range
);
549 /* Construct a bounded_ranges instance from multiple ranges. */
551 bounded_ranges::bounded_ranges (const vec
<bounded_range
> &ranges
)
552 : m_ranges (ranges
.length ())
554 m_ranges
.safe_splice (ranges
);
559 /* Construct a bounded_ranges instance for values of LHS for which
560 (LHS OP RHS_CONST) is true (e.g. "(LHS > 3)". */
562 bounded_ranges::bounded_ranges (enum tree_code op
, tree rhs_const
)
565 gcc_assert (TREE_CODE (rhs_const
) == INTEGER_CST
);
566 tree type
= TREE_TYPE (rhs_const
);
572 m_ranges
.safe_push (bounded_range (rhs_const
, rhs_const
));
576 m_ranges
.safe_push (bounded_range (rhs_const
, TYPE_MAX_VALUE (type
)));
580 m_ranges
.safe_push (bounded_range (TYPE_MIN_VALUE (type
), rhs_const
));
584 if (tree_int_cst_lt (TYPE_MIN_VALUE (type
), rhs_const
))
585 m_ranges
.safe_push (bounded_range (TYPE_MIN_VALUE (type
),
586 minus_one (rhs_const
)));
587 if (tree_int_cst_lt (rhs_const
, TYPE_MAX_VALUE (type
)))
588 m_ranges
.safe_push (bounded_range (plus_one (rhs_const
),
589 TYPE_MAX_VALUE (type
)));
592 if (tree_int_cst_lt (rhs_const
, TYPE_MAX_VALUE (type
)))
593 m_ranges
.safe_push (bounded_range (plus_one (rhs_const
),
594 TYPE_MAX_VALUE (type
)));
597 if (tree_int_cst_lt (TYPE_MIN_VALUE (type
), rhs_const
))
598 m_ranges
.safe_push (bounded_range (TYPE_MIN_VALUE (type
),
599 minus_one (rhs_const
)));
606 /* Subroutine of ctors for fixing up m_ranges.
607 Also, initialize m_hash. */
610 bounded_ranges::canonicalize ()
612 /* Sort the ranges. */
613 m_ranges
.qsort ([](const void *p1
, const void *p2
) -> int
615 const bounded_range
&br1
= *(const bounded_range
*)p1
;
616 const bounded_range
&br2
= *(const bounded_range
*)p2
;
617 return bounded_range::cmp (br1
, br2
);
620 /* Merge ranges that are touching or overlapping. */
621 for (unsigned i
= 1; i
< m_ranges
.length (); )
623 bounded_range
*prev
= &m_ranges
[i
- 1];
624 const bounded_range
*next
= &m_ranges
[i
];
625 if (prev
->intersects_p (*next
, NULL
)
626 || (can_plus_one_p (prev
->m_upper
)
627 && tree_int_cst_equal (plus_one (prev
->m_upper
),
630 prev
->m_upper
= next
->m_upper
;
631 m_ranges
.ordered_remove (i
);
637 /* Initialize m_hash. */
638 inchash::hash
hstate (0);
639 for (const auto &iter
: m_ranges
)
641 inchash::add_expr (iter
.m_lower
, hstate
);
642 inchash::add_expr (iter
.m_upper
, hstate
);
644 m_hash
= hstate
.end ();
647 /* Assert that this object is valid. */
650 bounded_ranges::validate () const
652 /* Skip this in a release build. */
657 for (unsigned i
= 1; i
< m_ranges
.length (); i
++)
659 const bounded_range
&prev
= m_ranges
[i
- 1];
660 const bounded_range
&next
= m_ranges
[i
];
662 /* Give up if we somehow have incompatible different types. */
663 if (!types_compatible_p (TREE_TYPE (prev
.m_upper
),
664 TREE_TYPE (next
.m_lower
)))
668 gcc_assert (tree_int_cst_lt (prev
.m_upper
, next
.m_lower
));
670 gcc_assert (can_plus_one_p (prev
.m_upper
));
671 /* otherwise there's no room for "next". */
673 /* Verify no ranges touch each other. */
674 gcc_assert (tree_int_cst_lt (plus_one (prev
.m_upper
), next
.m_lower
));
678 /* bounded_ranges equality operator. */
681 bounded_ranges::operator== (const bounded_ranges
&other
) const
683 if (m_ranges
.length () != other
.m_ranges
.length ())
685 for (unsigned i
= 0; i
< m_ranges
.length (); i
++)
687 if (m_ranges
[i
] != other
.m_ranges
[i
])
693 /* Dump this object to PP. */
696 bounded_ranges::dump_to_pp (pretty_printer
*pp
, bool show_types
) const
698 pp_character (pp
, '{');
699 for (unsigned i
= 0; i
< m_ranges
.length (); ++i
)
702 pp_string (pp
, ", ");
703 m_ranges
[i
].dump_to_pp (pp
, show_types
);
705 pp_character (pp
, '}');
708 /* Dump this object to stderr. */
711 bounded_ranges::dump (bool show_types
) const
713 tree_dump_pretty_printer
pp (stderr
);
714 dump_to_pp (&pp
, show_types
);
718 std::unique_ptr
<json::value
>
719 bounded_ranges::to_json () const
721 auto arr_obj
= ::make_unique
<json::array
> ();
723 for (unsigned i
= 0; i
< m_ranges
.length (); ++i
)
724 arr_obj
->append (m_ranges
[i
].to_json ());
730 bounded_ranges::add_to_dump_widget (text_art::tree_widget
&parent
,
731 const text_art::dump_widget_info
&dwi
) const
733 for (auto &range
: m_ranges
)
734 parent
.add_child (range
.make_dump_widget (dwi
));
737 /* Determine whether (X OP RHS_CONST) is known to be true or false
738 for all X in the ranges expressed by this object. */
741 bounded_ranges::eval_condition (enum tree_code op
,
743 bounded_ranges_manager
*mgr
) const
745 /* Convert (X OP RHS_CONST) to a bounded_ranges instance and find
746 the intersection of that with this object. */
747 bounded_ranges
other (op
, rhs_const
);
748 const bounded_ranges
*intersection
749 = mgr
->get_or_create_intersection (this, &other
);
751 if (intersection
->m_ranges
.length () > 0)
753 /* We can use pointer equality to check for equality,
754 due to instance consolidation. */
755 if (intersection
== this)
756 return tristate (tristate::TS_TRUE
);
758 return tristate (tristate::TS_UNKNOWN
);
761 /* No intersection. */
762 return tristate (tristate::TS_FALSE
);
765 /* Return true if CST is within any of the ranges. */
768 bounded_ranges::contain_p (tree cst
) const
770 gcc_assert (TREE_CODE (cst
) == INTEGER_CST
);
771 for (const auto &iter
: m_ranges
)
773 /* TODO: should we optimize this based on sorting? */
774 if (iter
.contains_p (cst
))
781 bounded_ranges::cmp (const bounded_ranges
*a
, const bounded_ranges
*b
)
783 if (int cmp_length
= ((int)a
->m_ranges
.length ()
784 - (int)b
->m_ranges
.length ()))
786 for (unsigned i
= 0; i
< a
->m_ranges
.length (); i
++)
788 if (int cmp_range
= bounded_range::cmp (a
->m_ranges
[i
], b
->m_ranges
[i
]))
791 /* They are equal. They ought to have been consolidated, so we should
792 have two pointers to the same object. */
797 /* class bounded_ranges_manager. */
799 /* bounded_ranges_manager's dtor. */
801 bounded_ranges_manager::~bounded_ranges_manager ()
803 /* Delete the managed objects. */
804 for (const auto &iter
: m_map
)
808 /* Get the bounded_ranges instance for the empty set, creating it if
811 const bounded_ranges
*
812 bounded_ranges_manager::get_or_create_empty ()
814 auto_vec
<bounded_range
> empty_vec
;
816 return consolidate (new bounded_ranges (empty_vec
));
819 /* Get the bounded_ranges instance for {CST}, creating it if necessary. */
821 const bounded_ranges
*
822 bounded_ranges_manager::get_or_create_point (const_tree cst
)
824 gcc_assert (TREE_CODE (cst
) == INTEGER_CST
);
826 return get_or_create_range (cst
, cst
);
829 /* Get the bounded_ranges instance for {[LOWER_BOUND..UPPER_BOUND]},
830 creating it if necessary. */
832 const bounded_ranges
*
833 bounded_ranges_manager::get_or_create_range (const_tree lower_bound
,
834 const_tree upper_bound
)
836 gcc_assert (TREE_CODE (lower_bound
) == INTEGER_CST
);
837 gcc_assert (TREE_CODE (upper_bound
) == INTEGER_CST
);
840 (new bounded_ranges (bounded_range (lower_bound
, upper_bound
)));
843 /* Get the bounded_ranges instance for the union of OTHERS,
844 creating it if necessary. */
846 const bounded_ranges
*
847 bounded_ranges_manager::
848 get_or_create_union (const vec
<const bounded_ranges
*> &others
)
850 auto_vec
<bounded_range
> ranges
;
851 for (const auto &r
: others
)
852 ranges
.safe_splice (r
->m_ranges
);
853 return consolidate (new bounded_ranges (ranges
));
856 /* Get the bounded_ranges instance for the intersection of A and B,
857 creating it if necessary. */
859 const bounded_ranges
*
860 bounded_ranges_manager::get_or_create_intersection (const bounded_ranges
*a
,
861 const bounded_ranges
*b
)
863 auto_vec
<bounded_range
> ranges
;
866 while (a_idx
< a
->m_ranges
.length ()
867 && b_idx
< b
->m_ranges
.length ())
869 const bounded_range
&r_a
= a
->m_ranges
[a_idx
];
870 const bounded_range
&r_b
= b
->m_ranges
[b_idx
];
872 bounded_range
intersection (NULL_TREE
, NULL_TREE
);
873 if (r_a
.intersects_p (r_b
, &intersection
))
875 ranges
.safe_push (intersection
);
877 if (tree_int_cst_lt (r_a
.m_lower
, r_b
.m_lower
))
883 if (tree_int_cst_lt (r_a
.m_upper
, r_b
.m_upper
))
890 return consolidate (new bounded_ranges (ranges
));
893 /* Get the bounded_ranges instance for the inverse of OTHER relative
894 to TYPE, creating it if necessary.
895 This is for use when handling "default" in switch statements, where
896 OTHER represents all the other cases. */
898 const bounded_ranges
*
899 bounded_ranges_manager::get_or_create_inverse (const bounded_ranges
*other
,
902 tree min_val
= TYPE_MIN_VALUE (type
);
903 tree max_val
= TYPE_MAX_VALUE (type
);
904 if (other
->m_ranges
.length () == 0)
905 return get_or_create_range (min_val
, max_val
);
906 auto_vec
<bounded_range
> ranges
;
907 tree first_lb
= other
->m_ranges
[0].m_lower
;
908 if (tree_int_cst_lt (min_val
, first_lb
)
909 && can_minus_one_p (first_lb
))
910 ranges
.safe_push (bounded_range (min_val
,
911 minus_one (first_lb
)));
912 for (unsigned i
= 1; i
< other
->m_ranges
.length (); i
++)
914 tree prev_ub
= other
->m_ranges
[i
- 1].m_upper
;
915 tree iter_lb
= other
->m_ranges
[i
].m_lower
;
916 gcc_assert (tree_int_cst_lt (prev_ub
, iter_lb
));
917 if (can_plus_one_p (prev_ub
) && can_minus_one_p (iter_lb
))
918 ranges
.safe_push (bounded_range (plus_one (prev_ub
),
919 minus_one (iter_lb
)));
922 = other
->m_ranges
[other
->m_ranges
.length () - 1].m_upper
;
923 if (tree_int_cst_lt (last_ub
, max_val
)
924 && can_plus_one_p (last_ub
))
925 ranges
.safe_push (bounded_range (plus_one (last_ub
), max_val
));
927 return consolidate (new bounded_ranges (ranges
));
930 /* If an object equal to INST is already present, delete INST and
931 return the existing object.
932 Otherwise add INST and return it. */
934 const bounded_ranges
*
935 bounded_ranges_manager::consolidate (bounded_ranges
*inst
)
937 if (bounded_ranges
**slot
= m_map
.get (inst
))
942 m_map
.put (inst
, inst
);
946 /* Get the bounded_ranges instance for EDGE of SWITCH_STMT,
947 creating it if necessary, and caching it by edge. */
949 const bounded_ranges
*
950 bounded_ranges_manager::
951 get_or_create_ranges_for_switch (const switch_cfg_superedge
*edge
,
952 const gswitch
*switch_stmt
)
954 /* Look in per-edge cache. */
955 if (const bounded_ranges
** slot
= m_edge_cache
.get (edge
))
958 /* Not yet in cache. */
959 const bounded_ranges
*all_cases_ranges
960 = create_ranges_for_switch (*edge
, switch_stmt
);
961 m_edge_cache
.put (edge
, all_cases_ranges
);
962 return all_cases_ranges
;
965 /* Get the bounded_ranges instance for EDGE of SWITCH_STMT,
966 creating it if necessary, for edges for which the per-edge
967 cache has not yet been populated. */
969 const bounded_ranges
*
970 bounded_ranges_manager::
971 create_ranges_for_switch (const switch_cfg_superedge
&edge
,
972 const gswitch
*switch_stmt
)
974 /* Get the ranges for each case label. */
975 auto_vec
<const bounded_ranges
*> case_ranges_vec
976 (gimple_switch_num_labels (switch_stmt
));
978 for (tree case_label
: edge
.get_case_labels ())
980 /* Get the ranges for this case label. */
981 const bounded_ranges
*case_ranges
982 = make_case_label_ranges (switch_stmt
, case_label
);
983 case_ranges_vec
.quick_push (case_ranges
);
986 /* Combine all the ranges for each case label into a single collection
988 const bounded_ranges
*all_cases_ranges
989 = get_or_create_union (case_ranges_vec
);
990 return all_cases_ranges
;
993 /* Get the bounded_ranges instance for CASE_LABEL within
996 const bounded_ranges
*
997 bounded_ranges_manager::
998 make_case_label_ranges (const gswitch
*switch_stmt
,
1001 gcc_assert (TREE_CODE (case_label
) == CASE_LABEL_EXPR
);
1002 tree lower_bound
= CASE_LOW (case_label
);
1003 tree upper_bound
= CASE_HIGH (case_label
);
1008 return get_or_create_range (lower_bound
, upper_bound
);
1011 return get_or_create_point (lower_bound
);
1015 /* The default case.
1016 Add exclusions based on the other cases. */
1017 auto_vec
<const bounded_ranges
*> other_case_ranges
1018 (gimple_switch_num_labels (switch_stmt
));
1019 for (unsigned other_idx
= 1;
1020 other_idx
< gimple_switch_num_labels (switch_stmt
);
1023 tree other_label
= gimple_switch_label (switch_stmt
,
1025 const bounded_ranges
*other_ranges
1026 = make_case_label_ranges (switch_stmt
, other_label
);
1027 other_case_ranges
.quick_push (other_ranges
);
1029 const bounded_ranges
*other_cases_ranges
1030 = get_or_create_union (other_case_ranges
);
1031 tree type
= TREE_TYPE (gimple_switch_index (switch_stmt
));
1032 return get_or_create_inverse (other_cases_ranges
, type
);
1036 /* Dump the number of objects of each class that were managed by this
1038 If SHOW_OBJS is true, also dump the objects themselves. */
1041 bounded_ranges_manager::log_stats (logger
*logger
, bool show_objs
) const
1044 logger
->log (" # %s: %li", "ranges", (long)m_map
.elements ());
1048 auto_vec
<const bounded_ranges
*> vec_objs (m_map
.elements ());
1049 for (const auto &iter
: m_map
)
1050 vec_objs
.quick_push (iter
.second
);
1052 ([](const void *p1
, const void *p2
) -> int
1054 const bounded_ranges
*br1
= *(const bounded_ranges
* const *)p1
;
1055 const bounded_ranges
*br2
= *(const bounded_ranges
* const *)p2
;
1056 return bounded_ranges::cmp (br1
, br2
);
1059 for (const auto &iter
: vec_objs
)
1061 logger
->start_log_line ();
1062 pretty_printer
*pp
= logger
->get_printer ();
1063 pp_string (pp
, " ");
1064 iter
->dump_to_pp (pp
, true);
1065 logger
->end_log_line ();
1069 /* class equiv_class. */
1071 /* equiv_class's default ctor. */
1073 equiv_class::equiv_class ()
1074 : m_constant (NULL_TREE
), m_cst_sval (NULL
), m_vars ()
1078 /* equiv_class's copy ctor. */
1080 equiv_class::equiv_class (const equiv_class
&other
)
1081 : m_constant (other
.m_constant
), m_cst_sval (other
.m_cst_sval
),
1082 m_vars (other
.m_vars
.length ())
1084 for (const svalue
*sval
: other
.m_vars
)
1085 m_vars
.quick_push (sval
);
1088 /* Print an all-on-one-line representation of this equiv_class to PP,
1089 which must support %E for trees. */
1092 equiv_class::print (pretty_printer
*pp
) const
1094 pp_character (pp
, '{');
1097 FOR_EACH_VEC_ELT (m_vars
, i
, sval
)
1100 pp_string (pp
, " == ");
1101 sval
->dump_to_pp (pp
, true);
1106 pp_string (pp
, " == ");
1107 pp_printf (pp
, "[m_constant]%qE", m_constant
);
1109 pp_character (pp
, '}');
1112 /* Return a new json::object of the form
1114 "constant" : optional str}. */
1116 std::unique_ptr
<json::object
>
1117 equiv_class::to_json () const
1119 auto ec_obj
= ::make_unique
<json::object
> ();
1121 auto sval_arr
= ::make_unique
<json::array
> ();
1122 for (const svalue
*sval
: m_vars
)
1123 sval_arr
->append (sval
->to_json ());
1124 ec_obj
->set ("svals", std::move (sval_arr
));
1129 pp_format_decoder (&pp
) = default_tree_printer
;
1130 pp_printf (&pp
, "%qE", m_constant
);
1131 ec_obj
->set_string ("constant", pp_formatted_text (&pp
));
1137 std::unique_ptr
<text_art::tree_widget
>
1138 equiv_class::make_dump_widget (const text_art::dump_widget_info
&dwi
,
1141 using text_art::tree_widget
;
1142 std::unique_ptr
<tree_widget
> ec_widget
;
1146 pp_string (&pp
, "Equivalence class ");
1147 equiv_class_id (id
).print (&pp
);
1148 ec_widget
= tree_widget::make (dwi
, &pp
);
1151 for (const svalue
*sval
: m_vars
)
1154 pp_format_decoder (&pp
) = default_tree_printer
;
1155 sval
->dump_to_pp (&pp
, true);
1156 ec_widget
->add_child (tree_widget::make (dwi
, &pp
));
1162 pp_format_decoder (&pp
) = default_tree_printer
;
1163 pp_printf (&pp
, "%qE", m_constant
);
1164 ec_widget
->add_child (tree_widget::make (dwi
, &pp
));
1170 /* Generate a hash value for this equiv_class.
1171 This relies on the ordering of m_vars, and so this object needs to
1172 have been canonicalized for this to be meaningful. */
1175 equiv_class::hash () const
1177 inchash::hash hstate
;
1179 inchash::add_expr (m_constant
, hstate
);
1180 for (const svalue
* sval
: m_vars
)
1181 hstate
.add_ptr (sval
);
1182 return hstate
.end ();
1185 /* Equality operator for equiv_class.
1186 This relies on the ordering of m_vars, and so this object
1187 and OTHER need to have been canonicalized for this to be
1191 equiv_class::operator== (const equiv_class
&other
)
1193 if (m_constant
!= other
.m_constant
)
1194 return false; // TODO: use tree equality here?
1196 /* FIXME: should we compare m_cst_sval? */
1198 if (m_vars
.length () != other
.m_vars
.length ())
1203 FOR_EACH_VEC_ELT (m_vars
, i
, sval
)
1204 if (sval
!= other
.m_vars
[i
])
1210 /* Add SID to this equiv_class, using CM to check if it's a constant. */
1213 equiv_class::add (const svalue
*sval
)
1216 if (tree cst
= sval
->maybe_get_constant ())
1218 gcc_assert (CONSTANT_CLASS_P (cst
));
1219 /* FIXME: should we canonicalize which svalue is the constant
1220 when there are multiple equal constants? */
1224 m_vars
.safe_push (sval
);
1227 /* Remove SID from this equivalence class.
1228 Return true if SID was the last var in the equivalence class (suggesting
1229 a possible leak). */
1232 equiv_class::del (const svalue
*sval
)
1235 gcc_assert (sval
!= m_cst_sval
);
1239 FOR_EACH_VEC_ELT (m_vars
, i
, iv
)
1243 m_vars
[i
] = m_vars
[m_vars
.length () - 1];
1245 return m_vars
.length () == 0;
1249 /* SVAL must be in the class. */
1254 /* Get a representative member of this class, for handling cases
1255 where the IDs can change mid-traversal. */
1258 equiv_class::get_representative () const
1260 gcc_assert (m_vars
.length () > 0);
1264 /* Sort the svalues within this equiv_class. */
1267 equiv_class::canonicalize ()
1269 m_vars
.qsort (svalue::cmp_ptr_ptr
);
1272 /* Return true if this EC contains a variable, false if it merely
1274 Subroutine of constraint_manager::canonicalize, for removing
1278 equiv_class::contains_non_constant_p () const
1282 for (auto iter
: m_vars
)
1283 if (iter
->maybe_get_constant ())
1286 /* We have {non-constant == constant}. */
1288 /* We only have constants. */
1292 /* Return true if we have {non-constant == non-constant}. */
1293 return m_vars
.length () > 1;
1296 /* Get a debug string for C_OP. */
1299 constraint_op_code (enum constraint_op c_op
)
1305 case CONSTRAINT_NE
: return "!=";
1306 case CONSTRAINT_LT
: return "<";
1307 case CONSTRAINT_LE
: return "<=";
1311 /* Convert C_OP to an enum tree_code. */
1314 constraint_tree_code (enum constraint_op c_op
)
1320 case CONSTRAINT_NE
: return NE_EXPR
;
1321 case CONSTRAINT_LT
: return LT_EXPR
;
1322 case CONSTRAINT_LE
: return LE_EXPR
;
1326 /* Given "lhs C_OP rhs", determine "lhs T_OP rhs".
1328 For example, given "x < y", then "x > y" is false. */
1331 eval_constraint_op_for_op (enum constraint_op c_op
, enum tree_code t_op
)
1338 if (t_op
== EQ_EXPR
)
1339 return tristate (tristate::TS_FALSE
);
1340 if (t_op
== NE_EXPR
)
1341 return tristate (tristate::TS_TRUE
);
1344 if (t_op
== LT_EXPR
|| t_op
== LE_EXPR
|| t_op
== NE_EXPR
)
1345 return tristate (tristate::TS_TRUE
);
1346 if (t_op
== EQ_EXPR
|| t_op
== GT_EXPR
|| t_op
== GE_EXPR
)
1347 return tristate (tristate::TS_FALSE
);
1350 if (t_op
== LE_EXPR
)
1351 return tristate (tristate::TS_TRUE
);
1352 if (t_op
== GT_EXPR
)
1353 return tristate (tristate::TS_FALSE
);
1356 return tristate (tristate::TS_UNKNOWN
);
1359 /* class constraint. */
1361 /* Print this constraint to PP (which must support %E for trees),
1362 using CM to look up equiv_class instances from ids. */
1365 constraint::print (pretty_printer
*pp
, const constraint_manager
&cm
) const
1368 pp_string (pp
, ": ");
1369 m_lhs
.get_obj (cm
).print (pp
);
1370 pp_string (pp
, " ");
1371 pp_string (pp
, constraint_op_code (m_op
));
1372 pp_string (pp
, " ");
1374 pp_string (pp
, ": ");
1375 m_rhs
.get_obj (cm
).print (pp
);
1378 /* Return a new json::object of the form
1379 {"lhs" : int, the EC index
1381 "rhs" : int, the EC index}. */
1383 std::unique_ptr
<json::object
>
1384 constraint::to_json () const
1386 auto con_obj
= ::make_unique
<json::object
> ();
1388 con_obj
->set_integer ("lhs", m_lhs
.as_int ());
1389 con_obj
->set_string ("op", constraint_op_code (m_op
));
1390 con_obj
->set_integer ("rhs", m_rhs
.as_int ());
1395 std::unique_ptr
<text_art::widget
>
1396 constraint::make_dump_widget (const text_art::dump_widget_info
&dwi
,
1397 const constraint_manager
&cm
) const
1400 pp_format_decoder (&pp
) = default_tree_printer
;
1401 pp_show_color (&pp
) = true;
1403 return text_art::tree_widget::make (dwi
, &pp
);
1406 /* Generate a hash value for this constraint. */
1409 constraint::hash () const
1411 inchash::hash hstate
;
1412 hstate
.add_int (m_lhs
.m_idx
);
1413 hstate
.add_int (m_op
);
1414 hstate
.add_int (m_rhs
.m_idx
);
1415 return hstate
.end ();
1418 /* Equality operator for constraints. */
1421 constraint::operator== (const constraint
&other
) const
1423 if (m_lhs
!= other
.m_lhs
)
1425 if (m_op
!= other
.m_op
)
1427 if (m_rhs
!= other
.m_rhs
)
1432 /* Return true if this constraint is implied by OTHER. */
1435 constraint::implied_by (const constraint
&other
,
1436 const constraint_manager
&cm
) const
1438 if (m_lhs
== other
.m_lhs
)
1439 if (tree rhs_const
= m_rhs
.get_obj (cm
).get_any_constant ())
1440 if (tree other_rhs_const
= other
.m_rhs
.get_obj (cm
).get_any_constant ())
1441 if (m_lhs
.get_obj (cm
).get_any_constant () == NULL_TREE
)
1442 if (m_op
== other
.m_op
)
1449 if (compare_constants (rhs_const
,
1451 other_rhs_const
).is_true ())
1458 /* class bounded_ranges_constraint. */
1461 bounded_ranges_constraint::print (pretty_printer
*pp
,
1462 const constraint_manager
&cm
) const
1465 pp_string (pp
, ": ");
1466 m_ec_id
.get_obj (cm
).print (pp
);
1467 pp_string (pp
, ": ");
1468 m_ranges
->dump_to_pp (pp
, true);
1471 std::unique_ptr
<json::object
>
1472 bounded_ranges_constraint::to_json () const
1474 auto con_obj
= ::make_unique
<json::object
> ();
1476 con_obj
->set_integer ("ec", m_ec_id
.as_int ());
1477 con_obj
->set ("ranges", m_ranges
->to_json ());
1482 std::unique_ptr
<text_art::tree_widget
>
1483 bounded_ranges_constraint::
1484 make_dump_widget (const text_art::dump_widget_info
&dwi
) const
1486 using text_art::tree_widget
;
1487 std::unique_ptr
<tree_widget
> brc_widget
1488 (tree_widget::from_fmt (dwi
, nullptr,
1489 "ec%i bounded ranges", m_ec_id
.as_int ()));
1490 m_ranges
->add_to_dump_widget (*brc_widget
.get (), dwi
);
1495 bounded_ranges_constraint::
1496 operator== (const bounded_ranges_constraint
&other
) const
1498 if (m_ec_id
!= other
.m_ec_id
)
1501 /* We can compare by pointer, since the bounded_ranges_manager
1502 consolidates instances. */
1503 return m_ranges
== other
.m_ranges
;
1507 bounded_ranges_constraint::add_to_hash (inchash::hash
*hstate
) const
1509 hstate
->add_int (m_ec_id
.m_idx
);
1510 hstate
->merge_hash (m_ranges
->get_hash ());
1513 /* class equiv_class_id. */
1515 /* Get the underlying equiv_class for this ID from CM. */
1518 equiv_class_id::get_obj (const constraint_manager
&cm
) const
1520 return cm
.get_equiv_class_by_index (m_idx
);
1523 /* Access the underlying equiv_class for this ID from CM. */
1526 equiv_class_id::get_obj (constraint_manager
&cm
) const
1528 return cm
.get_equiv_class_by_index (m_idx
);
1531 /* Print this equiv_class_id to PP. */
1534 equiv_class_id::print (pretty_printer
*pp
) const
1537 pp_printf (pp
, "null");
1539 pp_printf (pp
, "ec%i", m_idx
);
1542 /* class constraint_manager. */
1544 /* constraint_manager's copy ctor. */
1546 constraint_manager::constraint_manager (const constraint_manager
&other
)
1547 : m_equiv_classes (other
.m_equiv_classes
.length ()),
1548 m_constraints (other
.m_constraints
.length ()),
1549 m_bounded_ranges_constraints (other
.m_bounded_ranges_constraints
.length ()),
1554 FOR_EACH_VEC_ELT (other
.m_equiv_classes
, i
, ec
)
1555 m_equiv_classes
.quick_push (new equiv_class (*ec
));
1557 FOR_EACH_VEC_ELT (other
.m_constraints
, i
, c
)
1558 m_constraints
.quick_push (*c
);
1559 for (const auto &iter
: other
.m_bounded_ranges_constraints
)
1560 m_bounded_ranges_constraints
.quick_push (iter
);
1563 /* constraint_manager's assignment operator. */
1566 constraint_manager::operator= (const constraint_manager
&other
)
1568 gcc_assert (m_equiv_classes
.length () == 0);
1569 gcc_assert (m_constraints
.length () == 0);
1570 gcc_assert (m_bounded_ranges_constraints
.length () == 0);
1574 m_equiv_classes
.reserve (other
.m_equiv_classes
.length ());
1575 FOR_EACH_VEC_ELT (other
.m_equiv_classes
, i
, ec
)
1576 m_equiv_classes
.quick_push (new equiv_class (*ec
));
1578 m_constraints
.reserve (other
.m_constraints
.length ());
1579 FOR_EACH_VEC_ELT (other
.m_constraints
, i
, c
)
1580 m_constraints
.quick_push (*c
);
1581 for (const auto &iter
: other
.m_bounded_ranges_constraints
)
1582 m_bounded_ranges_constraints
.quick_push (iter
);
1587 /* Generate a hash value for this constraint_manager. */
1590 constraint_manager::hash () const
1592 inchash::hash hstate
;
1597 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
1598 hstate
.merge_hash (ec
->hash ());
1599 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
1600 hstate
.merge_hash (c
->hash ());
1601 for (const auto &iter
: m_bounded_ranges_constraints
)
1602 iter
.add_to_hash (&hstate
);
1603 return hstate
.end ();
1606 /* Equality operator for constraint_manager. */
1609 constraint_manager::operator== (const constraint_manager
&other
) const
1611 if (m_equiv_classes
.length () != other
.m_equiv_classes
.length ())
1613 if (m_constraints
.length () != other
.m_constraints
.length ())
1615 if (m_bounded_ranges_constraints
.length ()
1616 != other
.m_bounded_ranges_constraints
.length ())
1622 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
1623 if (!(*ec
== *other
.m_equiv_classes
[i
]))
1628 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
1629 if (!(*c
== other
.m_constraints
[i
]))
1632 for (unsigned i
= 0; i
< m_bounded_ranges_constraints
.length (); i
++)
1634 if (m_bounded_ranges_constraints
[i
]
1635 != other
.m_bounded_ranges_constraints
[i
])
1642 /* Print this constraint_manager to PP (which must support %E for trees). */
1645 constraint_manager::print (pretty_printer
*pp
) const
1647 pp_string (pp
, "{");
1650 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
1653 pp_string (pp
, ", ");
1654 equiv_class_id (i
).print (pp
);
1655 pp_string (pp
, ": ");
1658 pp_string (pp
, " | ");
1660 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
1663 pp_string (pp
, " && ");
1664 c
->print (pp
, *this);
1666 if (m_bounded_ranges_constraints
.length ())
1668 pp_string (pp
, " | ");
1670 for (const auto &iter
: m_bounded_ranges_constraints
)
1673 pp_string (pp
, " && ");
1674 iter
.print (pp
, *this);
1678 pp_printf (pp
, "}");
1681 /* Dump a representation of this constraint_manager to PP
1682 (which must support %E for trees). */
1685 constraint_manager::dump_to_pp (pretty_printer
*pp
, bool multiline
) const
1688 pp_string (pp
, " ");
1689 pp_string (pp
, "equiv classes:");
1693 pp_string (pp
, " {");
1696 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
1699 pp_string (pp
, " ");
1701 pp_string (pp
, ", ");
1702 equiv_class_id (i
).print (pp
);
1703 pp_string (pp
, ": ");
1709 pp_string (pp
, " ");
1711 pp_string (pp
, "}");
1712 pp_string (pp
, "constraints:");
1716 pp_string (pp
, "{");
1718 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
1721 pp_string (pp
, " ");
1722 pp_printf (pp
, "%i: ", i
);
1723 c
->print (pp
, *this);
1728 pp_string (pp
, "}");
1729 if (m_bounded_ranges_constraints
.length ())
1732 pp_string (pp
, " ");
1733 pp_string (pp
, "ranges:");
1737 pp_string (pp
, "{");
1739 for (const auto &iter
: m_bounded_ranges_constraints
)
1742 pp_string (pp
, " ");
1744 pp_string (pp
, " && ");
1745 iter
.print (pp
, *this);
1751 pp_string (pp
, "}");
1755 /* Dump a multiline representation of this constraint_manager to FP. */
1758 constraint_manager::dump (FILE *fp
) const
1760 tree_dump_pretty_printer
pp (fp
);
1761 dump_to_pp (&pp
, true);
1764 /* Dump a multiline representation of this constraint_manager to stderr. */
1767 constraint_manager::dump () const
1772 /* Dump a multiline representation of CM to stderr. */
1775 debug (const constraint_manager
&cm
)
1780 /* Return a new json::object of the form
1781 {"ecs" : array of objects, one per equiv_class
1782 "constraints" : array of objects, one per constraint}. */
1784 std::unique_ptr
<json::object
>
1785 constraint_manager::to_json () const
1787 auto cm_obj
= ::make_unique
<json::object
> ();
1789 /* Equivalence classes. */
1791 auto ec_arr
= ::make_unique
<json::array
> ();
1792 for (const equiv_class
*ec
: m_equiv_classes
)
1793 ec_arr
->append (ec
->to_json ());
1794 cm_obj
->set ("ecs", std::move (ec_arr
));
1799 auto con_arr
= ::make_unique
<json::array
> ();
1800 for (const constraint
&c
: m_constraints
)
1801 con_arr
->append (c
.to_json ());
1802 cm_obj
->set ("constraints", std::move (con_arr
));
1805 /* m_bounded_ranges_constraints. */
1807 auto con_arr
= ::make_unique
<json::array
> ();
1808 for (const auto &c
: m_bounded_ranges_constraints
)
1809 con_arr
->append (c
.to_json ());
1810 cm_obj
->set ("bounded_ranges_constraints", std::move (con_arr
));
1816 std::unique_ptr
<text_art::tree_widget
>
1817 constraint_manager::make_dump_widget (const text_art::dump_widget_info
&dwi
) const
1819 using text_art::tree_widget
;
1820 std::unique_ptr
<tree_widget
> cm_widget
1821 (tree_widget::make (dwi
, "Constraints"));
1823 /* Equivalence classes. */
1826 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
1827 cm_widget
->add_child (ec
->make_dump_widget (dwi
, i
));
1830 for (const constraint
&c
: m_constraints
)
1831 cm_widget
->add_child (c
.make_dump_widget (dwi
, *this));
1833 /* m_bounded_ranges_constraints. */
1834 for (const auto &brc
: m_bounded_ranges_constraints
)
1835 cm_widget
->add_child (brc
.make_dump_widget (dwi
));
1837 if (cm_widget
->get_num_children () == 0)
1843 /* Attempt to add the constraint LHS OP RHS to this constraint_manager.
1844 Return true if the constraint could be added (or is already true).
1845 Return false if the constraint contradicts existing knowledge. */
1848 constraint_manager::add_constraint (const svalue
*lhs
,
1852 lhs
= lhs
->unwrap_any_unmergeable ();
1853 rhs
= rhs
->unwrap_any_unmergeable ();
1855 /* Nothing can be known about unknown/poisoned values. */
1856 if (!lhs
->can_have_associated_state_p ()
1857 || !rhs
->can_have_associated_state_p ())
1858 /* Not a contradiction. */
1861 /* Check the conditions on svalues. */
1863 tristate t_cond
= eval_condition (lhs
, op
, rhs
);
1865 /* If we already have the condition, do nothing. */
1866 if (t_cond
.is_true ())
1869 /* Reject a constraint that would contradict existing knowledge, as
1871 if (t_cond
.is_false ())
1875 equiv_class_id lhs_ec_id
= get_or_add_equiv_class (lhs
);
1876 equiv_class_id rhs_ec_id
= get_or_add_equiv_class (rhs
);
1878 /* Check the stronger conditions on ECs. */
1880 tristate t
= eval_condition (lhs_ec_id
, op
, rhs_ec_id
);
1882 /* Discard constraints that are already known. */
1886 /* Reject unsatisfiable constraints. */
1892 (SVAL + OFFSET) > CST,
1893 then that can imply:
1894 SVAL > (CST - OFFSET). */
1895 if (const binop_svalue
*lhs_binop
= lhs
->dyn_cast_binop_svalue ())
1896 if (tree rhs_cst
= rhs
->maybe_get_constant ())
1897 if (tree offset
= lhs_binop
->get_arg1 ()->maybe_get_constant ())
1898 if ((op
== GT_EXPR
|| op
== LT_EXPR
1899 || op
== GE_EXPR
|| op
== LE_EXPR
)
1900 && lhs_binop
->get_op () == PLUS_EXPR
)
1902 tree offset_of_cst
= fold_build2 (MINUS_EXPR
, TREE_TYPE (rhs_cst
),
1904 const svalue
*implied_lhs
= lhs_binop
->get_arg0 ();
1905 enum tree_code implied_op
= op
;
1906 const svalue
*implied_rhs
1907 = m_mgr
->get_or_create_constant_svalue (offset_of_cst
);
1908 if (!add_constraint (implied_lhs
, implied_op
, implied_rhs
))
1910 /* The above add_constraint could lead to EC merger, so we need
1911 to refresh the EC IDs. */
1912 lhs_ec_id
= get_or_add_equiv_class (lhs
);
1913 rhs_ec_id
= get_or_add_equiv_class (rhs
);
1916 add_unknown_constraint (lhs_ec_id
, op
, rhs_ec_id
);
1920 /* Attempt to add the constraint LHS_EC_ID OP RHS_EC_ID to this
1922 Return true if the constraint could be added (or is already true).
1923 Return false if the constraint contradicts existing knowledge. */
1926 constraint_manager::add_constraint (equiv_class_id lhs_ec_id
,
1928 equiv_class_id rhs_ec_id
)
1930 tristate t
= eval_condition (lhs_ec_id
, op
, rhs_ec_id
);
1932 /* Discard constraints that are already known. */
1936 /* Reject unsatisfiable constraints. */
1940 add_unknown_constraint (lhs_ec_id
, op
, rhs_ec_id
);
1944 /* Add the constraint LHS_EC_ID OP RHS_EC_ID to this constraint_manager,
1945 where the constraint has already been checked for being "unknown". */
1948 constraint_manager::add_unknown_constraint (equiv_class_id lhs_ec_id
,
1950 equiv_class_id rhs_ec_id
)
1952 gcc_assert (lhs_ec_id
!= rhs_ec_id
);
1954 /* For now, simply accumulate constraints, without attempting any further
1960 /* Merge rhs_ec into lhs_ec. */
1961 equiv_class
&lhs_ec_obj
= lhs_ec_id
.get_obj (*this);
1962 const equiv_class
&rhs_ec_obj
= rhs_ec_id
.get_obj (*this);
1966 FOR_EACH_VEC_ELT (rhs_ec_obj
.m_vars
, i
, sval
)
1967 lhs_ec_obj
.add (sval
);
1969 if (rhs_ec_obj
.m_constant
)
1971 lhs_ec_obj
.m_constant
= rhs_ec_obj
.m_constant
;
1972 lhs_ec_obj
.m_cst_sval
= rhs_ec_obj
.m_cst_sval
;
1975 /* Drop rhs equivalence class, overwriting it with the
1976 final ec (which might be the same one). */
1977 equiv_class_id final_ec_id
= m_equiv_classes
.length () - 1;
1978 equiv_class
*old_ec
= m_equiv_classes
[rhs_ec_id
.m_idx
];
1979 equiv_class
*final_ec
= m_equiv_classes
.pop ();
1980 if (final_ec
!= old_ec
)
1981 m_equiv_classes
[rhs_ec_id
.m_idx
] = final_ec
;
1983 if (lhs_ec_id
== final_ec_id
)
1984 lhs_ec_id
= rhs_ec_id
;
1986 /* Update the constraints. */
1988 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
1990 /* Update references to the rhs_ec so that
1991 they refer to the lhs_ec. */
1992 if (c
->m_lhs
== rhs_ec_id
)
1993 c
->m_lhs
= lhs_ec_id
;
1994 if (c
->m_rhs
== rhs_ec_id
)
1995 c
->m_rhs
= lhs_ec_id
;
1997 /* Renumber all constraints that refer to the final rhs_ec
1998 to the old rhs_ec, where the old final_ec now lives. */
1999 if (c
->m_lhs
== final_ec_id
)
2000 c
->m_lhs
= rhs_ec_id
;
2001 if (c
->m_rhs
== final_ec_id
)
2002 c
->m_rhs
= rhs_ec_id
;
2004 bounded_ranges_constraint
*brc
;
2005 FOR_EACH_VEC_ELT (m_bounded_ranges_constraints
, i
, brc
)
2007 if (brc
->m_ec_id
== rhs_ec_id
)
2008 brc
->m_ec_id
= lhs_ec_id
;
2009 if (brc
->m_ec_id
== final_ec_id
)
2010 brc
->m_ec_id
= rhs_ec_id
;
2013 /* We may now have self-comparisons due to the merger; these
2014 constraints should be removed. */
2015 unsigned read_index
, write_index
;
2016 VEC_ORDERED_REMOVE_IF (m_constraints
, read_index
, write_index
, c
,
2017 (c
->m_lhs
== c
->m_rhs
));
2021 add_constraint_internal (rhs_ec_id
, CONSTRAINT_LE
, lhs_ec_id
);
2024 add_constraint_internal (lhs_ec_id
, CONSTRAINT_LE
, rhs_ec_id
);
2027 add_constraint_internal (lhs_ec_id
, CONSTRAINT_NE
, rhs_ec_id
);
2030 add_constraint_internal (rhs_ec_id
, CONSTRAINT_LT
, lhs_ec_id
);
2033 add_constraint_internal (lhs_ec_id
, CONSTRAINT_LT
, rhs_ec_id
);
2042 /* Subroutine of constraint_manager::add_constraint, for handling all
2043 operations other than equality (for which equiv classes are merged). */
2046 constraint_manager::add_constraint_internal (equiv_class_id lhs_id
,
2047 enum constraint_op c_op
,
2048 equiv_class_id rhs_id
)
2050 if (m_constraints
.length () >= (unsigned)param_analyzer_max_constraints
)
2053 constraint
new_c (lhs_id
, c_op
, rhs_id
);
2055 /* Remove existing constraints that would be implied by the
2057 unsigned read_index
, write_index
;
2059 VEC_ORDERED_REMOVE_IF (m_constraints
, read_index
, write_index
, c
,
2060 (c
->implied_by (new_c
, *this)));
2062 /* Add the constraint. */
2063 m_constraints
.safe_push (new_c
);
2065 /* We don't yet update m_bounded_ranges_constraints here yet. */
2067 if (!flag_analyzer_transitivity
)
2070 if (c_op
!= CONSTRAINT_NE
)
2072 /* The following can potentially add EQ_EXPR facts, which could lead
2073 to ECs being merged, which would change the meaning of the EC IDs.
2074 Hence we need to do this via representatives. */
2075 const svalue
*lhs
= lhs_id
.get_obj (*this).get_representative ();
2076 const svalue
*rhs
= rhs_id
.get_obj (*this).get_representative ();
2078 /* We have LHS </<= RHS */
2080 /* Handle transitivity of ordering by adding additional constraints
2081 based on what we already knew.
2083 So if we have already have:
2091 We need to recurse to ensure we also add:
2093 We call the checked add_constraint to avoid adding constraints
2094 that are already present. Doing so also ensures termination
2095 in the case of cycles.
2097 We also check for single-element ranges, adding EQ_EXPR facts
2098 where we discover them. For example 3 < x < 5 implies
2099 that x == 4 (if x is an integer). */
2100 for (unsigned i
= 0; i
< m_constraints
.length (); i
++)
2102 const constraint
*other
= &m_constraints
[i
];
2103 if (other
->is_ordering_p ())
2105 /* Refresh the EC IDs, in case any mergers have happened. */
2106 lhs_id
= get_or_add_equiv_class (lhs
);
2107 rhs_id
= get_or_add_equiv_class (rhs
);
2109 tree lhs_const
= lhs_id
.get_obj (*this).m_constant
;
2110 tree rhs_const
= rhs_id
.get_obj (*this).m_constant
;
2111 tree other_lhs_const
2112 = other
->m_lhs
.get_obj (*this).m_constant
;
2113 tree other_rhs_const
2114 = other
->m_rhs
.get_obj (*this).m_constant
;
2116 /* We have "LHS </<= RHS" and "other.lhs </<= other.rhs". */
2118 /* If we have LHS </<= RHS and RHS </<= LHS, then we have a
2120 if (rhs_id
== other
->m_lhs
2121 && other
->m_rhs
== lhs_id
)
2123 /* We must have equality for this to be possible. */
2124 gcc_assert (c_op
== CONSTRAINT_LE
2125 && other
->m_op
== CONSTRAINT_LE
);
2126 add_constraint (lhs_id
, EQ_EXPR
, rhs_id
);
2127 /* Adding an equality will merge the two ECs and potentially
2128 reorganize the constraints. Stop iterating. */
2131 /* Otherwise, check for transitivity. */
2132 if (rhs_id
== other
->m_lhs
)
2134 /* With RHS == other.lhs, we have:
2135 "LHS </<= (RHS, other.lhs) </<= other.rhs"
2136 and thus this implies "LHS </<= other.rhs". */
2138 /* Do we have a tightly-constrained range? */
2143 range
r (bound (lhs_const
, c_op
== CONSTRAINT_LE
),
2144 bound (other_rhs_const
,
2145 other
->m_op
== CONSTRAINT_LE
));
2146 if (tree constant
= r
.constrained_to_single_element ())
2148 const svalue
*cst_sval
2149 = m_mgr
->get_or_create_constant_svalue (constant
);
2152 get_or_add_equiv_class (cst_sval
));
2157 /* Otherwise, add the constraint implied by transitivity. */
2158 enum tree_code new_op
2159 = ((c_op
== CONSTRAINT_LE
&& other
->m_op
== CONSTRAINT_LE
)
2160 ? LE_EXPR
: LT_EXPR
);
2161 add_constraint (lhs_id
, new_op
, other
->m_rhs
);
2163 else if (other
->m_rhs
== lhs_id
)
2165 /* With other.rhs == LHS, we have:
2166 "other.lhs </<= (other.rhs, LHS) </<= RHS"
2167 and thus this implies "other.lhs </<= RHS". */
2169 /* Do we have a tightly-constrained range? */
2174 range
r (bound (other_lhs_const
,
2175 other
->m_op
== CONSTRAINT_LE
),
2177 c_op
== CONSTRAINT_LE
));
2178 if (tree constant
= r
.constrained_to_single_element ())
2180 const svalue
*cst_sval
2181 = m_mgr
->get_or_create_constant_svalue (constant
);
2184 get_or_add_equiv_class (cst_sval
));
2189 /* Otherwise, add the constraint implied by transitivity. */
2190 enum tree_code new_op
2191 = ((c_op
== CONSTRAINT_LE
&& other
->m_op
== CONSTRAINT_LE
)
2192 ? LE_EXPR
: LT_EXPR
);
2193 add_constraint (other
->m_lhs
, new_op
, rhs_id
);
2200 /* Attempt to add the constraint that SVAL is within RANGES to this
2203 Return true if the constraint was successfully added (or is already
2205 Return false if the constraint contradicts existing knowledge. */
2208 constraint_manager::add_bounded_ranges (const svalue
*sval
,
2209 const bounded_ranges
*ranges
)
2211 /* If RANGES is just a singleton, convert this to adding the constraint:
2212 "SVAL == {the singleton}". */
2213 if (ranges
->get_count () == 1
2214 && ranges
->get_range (0).singleton_p ())
2216 tree range_cst
= ranges
->get_range (0).m_lower
;
2217 const svalue
*range_sval
2218 = m_mgr
->get_or_create_constant_svalue (range_cst
);
2219 return add_constraint (sval
, EQ_EXPR
, range_sval
);
2222 sval
= sval
->unwrap_any_unmergeable ();
2224 /* Nothing can be known about unknown/poisoned values. */
2225 if (!sval
->can_have_associated_state_p ())
2226 /* Not a contradiction. */
2229 /* If SVAL is a constant, then we can look at RANGES directly. */
2230 if (tree cst
= sval
->maybe_get_constant ())
2232 /* If the ranges contain CST, then it's a successful no-op;
2233 otherwise it's a contradiction. */
2234 return ranges
->contain_p (cst
);
2237 equiv_class_id ec_id
= get_or_add_equiv_class (sval
);
2239 /* If the EC has a constant, it's either true or false. */
2240 const equiv_class
&ec
= ec_id
.get_obj (*this);
2241 if (tree ec_cst
= ec
.get_any_constant ())
2243 if (ranges
->contain_p (ec_cst
))
2244 /* We already have SVAL == EC_CST, within RANGES, so
2245 we can discard RANGES and succeed. */
2248 /* We already have SVAL == EC_CST, not within RANGES, so
2249 we can reject RANGES as a contradiction. */
2253 /* We have at most one per ec_id. */
2254 /* Iterate through each range in RANGES. */
2255 for (auto iter
: m_bounded_ranges_constraints
)
2257 if (iter
.m_ec_id
== ec_id
)
2259 /* Update with intersection, or fail if empty. */
2260 bounded_ranges_manager
*mgr
= get_range_manager ();
2261 const bounded_ranges
*intersection
2262 = mgr
->get_or_create_intersection (iter
.m_ranges
, ranges
);
2263 if (intersection
->empty_p ())
2265 /* No intersection; fail. */
2270 /* Update with intersection; succeed. */
2271 iter
.m_ranges
= intersection
;
2277 m_bounded_ranges_constraints
.safe_push
2278 (bounded_ranges_constraint (ec_id
, ranges
));
2285 /* Look for SVAL within the equivalence classes of this constraint_manager;
2286 if found, return true, writing the id to *OUT if OUT is non-NULL,
2287 otherwise return false. */
2290 constraint_manager::get_equiv_class_by_svalue (const svalue
*sval
,
2291 equiv_class_id
*out
) const
2293 /* TODO: should we have a map, rather than these searches? */
2296 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
2300 FOR_EACH_VEC_ELT (ec
->m_vars
, j
, iv
)
2304 *out
= equiv_class_id (i
);
2311 /* Tries to find a svalue inside another svalue. */
2313 class sval_finder
: public visitor
2316 sval_finder (const svalue
*query
) : m_query (query
), m_found (false)
2320 bool found_query_p ()
2325 void visit_region_svalue (const region_svalue
*sval
)
2327 m_found
|= m_query
== sval
;
2330 void visit_constant_svalue (const constant_svalue
*sval
)
2332 m_found
|= m_query
== sval
;
2335 void visit_unknown_svalue (const unknown_svalue
*sval
)
2337 m_found
|= m_query
== sval
;
2340 void visit_poisoned_svalue (const poisoned_svalue
*sval
)
2342 m_found
|= m_query
== sval
;
2345 void visit_setjmp_svalue (const setjmp_svalue
*sval
)
2347 m_found
|= m_query
== sval
;
2350 void visit_initial_svalue (const initial_svalue
*sval
)
2352 m_found
|= m_query
== sval
;
2355 void visit_unaryop_svalue (const unaryop_svalue
*sval
)
2357 m_found
|= m_query
== sval
;
2360 void visit_binop_svalue (const binop_svalue
*sval
)
2362 m_found
|= m_query
== sval
;
2365 void visit_sub_svalue (const sub_svalue
*sval
)
2367 m_found
|= m_query
== sval
;
2370 void visit_repeated_svalue (const repeated_svalue
*sval
)
2372 m_found
|= m_query
== sval
;
2375 void visit_bits_within_svalue (const bits_within_svalue
*sval
)
2377 m_found
|= m_query
== sval
;
2380 void visit_unmergeable_svalue (const unmergeable_svalue
*sval
)
2382 m_found
|= m_query
== sval
;
2385 void visit_placeholder_svalue (const placeholder_svalue
*sval
)
2387 m_found
|= m_query
== sval
;
2390 void visit_widening_svalue (const widening_svalue
*sval
)
2392 m_found
|= m_query
== sval
;
2395 void visit_compound_svalue (const compound_svalue
*sval
)
2397 m_found
|= m_query
== sval
;
2400 void visit_conjured_svalue (const conjured_svalue
*sval
)
2402 m_found
|= m_query
== sval
;
2405 void visit_asm_output_svalue (const asm_output_svalue
*sval
)
2407 m_found
|= m_query
== sval
;
2410 void visit_const_fn_result_svalue (const const_fn_result_svalue
*sval
)
2412 m_found
|= m_query
== sval
;
2416 const svalue
*m_query
;
2420 /* Returns true if SVAL is constrained. */
2423 constraint_manager::sval_constrained_p (const svalue
*sval
) const
2427 sval_finder
finder (sval
);
2428 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
2432 FOR_EACH_VEC_ELT (ec
->m_vars
, j
, iv
)
2434 iv
->accept (&finder
);
2435 if (finder
.found_query_p ())
2442 /* Ensure that SVAL has an equivalence class within this constraint_manager;
2443 return the ID of the class. */
2446 constraint_manager::get_or_add_equiv_class (const svalue
*sval
)
2448 equiv_class_id
result (-1);
2450 gcc_assert (sval
->can_have_associated_state_p ());
2452 /* Convert all NULL pointers to (void *) to avoid state explosions
2453 involving all of the various (foo *)NULL vs (bar *)NULL. */
2454 if (sval
->get_type ())
2455 if (POINTER_TYPE_P (sval
->get_type ()))
2456 if (tree cst
= sval
->maybe_get_constant ())
2458 sval
= m_mgr
->get_or_create_constant_svalue (null_pointer_node
);
2460 /* Try svalue match. */
2461 if (get_equiv_class_by_svalue (sval
, &result
))
2464 /* Try equality of constants. */
2465 if (tree cst
= sval
->maybe_get_constant ())
2469 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
2471 && types_compatible_p (TREE_TYPE (cst
),
2472 TREE_TYPE (ec
->m_constant
)))
2474 tree eq
= fold_binary (EQ_EXPR
, boolean_type_node
,
2475 cst
, ec
->m_constant
);
2476 if (eq
== boolean_true_node
)
2479 return equiv_class_id (i
);
2486 equiv_class
*new_ec
= new equiv_class ();
2488 m_equiv_classes
.safe_push (new_ec
);
2490 equiv_class_id
new_id (m_equiv_classes
.length () - 1);
2495 /* Evaluate the condition LHS_EC OP RHS_EC. */
2498 constraint_manager::eval_condition (equiv_class_id lhs_ec
,
2500 equiv_class_id rhs_ec
) const
2502 if (lhs_ec
== rhs_ec
)
2509 return tristate (tristate::TS_TRUE
);
2514 return tristate (tristate::TS_FALSE
);
2520 tree lhs_const
= lhs_ec
.get_obj (*this).get_any_constant ();
2521 tree rhs_const
= rhs_ec
.get_obj (*this).get_any_constant ();
2522 if (lhs_const
&& rhs_const
)
2524 tristate result_for_constants
2525 = compare_constants (lhs_const
, op
, rhs_const
);
2526 if (result_for_constants
.is_known ())
2527 return result_for_constants
;
2530 enum tree_code swapped_op
= swap_tree_comparison (op
);
2534 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
2536 if (c
->m_lhs
== lhs_ec
2537 && c
->m_rhs
== rhs_ec
)
2539 tristate result_for_constraint
2540 = eval_constraint_op_for_op (c
->m_op
, op
);
2541 if (result_for_constraint
.is_known ())
2542 return result_for_constraint
;
2544 /* Swapped operands. */
2545 if (c
->m_lhs
== rhs_ec
2546 && c
->m_rhs
== lhs_ec
)
2548 tristate result_for_constraint
2549 = eval_constraint_op_for_op (c
->m_op
, swapped_op
);
2550 if (result_for_constraint
.is_known ())
2551 return result_for_constraint
;
2555 /* We don't use m_bounded_ranges_constraints here yet. */
2557 return tristate (tristate::TS_UNKNOWN
);
2561 constraint_manager::get_ec_bounds (equiv_class_id ec_id
) const
2567 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
2569 if (c
->m_lhs
== ec_id
)
2571 if (tree other_cst
= c
->m_rhs
.get_obj (*this).get_any_constant ())
2580 /* We have "EC_ID < OTHER_CST". */
2581 result
.add_bound (bound (other_cst
, false), BK_UPPER
);
2585 /* We have "EC_ID <= OTHER_CST". */
2586 result
.add_bound (bound (other_cst
, true), BK_UPPER
);
2590 if (c
->m_rhs
== ec_id
)
2592 if (tree other_cst
= c
->m_lhs
.get_obj (*this).get_any_constant ())
2601 /* We have "OTHER_CST < EC_ID"
2602 i.e. "EC_ID > OTHER_CST". */
2603 result
.add_bound (bound (other_cst
, false), BK_LOWER
);
2607 /* We have "OTHER_CST <= EC_ID"
2608 i.e. "EC_ID >= OTHER_CST". */
2609 result
.add_bound (bound (other_cst
, true), BK_LOWER
);
2618 /* Evaluate the condition LHS_EC OP RHS_CONST, avoiding the creation
2619 of equiv_class instances. */
2622 constraint_manager::eval_condition (equiv_class_id lhs_ec
,
2624 tree rhs_const
) const
2626 gcc_assert (!lhs_ec
.null_p ());
2627 gcc_assert (CONSTANT_CLASS_P (rhs_const
));
2629 if (tree lhs_const
= lhs_ec
.get_obj (*this).get_any_constant ())
2630 return compare_constants (lhs_const
, op
, rhs_const
);
2632 /* Check for known inequalities of the form
2633 (LHS_EC != OTHER_CST) or (OTHER_CST != LHS_EC).
2634 If RHS_CONST == OTHER_CST, then we also know that LHS_EC != OTHER_CST.
2635 For example, we might have the constraint
2637 so we want the condition
2642 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
2644 if (c
->m_op
== CONSTRAINT_NE
)
2646 if (c
->m_lhs
== lhs_ec
)
2648 if (tree other_cst
= c
->m_rhs
.get_obj (*this).get_any_constant ())
2649 if (compare_constants
2650 (rhs_const
, EQ_EXPR
, other_cst
).is_true ())
2655 return tristate (tristate::TS_FALSE
);
2657 return tristate (tristate::TS_TRUE
);
2663 if (c
->m_rhs
== lhs_ec
)
2665 if (tree other_cst
= c
->m_lhs
.get_obj (*this).get_any_constant ())
2666 if (compare_constants
2667 (rhs_const
, EQ_EXPR
, other_cst
).is_true ())
2672 return tristate (tristate::TS_FALSE
);
2674 return tristate (tristate::TS_TRUE
);
2683 bounded_ranges_manager
*mgr
= get_range_manager ();
2684 for (const auto &iter
: m_bounded_ranges_constraints
)
2685 if (iter
.m_ec_id
== lhs_ec
)
2686 return iter
.m_ranges
->eval_condition (op
, rhs_const
, mgr
);
2688 /* Look at existing bounds on LHS_EC. */
2689 range lhs_bounds
= get_ec_bounds (lhs_ec
);
2690 tristate result
= lhs_bounds
.eval_condition (op
, rhs_const
);
2691 if (result
.is_known ())
2694 /* Also reject if range::add_bound fails. */
2695 if (!lhs_bounds
.add_bound (op
, rhs_const
))
2696 return tristate (false);
2698 return tristate::unknown ();
2701 /* Return true iff "LHS == RHS" is known to be impossible due to
2704 Look for an EC containing an EC_VAL of the form (LHS OP CST).
2705 If found, see if (LHS OP CST) == EC_VAL is false.
2706 If so, we know this condition is false.
2708 For example, if we already know that
2710 and we're evaluating X == Z, we can test to see if
2711 (Z & CST_MASK) == EC_VAL
2714 and reject this if we know that's false. */
2717 constraint_manager::impossible_derived_conditions_p (const svalue
*lhs
,
2718 const svalue
*rhs
) const
2722 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
2724 for (const svalue
*ec_sval
: ec
->m_vars
)
2725 switch (ec_sval
->get_kind ())
2731 const binop_svalue
*iter_binop
2732 = as_a
<const binop_svalue
*> (ec_sval
);
2733 if (lhs
== iter_binop
->get_arg0 ()
2734 && iter_binop
->get_type ())
2735 if (iter_binop
->get_arg1 ()->get_kind () == SK_CONSTANT
)
2737 /* Try evalating EC_SVAL with LHS
2738 as the value of EC_SVAL's lhs, and see if it's
2739 consistent with existing knowledge. */
2740 const svalue
*subst_bin_op
2741 = m_mgr
->get_or_create_binop
2742 (iter_binop
->get_type (),
2743 iter_binop
->get_op (),
2745 iter_binop
->get_arg1 ());
2746 tristate t
= eval_condition (subst_bin_op
,
2750 return true; /* Impossible. */
2756 /* Not known to be impossible. */
2761 /* Evaluate the condition LHS OP RHS, without modifying this
2762 constraint_manager (avoiding the creation of equiv_class instances). */
2765 constraint_manager::eval_condition (const svalue
*lhs
,
2767 const svalue
*rhs
) const
2769 lhs
= lhs
->unwrap_any_unmergeable ();
2770 rhs
= rhs
->unwrap_any_unmergeable ();
2772 /* Nothing can be known about unknown or poisoned values. */
2773 if (lhs
->get_kind () == SK_UNKNOWN
2774 || lhs
->get_kind () == SK_POISONED
2775 || rhs
->get_kind () == SK_UNKNOWN
2776 || rhs
->get_kind () == SK_POISONED
)
2777 return tristate (tristate::TS_UNKNOWN
);
2780 && !(FLOAT_TYPE_P (lhs
->get_type ())
2781 || FLOAT_TYPE_P (rhs
->get_type ())))
2788 return tristate (tristate::TS_TRUE
);
2793 return tristate (tristate::TS_FALSE
);
2799 equiv_class_id
lhs_ec (-1);
2800 equiv_class_id
rhs_ec (-1);
2801 get_equiv_class_by_svalue (lhs
, &lhs_ec
);
2802 get_equiv_class_by_svalue (rhs
, &rhs_ec
);
2803 if (!lhs_ec
.null_p () && !rhs_ec
.null_p ())
2805 tristate result_for_ecs
2806 = eval_condition (lhs_ec
, op
, rhs_ec
);
2807 if (result_for_ecs
.is_known ())
2808 return result_for_ecs
;
2812 && impossible_derived_conditions_p (lhs
, rhs
))
2815 /* If at least one is not in an EC, we have no constraints
2816 comparing LHS and RHS yet.
2817 They might still be comparable if one (or both) is a constant.
2819 Alternatively, we can also get here if we had ECs but they weren't
2820 comparable. Again, constant comparisons might give an answer. */
2821 tree lhs_const
= lhs
->maybe_get_constant ();
2822 tree rhs_const
= rhs
->maybe_get_constant ();
2823 if (lhs_const
&& rhs_const
)
2825 tristate result_for_constants
2826 = compare_constants (lhs_const
, op
, rhs_const
);
2827 if (result_for_constants
.is_known ())
2828 return result_for_constants
;
2831 if (!lhs_ec
.null_p ())
2834 return eval_condition (lhs_ec
, op
, rhs_const
);
2836 if (!rhs_ec
.null_p ())
2840 enum tree_code swapped_op
= swap_tree_comparison (op
);
2841 return eval_condition (rhs_ec
, swapped_op
, lhs_const
);
2845 return tristate (tristate::TS_UNKNOWN
);
2848 /* Delete any information about svalues identified by P.
2849 Such instances are removed from equivalence classes, and any
2850 redundant ECs and constraints are also removed.
2851 Accumulate stats into STATS. */
2853 template <typename PurgeCriteria
>
2855 constraint_manager::purge (const PurgeCriteria
&p
, purge_stats
*stats
)
2857 /* Delete any svalues identified by P within the various equivalence
2859 for (unsigned ec_idx
= 0; ec_idx
< m_equiv_classes
.length (); )
2861 equiv_class
*ec
= m_equiv_classes
[ec_idx
];
2865 bool delete_ec
= false;
2866 FOR_EACH_VEC_ELT (ec
->m_vars
, i
, sval
)
2868 if (sval
== ec
->m_cst_sval
)
2870 if (p
.should_purge_p (sval
))
2873 if (!ec
->m_constant
)
2881 m_equiv_classes
.ordered_remove (ec_idx
);
2883 stats
->m_num_equiv_classes
++;
2885 /* Update the constraints, potentially removing some. */
2886 for (unsigned con_idx
= 0; con_idx
< m_constraints
.length (); )
2888 constraint
*c
= &m_constraints
[con_idx
];
2890 /* Remove constraints that refer to the deleted EC. */
2891 if (c
->m_lhs
== ec_idx
2892 || c
->m_rhs
== ec_idx
)
2894 m_constraints
.ordered_remove (con_idx
);
2896 stats
->m_num_constraints
++;
2900 /* Renumber constraints that refer to ECs that have
2901 had their idx changed. */
2902 c
->m_lhs
.update_for_removal (ec_idx
);
2903 c
->m_rhs
.update_for_removal (ec_idx
);
2909 /* Update bounded_ranges_constraint instances. */
2910 for (unsigned r_idx
= 0;
2911 r_idx
< m_bounded_ranges_constraints
.length (); )
2913 bounded_ranges_constraint
*brc
2914 = &m_bounded_ranges_constraints
[r_idx
];
2916 /* Remove if it refers to the deleted EC. */
2917 if (brc
->m_ec_id
== ec_idx
)
2919 m_bounded_ranges_constraints
.ordered_remove (r_idx
);
2921 stats
->m_num_bounded_ranges_constraints
++;
2925 /* Renumber any EC ids that refer to ECs that have
2926 had their idx changed. */
2927 brc
->m_ec_id
.update_for_removal (ec_idx
);
2936 /* Now delete any constraints that are purely between constants. */
2937 for (unsigned con_idx
= 0; con_idx
< m_constraints
.length (); )
2939 constraint
*c
= &m_constraints
[con_idx
];
2940 if (m_equiv_classes
[c
->m_lhs
.m_idx
]->m_vars
.length () == 0
2941 && m_equiv_classes
[c
->m_rhs
.m_idx
]->m_vars
.length () == 0)
2943 m_constraints
.ordered_remove (con_idx
);
2945 stats
->m_num_constraints
++;
2953 /* Finally, delete any ECs that purely contain constants and aren't
2954 referenced by any constraints. */
2955 for (unsigned ec_idx
= 0; ec_idx
< m_equiv_classes
.length (); )
2957 equiv_class
*ec
= m_equiv_classes
[ec_idx
];
2958 if (ec
->m_vars
.length () == 0)
2960 equiv_class_id
ec_id (ec_idx
);
2961 bool has_constraint
= false;
2962 for (unsigned con_idx
= 0; con_idx
< m_constraints
.length ();
2965 constraint
*c
= &m_constraints
[con_idx
];
2966 if (c
->m_lhs
== ec_id
2967 || c
->m_rhs
== ec_id
)
2969 has_constraint
= true;
2973 if (!has_constraint
)
2976 m_equiv_classes
.ordered_remove (ec_idx
);
2978 stats
->m_num_equiv_classes
++;
2980 /* Renumber constraints that refer to ECs that have
2981 had their idx changed. */
2982 for (unsigned con_idx
= 0; con_idx
< m_constraints
.length ();
2985 constraint
*c
= &m_constraints
[con_idx
];
2986 c
->m_lhs
.update_for_removal (ec_idx
);
2987 c
->m_rhs
.update_for_removal (ec_idx
);
2990 /* Likewise for m_bounded_ranges_constraints. */
2991 for (unsigned r_idx
= 0;
2992 r_idx
< m_bounded_ranges_constraints
.length ();
2995 bounded_ranges_constraint
*brc
2996 = &m_bounded_ranges_constraints
[r_idx
];
2997 brc
->m_ec_id
.update_for_removal (ec_idx
);
3009 /* Implementation of PurgeCriteria: purge svalues that are not live
3010 with respect to LIVE_SVALUES and MODEL. */
3012 class dead_svalue_purger
3015 dead_svalue_purger (const svalue_set
&live_svalues
,
3016 const region_model
*model
)
3017 : m_live_svalues (live_svalues
), m_model (model
)
3021 bool should_purge_p (const svalue
*sval
) const
3023 return !sval
->live_p (&m_live_svalues
, m_model
);
3027 const svalue_set
&m_live_svalues
;
3028 const region_model
*m_model
;
3031 /* Purge dead svalues from equivalence classes and update constraints
3035 constraint_manager::
3036 on_liveness_change (const svalue_set
&live_svalues
,
3037 const region_model
*model
)
3039 dead_svalue_purger
p (live_svalues
, model
);
3046 svalue_purger (const svalue
*sval
) : m_sval (sval
) {}
3048 bool should_purge_p (const svalue
*sval
) const
3050 return sval
->involves_p (m_sval
);
3054 const svalue
*m_sval
;
3057 /* Purge any state involving SVAL. */
3060 constraint_manager::purge_state_involving (const svalue
*sval
)
3062 svalue_purger
p (sval
);
3066 /* Comparator for use by constraint_manager::canonicalize.
3067 Sort a pair of equiv_class instances, using the representative
3068 svalue as a sort key. */
3071 equiv_class_cmp (const void *p1
, const void *p2
)
3073 const equiv_class
*ec1
= *(const equiv_class
* const *)p1
;
3074 const equiv_class
*ec2
= *(const equiv_class
* const *)p2
;
3076 const svalue
*rep1
= ec1
->get_representative ();
3077 const svalue
*rep2
= ec2
->get_representative ();
3082 return svalue::cmp_ptr (rep1
, rep2
);
3085 /* Comparator for use by constraint_manager::canonicalize.
3086 Sort a pair of constraint instances. */
3089 constraint_cmp (const void *p1
, const void *p2
)
3091 const constraint
*c1
= (const constraint
*)p1
;
3092 const constraint
*c2
= (const constraint
*)p2
;
3093 int lhs_cmp
= c1
->m_lhs
.as_int () - c2
->m_lhs
.as_int ();
3096 int rhs_cmp
= c1
->m_rhs
.as_int () - c2
->m_rhs
.as_int ();
3099 return c1
->m_op
- c2
->m_op
;
3102 /* Purge redundant equivalence classes and constraints, and reorder them
3103 within this constraint_manager into a canonical order, to increase the
3104 chances of finding equality with another instance. */
3107 constraint_manager::canonicalize ()
3109 /* First, sort svalues within the ECs. */
3112 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
3113 ec
->canonicalize ();
3115 /* TODO: remove constraints where both sides have a constant, and are
3116 thus implicit. But does this break transitivity? */
3118 /* We will be purging and reordering ECs.
3119 We will need to remap the equiv_class_ids in the constraints,
3120 so we need to store the original index of each EC.
3121 Build a lookup table, mapping from the representative svalue
3122 to the original equiv_class_id of that svalue. */
3123 hash_map
<const svalue
*, equiv_class_id
> original_ec_id
;
3124 const unsigned orig_num_equiv_classes
= m_equiv_classes
.length ();
3125 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
3127 const svalue
*rep
= ec
->get_representative ();
3129 original_ec_id
.put (rep
, i
);
3132 /* Find ECs used by constraints. */
3133 hash_set
<const equiv_class
*> used_ecs
;
3135 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
3137 used_ecs
.add (m_equiv_classes
[c
->m_lhs
.as_int ()]);
3138 used_ecs
.add (m_equiv_classes
[c
->m_rhs
.as_int ()]);
3141 for (const auto &iter
: m_bounded_ranges_constraints
)
3142 used_ecs
.add (m_equiv_classes
[iter
.m_ec_id
.as_int ()]);
3144 /* Purge unused ECs: those that aren't used by constraints and
3145 that effectively have only one svalue (either in m_constant
3148 /* "unordered remove if" from a vec. */
3150 while (i
< m_equiv_classes
.length ())
3152 equiv_class
*ec
= m_equiv_classes
[i
];
3153 if (!used_ecs
.contains (ec
)
3154 && !ec
->contains_non_constant_p ())
3156 m_equiv_classes
.unordered_remove (i
);
3164 /* Next, sort the surviving ECs into a canonical order. */
3165 m_equiv_classes
.qsort (equiv_class_cmp
);
3167 /* Populate ec_id_map based on the old vs new EC ids. */
3168 one_way_id_map
<equiv_class_id
> ec_id_map (orig_num_equiv_classes
);
3169 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
3171 const svalue
*rep
= ec
->get_representative ();
3173 ec_id_map
.put (*original_ec_id
.get (rep
), i
);
3176 /* Use ec_id_map to update the EC ids within the constraints. */
3177 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
3179 ec_id_map
.update (&c
->m_lhs
);
3180 ec_id_map
.update (&c
->m_rhs
);
3183 for (auto &iter
: m_bounded_ranges_constraints
)
3184 ec_id_map
.update (&iter
.m_ec_id
);
3186 /* Finally, sort the constraints. */
3187 m_constraints
.qsort (constraint_cmp
);
3190 /* Concrete subclass of fact_visitor for use by constraint_manager::merge.
3191 For every fact in CM_A, see if it is also true in *CM_B. Add such
3194 class merger_fact_visitor
: public fact_visitor
3197 merger_fact_visitor (const constraint_manager
*cm_b
,
3198 constraint_manager
*out
)
3199 : m_cm_b (cm_b
), m_out (out
)
3202 void on_fact (const svalue
*lhs
, enum tree_code code
, const svalue
*rhs
)
3205 /* Special-case for widening. */
3206 if (lhs
->get_kind () == SK_WIDENING
)
3207 if (!m_cm_b
->get_equiv_class_by_svalue (lhs
, NULL
))
3209 /* LHS isn't constrained within m_cm_b. */
3210 bool sat
= m_out
->add_constraint (lhs
, code
, rhs
);
3215 if (m_cm_b
->eval_condition (lhs
, code
, rhs
).is_true ())
3217 bool sat
= m_out
->add_constraint (lhs
, code
, rhs
);
3220 /* If -fanalyzer-transitivity is off, we can encounter cases
3221 where at least one of the two constraint_managers being merged
3222 is infeasible, but we only discover that infeasibility
3223 during merging (PR analyzer/96650).
3224 Silently drop such constraints. */
3225 gcc_assert (!flag_analyzer_transitivity
);
3230 void on_ranges (const svalue
*lhs_sval
,
3231 const bounded_ranges
*ranges
) final override
3233 for (const auto &iter
: m_cm_b
->m_bounded_ranges_constraints
)
3235 const equiv_class
&ec_rhs
= iter
.m_ec_id
.get_obj (*m_cm_b
);
3236 for (unsigned i
= 0; i
< ec_rhs
.m_vars
.length (); i
++)
3238 const svalue
*rhs_sval
= ec_rhs
.m_vars
[i
];
3239 if (lhs_sval
== rhs_sval
)
3241 /* Union of the two ranges. */
3242 auto_vec
<const bounded_ranges
*> pair (2);
3243 pair
.quick_push (ranges
);
3244 pair
.quick_push (iter
.m_ranges
);
3245 bounded_ranges_manager
*ranges_mgr
3246 = m_cm_b
->get_range_manager ();
3247 const bounded_ranges
*union_
3248 = ranges_mgr
->get_or_create_union (pair
);
3249 bool sat
= m_out
->add_bounded_ranges (lhs_sval
, union_
);
3257 const constraint_manager
*m_cm_b
;
3258 constraint_manager
*m_out
;
3261 /* Use MERGER to merge CM_A and CM_B into *OUT.
3262 If one thinks of a constraint_manager as a subset of N-dimensional
3263 space, this takes the union of the points of CM_A and CM_B, and
3264 expresses that into *OUT. Alternatively, it can be thought of
3265 as the intersection of the constraints. */
3268 constraint_manager::merge (const constraint_manager
&cm_a
,
3269 const constraint_manager
&cm_b
,
3270 constraint_manager
*out
)
3272 /* Merge the equivalence classes and constraints.
3273 The easiest way to do this seems to be to enumerate all of the facts
3274 in cm_a, see which are also true in cm_b,
3275 and add those to *OUT. */
3276 merger_fact_visitor
v (&cm_b
, out
);
3277 cm_a
.for_each_fact (&v
);
3280 /* Call VISITOR's on_fact vfunc repeatedly to express the various
3281 equivalence classes and constraints.
3282 This is used by constraint_manager::merge to find the common
3283 facts between two input constraint_managers. */
3286 constraint_manager::for_each_fact (fact_visitor
*visitor
) const
3288 /* First, call EQ_EXPR within the various equivalence classes. */
3291 FOR_EACH_VEC_ELT (m_equiv_classes
, ec_idx
, ec
)
3297 FOR_EACH_VEC_ELT (ec
->m_vars
, i
, sval
)
3298 visitor
->on_fact (ec
->m_cst_sval
, EQ_EXPR
, sval
);
3300 for (unsigned i
= 0; i
< ec
->m_vars
.length (); i
++)
3301 for (unsigned j
= i
+ 1; j
< ec
->m_vars
.length (); j
++)
3302 visitor
->on_fact (ec
->m_vars
[i
], EQ_EXPR
, ec
->m_vars
[j
]);
3305 /* Now, express the various constraints. */
3308 FOR_EACH_VEC_ELT (m_constraints
, con_idx
, c
)
3310 const equiv_class
&ec_lhs
= c
->m_lhs
.get_obj (*this);
3311 const equiv_class
&ec_rhs
= c
->m_rhs
.get_obj (*this);
3312 enum tree_code code
= constraint_tree_code (c
->m_op
);
3314 if (ec_lhs
.m_cst_sval
)
3316 for (unsigned j
= 0; j
< ec_rhs
.m_vars
.length (); j
++)
3318 visitor
->on_fact (ec_lhs
.m_cst_sval
, code
, ec_rhs
.m_vars
[j
]);
3321 for (unsigned i
= 0; i
< ec_lhs
.m_vars
.length (); i
++)
3323 if (ec_rhs
.m_cst_sval
)
3324 visitor
->on_fact (ec_lhs
.m_vars
[i
], code
, ec_rhs
.m_cst_sval
);
3325 for (unsigned j
= 0; j
< ec_rhs
.m_vars
.length (); j
++)
3326 visitor
->on_fact (ec_lhs
.m_vars
[i
], code
, ec_rhs
.m_vars
[j
]);
3330 for (const auto &iter
: m_bounded_ranges_constraints
)
3332 const equiv_class
&ec_lhs
= iter
.m_ec_id
.get_obj (*this);
3333 for (unsigned i
= 0; i
< ec_lhs
.m_vars
.length (); i
++)
3335 const svalue
*lhs_sval
= ec_lhs
.m_vars
[i
];
3336 visitor
->on_ranges (lhs_sval
, iter
.m_ranges
);
3341 /* Subclass of fact_visitor for use by
3342 constraint_manager::replay_call_summary. */
3344 class replay_fact_visitor
: public fact_visitor
3347 replay_fact_visitor (call_summary_replay
&r
,
3348 constraint_manager
*out
)
3349 : m_r (r
), m_out (out
), m_feasible (true)
3352 bool feasible_p () const { return m_feasible
; }
3354 void on_fact (const svalue
*lhs
, enum tree_code code
, const svalue
*rhs
)
3357 const svalue
*caller_lhs
= m_r
.convert_svalue_from_summary (lhs
);
3360 const svalue
*caller_rhs
= m_r
.convert_svalue_from_summary (rhs
);
3363 if (!m_out
->add_constraint (caller_lhs
, code
, caller_rhs
))
3367 void on_ranges (const svalue
*lhs_sval
,
3368 const bounded_ranges
*ranges
) final override
3370 const svalue
*caller_lhs
= m_r
.convert_svalue_from_summary (lhs_sval
);
3373 if (!m_out
->add_bounded_ranges (caller_lhs
, ranges
))
3378 call_summary_replay
&m_r
;
3379 constraint_manager
*m_out
;
3383 /* Attempt to use R to replay the constraints from SUMMARY into this object.
3384 Return true if it is feasible. */
3387 constraint_manager::replay_call_summary (call_summary_replay
&r
,
3388 const constraint_manager
&summary
)
3390 replay_fact_visitor
v (r
, this);
3391 summary
.for_each_fact (&v
);
3392 return v
.feasible_p ();
3395 /* Assert that this object is valid. */
3398 constraint_manager::validate () const
3400 /* Skip this in a release build. */
3407 FOR_EACH_VEC_ELT (m_equiv_classes
, i
, ec
)
3413 FOR_EACH_VEC_ELT (ec
->m_vars
, j
, sval
)
3417 gcc_assert (CONSTANT_CLASS_P (ec
->m_constant
));
3418 gcc_assert (ec
->m_cst_sval
);
3422 gcc_assert (ec
->m_vars
.length () > 0);
3427 FOR_EACH_VEC_ELT (m_constraints
, i
, c
)
3429 gcc_assert (!c
->m_lhs
.null_p ());
3430 gcc_assert (c
->m_lhs
.as_int () < (int)m_equiv_classes
.length ());
3431 gcc_assert (!c
->m_rhs
.null_p ());
3432 gcc_assert (c
->m_rhs
.as_int () < (int)m_equiv_classes
.length ());
3435 for (const auto &iter
: m_bounded_ranges_constraints
)
3437 gcc_assert (!iter
.m_ec_id
.null_p ());
3438 gcc_assert (iter
.m_ec_id
.as_int () < (int)m_equiv_classes
.length ());
3442 bounded_ranges_manager
*
3443 constraint_manager::get_range_manager () const
3445 return m_mgr
->get_range_manager ();
3450 namespace selftest
{
3452 /* Various constraint_manager selftests.
3453 These have to be written in terms of a region_model, since
3454 the latter is responsible for managing svalue instances. */
3456 /* Verify that range::add_bound works as expected. */
3461 tree int_0
= integer_zero_node
;
3462 tree int_1
= integer_one_node
;
3463 tree int_2
= build_int_cst (integer_type_node
, 2);
3464 tree int_5
= build_int_cst (integer_type_node
, 5);
3468 ASSERT_FALSE (r
.constrained_to_single_element ());
3471 ASSERT_TRUE (r
.add_bound (GE_EXPR
, int_1
));
3474 ASSERT_TRUE (r
.add_bound (GE_EXPR
, int_0
));
3475 ASSERT_TRUE (r
.add_bound (GT_EXPR
, int_0
));
3477 ASSERT_FALSE (r
.constrained_to_single_element ());
3479 /* Contradiction. */
3480 ASSERT_FALSE (r
.add_bound (LT_EXPR
, int_1
));
3483 ASSERT_TRUE (r
.add_bound (LT_EXPR
, int_5
));
3484 ASSERT_FALSE (r
.constrained_to_single_element ());
3486 /* Contradiction. */
3487 ASSERT_FALSE (r
.add_bound (GE_EXPR
, int_5
));
3490 ASSERT_TRUE (r
.add_bound (LT_EXPR
, int_2
));
3491 ASSERT_TRUE (r
.constrained_to_single_element ());
3494 ASSERT_TRUE (r
.add_bound (LE_EXPR
, int_1
));
3495 ASSERT_TRUE (r
.constrained_to_single_element ());
3499 /* Verify that setting and getting simple conditions within a region_model
3500 work (thus exercising the underlying constraint_manager). */
3503 test_constraint_conditions ()
3505 tree int_42
= build_int_cst (integer_type_node
, 42);
3506 tree int_0
= integer_zero_node
;
3508 tree x
= build_global_decl ("x", integer_type_node
);
3509 tree y
= build_global_decl ("y", integer_type_node
);
3510 tree z
= build_global_decl ("z", integer_type_node
);
3512 /* Self-comparisons. */
3514 region_model_manager mgr
;
3515 region_model
model (&mgr
);
3516 ASSERT_CONDITION_TRUE (model
, x
, EQ_EXPR
, x
);
3517 ASSERT_CONDITION_TRUE (model
, x
, LE_EXPR
, x
);
3518 ASSERT_CONDITION_TRUE (model
, x
, GE_EXPR
, x
);
3519 ASSERT_CONDITION_FALSE (model
, x
, NE_EXPR
, x
);
3520 ASSERT_CONDITION_FALSE (model
, x
, LT_EXPR
, x
);
3521 ASSERT_CONDITION_FALSE (model
, x
, GT_EXPR
, x
);
3524 /* Adding self-equality shouldn't add equiv classes. */
3526 region_model_manager mgr
;
3527 region_model
model (&mgr
);
3528 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, x
);
3529 ADD_SAT_CONSTRAINT (model
, int_42
, EQ_EXPR
, int_42
);
3530 /* ...even when done directly via svalues: */
3531 const svalue
*sval_int_42
= model
.get_rvalue (int_42
, NULL
);
3532 bool sat
= model
.get_constraints ()->add_constraint (sval_int_42
,
3536 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 0);
3541 region_model_manager mgr
;
3542 region_model
model (&mgr
);
3543 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, y
);
3545 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, y
);
3547 ASSERT_CONDITION_TRUE (model
, x
, EQ_EXPR
, y
);
3548 ASSERT_CONDITION_TRUE (model
, x
, LE_EXPR
, y
);
3549 ASSERT_CONDITION_TRUE (model
, x
, GE_EXPR
, y
);
3550 ASSERT_CONDITION_FALSE (model
, x
, NE_EXPR
, y
);
3551 ASSERT_CONDITION_FALSE (model
, x
, LT_EXPR
, y
);
3552 ASSERT_CONDITION_FALSE (model
, x
, GT_EXPR
, y
);
3554 /* Swapped operands. */
3555 ASSERT_CONDITION_TRUE (model
, y
, EQ_EXPR
, x
);
3556 ASSERT_CONDITION_TRUE (model
, y
, LE_EXPR
, x
);
3557 ASSERT_CONDITION_TRUE (model
, y
, GE_EXPR
, x
);
3558 ASSERT_CONDITION_FALSE (model
, y
, NE_EXPR
, x
);
3559 ASSERT_CONDITION_FALSE (model
, y
, LT_EXPR
, x
);
3560 ASSERT_CONDITION_FALSE (model
, y
, GT_EXPR
, x
);
3562 /* Comparison with other var. */
3563 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, z
);
3564 ASSERT_CONDITION_UNKNOWN (model
, x
, LE_EXPR
, z
);
3565 ASSERT_CONDITION_UNKNOWN (model
, x
, GE_EXPR
, z
);
3566 ASSERT_CONDITION_UNKNOWN (model
, x
, NE_EXPR
, z
);
3567 ASSERT_CONDITION_UNKNOWN (model
, x
, LT_EXPR
, z
);
3568 ASSERT_CONDITION_UNKNOWN (model
, x
, GT_EXPR
, z
);
3571 /* x == y, then y == z */
3573 region_model_manager mgr
;
3574 region_model
model (&mgr
);
3575 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, y
);
3577 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, y
);
3578 ADD_SAT_CONSTRAINT (model
, y
, EQ_EXPR
, z
);
3580 ASSERT_CONDITION_TRUE (model
, x
, EQ_EXPR
, z
);
3581 ASSERT_CONDITION_TRUE (model
, x
, LE_EXPR
, z
);
3582 ASSERT_CONDITION_TRUE (model
, x
, GE_EXPR
, z
);
3583 ASSERT_CONDITION_FALSE (model
, x
, NE_EXPR
, z
);
3584 ASSERT_CONDITION_FALSE (model
, x
, LT_EXPR
, z
);
3585 ASSERT_CONDITION_FALSE (model
, x
, GT_EXPR
, z
);
3590 region_model_manager mgr
;
3591 region_model
model (&mgr
);
3593 ADD_SAT_CONSTRAINT (model
, x
, NE_EXPR
, y
);
3595 ASSERT_CONDITION_TRUE (model
, x
, NE_EXPR
, y
);
3596 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, y
);
3597 ASSERT_CONDITION_UNKNOWN (model
, x
, LE_EXPR
, y
);
3598 ASSERT_CONDITION_UNKNOWN (model
, x
, GE_EXPR
, y
);
3599 ASSERT_CONDITION_UNKNOWN (model
, x
, LT_EXPR
, y
);
3600 ASSERT_CONDITION_UNKNOWN (model
, x
, GT_EXPR
, y
);
3602 /* Swapped operands. */
3603 ASSERT_CONDITION_TRUE (model
, y
, NE_EXPR
, x
);
3604 ASSERT_CONDITION_FALSE (model
, y
, EQ_EXPR
, x
);
3605 ASSERT_CONDITION_UNKNOWN (model
, y
, LE_EXPR
, x
);
3606 ASSERT_CONDITION_UNKNOWN (model
, y
, GE_EXPR
, x
);
3607 ASSERT_CONDITION_UNKNOWN (model
, y
, LT_EXPR
, x
);
3608 ASSERT_CONDITION_UNKNOWN (model
, y
, GT_EXPR
, x
);
3610 /* Comparison with other var. */
3611 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, z
);
3612 ASSERT_CONDITION_UNKNOWN (model
, x
, LE_EXPR
, z
);
3613 ASSERT_CONDITION_UNKNOWN (model
, x
, GE_EXPR
, z
);
3614 ASSERT_CONDITION_UNKNOWN (model
, x
, NE_EXPR
, z
);
3615 ASSERT_CONDITION_UNKNOWN (model
, x
, LT_EXPR
, z
);
3616 ASSERT_CONDITION_UNKNOWN (model
, x
, GT_EXPR
, z
);
3621 region_model_manager mgr
;
3622 region_model
model (&mgr
);
3624 ADD_SAT_CONSTRAINT (model
, x
, LT_EXPR
, y
);
3626 ASSERT_CONDITION_TRUE (model
, x
, LT_EXPR
, y
);
3627 ASSERT_CONDITION_TRUE (model
, x
, LE_EXPR
, y
);
3628 ASSERT_CONDITION_TRUE (model
, x
, NE_EXPR
, y
);
3629 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, y
);
3630 ASSERT_CONDITION_FALSE (model
, x
, GT_EXPR
, y
);
3631 ASSERT_CONDITION_FALSE (model
, x
, GE_EXPR
, y
);
3633 /* Swapped operands. */
3634 ASSERT_CONDITION_FALSE (model
, y
, LT_EXPR
, x
);
3635 ASSERT_CONDITION_FALSE (model
, y
, LE_EXPR
, x
);
3636 ASSERT_CONDITION_TRUE (model
, y
, NE_EXPR
, x
);
3637 ASSERT_CONDITION_FALSE (model
, y
, EQ_EXPR
, x
);
3638 ASSERT_CONDITION_TRUE (model
, y
, GT_EXPR
, x
);
3639 ASSERT_CONDITION_TRUE (model
, y
, GE_EXPR
, x
);
3644 region_model_manager mgr
;
3645 region_model
model (&mgr
);
3647 ADD_SAT_CONSTRAINT (model
, x
, LE_EXPR
, y
);
3649 ASSERT_CONDITION_UNKNOWN (model
, x
, LT_EXPR
, y
);
3650 ASSERT_CONDITION_TRUE (model
, x
, LE_EXPR
, y
);
3651 ASSERT_CONDITION_UNKNOWN (model
, x
, NE_EXPR
, y
);
3652 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, y
);
3653 ASSERT_CONDITION_FALSE (model
, x
, GT_EXPR
, y
);
3654 ASSERT_CONDITION_UNKNOWN (model
, x
, GE_EXPR
, y
);
3656 /* Swapped operands. */
3657 ASSERT_CONDITION_FALSE (model
, y
, LT_EXPR
, x
);
3658 ASSERT_CONDITION_UNKNOWN (model
, y
, LE_EXPR
, x
);
3659 ASSERT_CONDITION_UNKNOWN (model
, y
, NE_EXPR
, x
);
3660 ASSERT_CONDITION_UNKNOWN (model
, y
, EQ_EXPR
, x
);
3661 ASSERT_CONDITION_UNKNOWN (model
, y
, GT_EXPR
, x
);
3662 ASSERT_CONDITION_TRUE (model
, y
, GE_EXPR
, x
);
3667 region_model_manager mgr
;
3668 region_model
model (&mgr
);
3670 ADD_SAT_CONSTRAINT (model
, x
, GT_EXPR
, y
);
3672 ASSERT_CONDITION_TRUE (model
, x
, GT_EXPR
, y
);
3673 ASSERT_CONDITION_TRUE (model
, x
, GE_EXPR
, y
);
3674 ASSERT_CONDITION_TRUE (model
, x
, NE_EXPR
, y
);
3675 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, y
);
3676 ASSERT_CONDITION_FALSE (model
, x
, LT_EXPR
, y
);
3677 ASSERT_CONDITION_FALSE (model
, x
, LE_EXPR
, y
);
3679 /* Swapped operands. */
3680 ASSERT_CONDITION_FALSE (model
, y
, GT_EXPR
, x
);
3681 ASSERT_CONDITION_FALSE (model
, y
, GE_EXPR
, x
);
3682 ASSERT_CONDITION_TRUE (model
, y
, NE_EXPR
, x
);
3683 ASSERT_CONDITION_FALSE (model
, y
, EQ_EXPR
, x
);
3684 ASSERT_CONDITION_TRUE (model
, y
, LT_EXPR
, x
);
3685 ASSERT_CONDITION_TRUE (model
, y
, LE_EXPR
, x
);
3690 region_model_manager mgr
;
3691 region_model
model (&mgr
);
3693 ADD_SAT_CONSTRAINT (model
, x
, GE_EXPR
, y
);
3695 ASSERT_CONDITION_UNKNOWN (model
, x
, GT_EXPR
, y
);
3696 ASSERT_CONDITION_TRUE (model
, x
, GE_EXPR
, y
);
3697 ASSERT_CONDITION_UNKNOWN (model
, x
, NE_EXPR
, y
);
3698 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, y
);
3699 ASSERT_CONDITION_FALSE (model
, x
, LT_EXPR
, y
);
3700 ASSERT_CONDITION_UNKNOWN (model
, x
, LE_EXPR
, y
);
3702 /* Swapped operands. */
3703 ASSERT_CONDITION_FALSE (model
, y
, GT_EXPR
, x
);
3704 ASSERT_CONDITION_UNKNOWN (model
, y
, GE_EXPR
, x
);
3705 ASSERT_CONDITION_UNKNOWN (model
, y
, NE_EXPR
, x
);
3706 ASSERT_CONDITION_UNKNOWN (model
, y
, EQ_EXPR
, x
);
3707 ASSERT_CONDITION_UNKNOWN (model
, y
, LT_EXPR
, x
);
3708 ASSERT_CONDITION_TRUE (model
, y
, LE_EXPR
, x
);
3711 // TODO: implied orderings
3715 region_model_manager mgr
;
3716 region_model
model (&mgr
);
3717 ASSERT_CONDITION_FALSE (model
, int_0
, EQ_EXPR
, int_42
);
3718 ASSERT_CONDITION_TRUE (model
, int_0
, NE_EXPR
, int_42
);
3719 ASSERT_CONDITION_TRUE (model
, int_0
, LT_EXPR
, int_42
);
3720 ASSERT_CONDITION_TRUE (model
, int_0
, LE_EXPR
, int_42
);
3721 ASSERT_CONDITION_FALSE (model
, int_0
, GT_EXPR
, int_42
);
3722 ASSERT_CONDITION_FALSE (model
, int_0
, GE_EXPR
, int_42
);
3725 /* x == 0, y == 42. */
3727 region_model_manager mgr
;
3728 region_model
model (&mgr
);
3729 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, int_0
);
3730 ADD_SAT_CONSTRAINT (model
, y
, EQ_EXPR
, int_42
);
3732 ASSERT_CONDITION_TRUE (model
, x
, NE_EXPR
, y
);
3733 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, y
);
3734 ASSERT_CONDITION_TRUE (model
, x
, LE_EXPR
, y
);
3735 ASSERT_CONDITION_FALSE (model
, x
, GE_EXPR
, y
);
3736 ASSERT_CONDITION_TRUE (model
, x
, LT_EXPR
, y
);
3737 ASSERT_CONDITION_FALSE (model
, x
, GT_EXPR
, y
);
3740 /* Unsatisfiable combinations. */
3742 /* x == y && x != y. */
3744 region_model_manager mgr
;
3745 region_model
model (&mgr
);
3746 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, y
);
3747 ADD_UNSAT_CONSTRAINT (model
, x
, NE_EXPR
, y
);
3750 /* x == 0 then x == 42. */
3752 region_model_manager mgr
;
3753 region_model
model (&mgr
);
3754 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, int_0
);
3755 ADD_UNSAT_CONSTRAINT (model
, x
, EQ_EXPR
, int_42
);
3758 /* x == 0 then x != 0. */
3760 region_model_manager mgr
;
3761 region_model
model (&mgr
);
3762 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, int_0
);
3763 ADD_UNSAT_CONSTRAINT (model
, x
, NE_EXPR
, int_0
);
3766 /* x == 0 then x > 0. */
3768 region_model_manager mgr
;
3769 region_model
model (&mgr
);
3770 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, int_0
);
3771 ADD_UNSAT_CONSTRAINT (model
, x
, GT_EXPR
, int_0
);
3774 /* x != y && x == y. */
3776 region_model_manager mgr
;
3777 region_model
model (&mgr
);
3778 ADD_SAT_CONSTRAINT (model
, x
, NE_EXPR
, y
);
3779 ADD_UNSAT_CONSTRAINT (model
, x
, EQ_EXPR
, y
);
3782 /* x <= y && x > y. */
3784 region_model_manager mgr
;
3785 region_model
model (&mgr
);
3786 ADD_SAT_CONSTRAINT (model
, x
, LE_EXPR
, y
);
3787 ADD_UNSAT_CONSTRAINT (model
, x
, GT_EXPR
, y
);
3793 /* Test transitivity of conditions. */
3796 test_transitivity ()
3798 tree a
= build_global_decl ("a", integer_type_node
);
3799 tree b
= build_global_decl ("b", integer_type_node
);
3800 tree c
= build_global_decl ("c", integer_type_node
);
3801 tree d
= build_global_decl ("d", integer_type_node
);
3803 /* a == b, then c == d, then c == b. */
3805 region_model_manager mgr
;
3806 region_model
model (&mgr
);
3807 ASSERT_CONDITION_UNKNOWN (model
, a
, EQ_EXPR
, b
);
3808 ASSERT_CONDITION_UNKNOWN (model
, b
, EQ_EXPR
, c
);
3809 ASSERT_CONDITION_UNKNOWN (model
, c
, EQ_EXPR
, d
);
3810 ASSERT_CONDITION_UNKNOWN (model
, a
, EQ_EXPR
, d
);
3812 ADD_SAT_CONSTRAINT (model
, a
, EQ_EXPR
, b
);
3813 ASSERT_CONDITION_TRUE (model
, a
, EQ_EXPR
, b
);
3815 ADD_SAT_CONSTRAINT (model
, c
, EQ_EXPR
, d
);
3816 ASSERT_CONDITION_TRUE (model
, c
, EQ_EXPR
, d
);
3817 ASSERT_CONDITION_UNKNOWN (model
, a
, EQ_EXPR
, d
);
3819 ADD_SAT_CONSTRAINT (model
, c
, EQ_EXPR
, b
);
3820 ASSERT_CONDITION_TRUE (model
, c
, EQ_EXPR
, b
);
3821 ASSERT_CONDITION_TRUE (model
, a
, EQ_EXPR
, d
);
3824 /* Transitivity: "a < b", "b < c" should imply "a < c". */
3826 region_model_manager mgr
;
3827 region_model
model (&mgr
);
3828 ADD_SAT_CONSTRAINT (model
, a
, LT_EXPR
, b
);
3829 ADD_SAT_CONSTRAINT (model
, b
, LT_EXPR
, c
);
3831 ASSERT_CONDITION_TRUE (model
, a
, LT_EXPR
, c
);
3832 ASSERT_CONDITION_FALSE (model
, a
, EQ_EXPR
, c
);
3835 /* Transitivity: "a <= b", "b < c" should imply "a < c". */
3837 region_model_manager mgr
;
3838 region_model
model (&mgr
);
3839 ADD_SAT_CONSTRAINT (model
, a
, LE_EXPR
, b
);
3840 ADD_SAT_CONSTRAINT (model
, b
, LT_EXPR
, c
);
3842 ASSERT_CONDITION_TRUE (model
, a
, LT_EXPR
, c
);
3843 ASSERT_CONDITION_FALSE (model
, a
, EQ_EXPR
, c
);
3846 /* Transitivity: "a <= b", "b <= c" should imply "a <= c". */
3848 region_model_manager mgr
;
3849 region_model
model (&mgr
);
3850 ADD_SAT_CONSTRAINT (model
, a
, LE_EXPR
, b
);
3851 ADD_SAT_CONSTRAINT (model
, b
, LE_EXPR
, c
);
3853 ASSERT_CONDITION_TRUE (model
, a
, LE_EXPR
, c
);
3854 ASSERT_CONDITION_UNKNOWN (model
, a
, EQ_EXPR
, c
);
3857 /* Transitivity: "a > b", "b > c" should imply "a > c". */
3859 region_model_manager mgr
;
3860 region_model
model (&mgr
);
3861 ADD_SAT_CONSTRAINT (model
, a
, GT_EXPR
, b
);
3862 ADD_SAT_CONSTRAINT (model
, b
, GT_EXPR
, c
);
3864 ASSERT_CONDITION_TRUE (model
, a
, GT_EXPR
, c
);
3865 ASSERT_CONDITION_FALSE (model
, a
, EQ_EXPR
, c
);
3868 /* Transitivity: "a >= b", "b > c" should imply " a > c". */
3870 region_model_manager mgr
;
3871 region_model
model (&mgr
);
3872 ADD_SAT_CONSTRAINT (model
, a
, GE_EXPR
, b
);
3873 ADD_SAT_CONSTRAINT (model
, b
, GT_EXPR
, c
);
3875 ASSERT_CONDITION_TRUE (model
, a
, GT_EXPR
, c
);
3876 ASSERT_CONDITION_FALSE (model
, a
, EQ_EXPR
, c
);
3879 /* Transitivity: "a >= b", "b >= c" should imply "a >= c". */
3881 region_model_manager mgr
;
3882 region_model
model (&mgr
);
3883 ADD_SAT_CONSTRAINT (model
, a
, GE_EXPR
, b
);
3884 ADD_SAT_CONSTRAINT (model
, b
, GE_EXPR
, c
);
3886 ASSERT_CONDITION_TRUE (model
, a
, GE_EXPR
, c
);
3887 ASSERT_CONDITION_UNKNOWN (model
, a
, EQ_EXPR
, c
);
3890 /* Transitivity: "(a < b)", "(c < d)", "(b < c)" should
3891 imply the easy cases:
3897 region_model_manager mgr
;
3898 region_model
model (&mgr
);
3899 ADD_SAT_CONSTRAINT (model
, a
, LT_EXPR
, b
);
3900 ADD_SAT_CONSTRAINT (model
, c
, LT_EXPR
, d
);
3901 ADD_SAT_CONSTRAINT (model
, b
, LT_EXPR
, c
);
3903 ASSERT_CONDITION_TRUE (model
, a
, LT_EXPR
, c
);
3904 ASSERT_CONDITION_TRUE (model
, b
, LT_EXPR
, d
);
3905 ASSERT_CONDITION_TRUE (model
, a
, LT_EXPR
, d
);
3908 /* Transitivity: "a >= b", "b >= a" should imply that a == b. */
3910 region_model_manager mgr
;
3911 region_model
model (&mgr
);
3912 ADD_SAT_CONSTRAINT (model
, a
, GE_EXPR
, b
);
3913 ADD_SAT_CONSTRAINT (model
, b
, GE_EXPR
, a
);
3916 ASSERT_CONDITION_TRUE (model
, a
, EQ_EXPR
, b
);
3918 /* The ECs for a and b should have merged, and any constraints removed. */
3919 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 1);
3920 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 0);
3923 /* Transitivity: "a >= b", "b > a" should be impossible. */
3925 region_model_manager mgr
;
3926 region_model
model (&mgr
);
3927 ADD_SAT_CONSTRAINT (model
, a
, GE_EXPR
, b
);
3928 ADD_UNSAT_CONSTRAINT (model
, b
, GT_EXPR
, a
);
3931 /* Transitivity: "a >= b", "b >= c", "c >= a" should imply
3932 that a == b == c. */
3934 region_model_manager mgr
;
3935 region_model
model (&mgr
);
3936 ADD_SAT_CONSTRAINT (model
, a
, GE_EXPR
, b
);
3937 ADD_SAT_CONSTRAINT (model
, b
, GE_EXPR
, c
);
3938 ADD_SAT_CONSTRAINT (model
, c
, GE_EXPR
, a
);
3940 ASSERT_CONDITION_TRUE (model
, a
, EQ_EXPR
, c
);
3943 /* Transitivity: "a > b", "b > c", "c > a"
3944 should be impossible. */
3946 region_model_manager mgr
;
3947 region_model
model (&mgr
);
3948 ADD_SAT_CONSTRAINT (model
, a
, GT_EXPR
, b
);
3949 ADD_SAT_CONSTRAINT (model
, b
, GT_EXPR
, c
);
3950 ADD_UNSAT_CONSTRAINT (model
, c
, GT_EXPR
, a
);
3955 /* Test various conditionals involving constants where the results
3956 ought to be implied based on the values of the constants. */
3959 test_constant_comparisons ()
3961 tree int_1
= integer_one_node
;
3962 tree int_3
= build_int_cst (integer_type_node
, 3);
3963 tree int_4
= build_int_cst (integer_type_node
, 4);
3964 tree int_5
= build_int_cst (integer_type_node
, 5);
3966 tree int_1023
= build_int_cst (integer_type_node
, 1023);
3967 tree int_1024
= build_int_cst (integer_type_node
, 1024);
3969 tree a
= build_global_decl ("a", integer_type_node
);
3970 tree b
= build_global_decl ("b", integer_type_node
);
3972 tree a_plus_one
= build2 (PLUS_EXPR
, integer_type_node
, a
, int_1
);
3974 /* Given a >= 1024, then a <= 1023 should be impossible. */
3976 region_model_manager mgr
;
3977 region_model
model (&mgr
);
3978 ADD_SAT_CONSTRAINT (model
, a
, GE_EXPR
, int_1024
);
3979 ADD_UNSAT_CONSTRAINT (model
, a
, LE_EXPR
, int_1023
);
3984 region_model_manager mgr
;
3985 region_model
model (&mgr
);
3986 ADD_SAT_CONSTRAINT (model
, a
, GT_EXPR
, int_4
);
3987 ASSERT_CONDITION_TRUE (model
, a
, GT_EXPR
, int_4
);
3988 ASSERT_CONDITION_TRUE (model
, a
, NE_EXPR
, int_3
);
3989 ASSERT_CONDITION_UNKNOWN (model
, a
, NE_EXPR
, int_5
);
3994 region_model_manager mgr
;
3995 region_model
model (&mgr
);
3996 ADD_SAT_CONSTRAINT (model
, a
, LE_EXPR
, int_4
);
3997 ASSERT_CONDITION_FALSE (model
, a
, GT_EXPR
, int_4
);
3998 ASSERT_CONDITION_FALSE (model
, a
, GT_EXPR
, int_5
);
3999 ASSERT_CONDITION_UNKNOWN (model
, a
, NE_EXPR
, int_3
);
4002 /* If "a > b" and "a == 3", then "b == 4" ought to be unsatisfiable. */
4004 region_model_manager mgr
;
4005 region_model
model (&mgr
);
4006 ADD_SAT_CONSTRAINT (model
, a
, GT_EXPR
, b
);
4007 ADD_SAT_CONSTRAINT (model
, a
, EQ_EXPR
, int_3
);
4008 ADD_UNSAT_CONSTRAINT (model
, b
, EQ_EXPR
, int_4
);
4011 /* Various tests of int ranges where there is only one possible candidate. */
4013 /* If "a <= 4" && "a > 3", then "a == 4",
4014 assuming a is of integral type. */
4016 region_model_manager mgr
;
4017 region_model
model (&mgr
);
4018 ADD_SAT_CONSTRAINT (model
, a
, LE_EXPR
, int_4
);
4019 ADD_SAT_CONSTRAINT (model
, a
, GT_EXPR
, int_3
);
4020 ASSERT_CONDITION_TRUE (model
, a
, EQ_EXPR
, int_4
);
4023 /* If "a > 3" && "a <= 4", then "a == 4",
4024 assuming a is of integral type. */
4026 region_model_manager mgr
;
4027 region_model
model (&mgr
);
4028 ADD_SAT_CONSTRAINT (model
, a
, GT_EXPR
, int_3
);
4029 ADD_SAT_CONSTRAINT (model
, a
, LE_EXPR
, int_4
);
4030 ASSERT_CONDITION_TRUE (model
, a
, EQ_EXPR
, int_4
);
4032 /* If "a > 3" && "a < 5", then "a == 4",
4033 assuming a is of integral type. */
4035 region_model_manager mgr
;
4036 region_model
model (&mgr
);
4037 ADD_SAT_CONSTRAINT (model
, a
, GT_EXPR
, int_3
);
4038 ADD_SAT_CONSTRAINT (model
, a
, LT_EXPR
, int_5
);
4039 ASSERT_CONDITION_TRUE (model
, a
, EQ_EXPR
, int_4
);
4041 /* If "a >= 4" && "a < 5", then "a == 4",
4042 assuming a is of integral type. */
4044 region_model_manager mgr
;
4045 region_model
model (&mgr
);
4046 ADD_SAT_CONSTRAINT (model
, a
, GE_EXPR
, int_4
);
4047 ADD_SAT_CONSTRAINT (model
, a
, LT_EXPR
, int_5
);
4048 ASSERT_CONDITION_TRUE (model
, a
, EQ_EXPR
, int_4
);
4050 /* If "a >= 4" && "a <= 4", then "a == 4". */
4052 region_model_manager mgr
;
4053 region_model
model (&mgr
);
4054 ADD_SAT_CONSTRAINT (model
, a
, GE_EXPR
, int_4
);
4055 ADD_SAT_CONSTRAINT (model
, a
, LE_EXPR
, int_4
);
4056 ASSERT_CONDITION_TRUE (model
, a
, EQ_EXPR
, int_4
);
4060 /* As above, but for floating-point:
4061 if "f > 3" && "f <= 4" we don't know that f == 4. */
4063 tree f
= build_global_decl ("f", double_type_node
);
4064 tree float_3
= build_real_from_int_cst (double_type_node
, int_3
);
4065 tree float_4
= build_real_from_int_cst (double_type_node
, int_4
);
4067 region_model_manager mgr
;
4068 region_model
model (&mgr
);
4069 ADD_SAT_CONSTRAINT (model
, f
, GT_EXPR
, float_3
);
4070 ADD_SAT_CONSTRAINT (model
, f
, LE_EXPR
, float_4
);
4071 ASSERT_CONDITION_UNKNOWN (model
, f
, EQ_EXPR
, float_4
);
4072 ASSERT_CONDITION_UNKNOWN (model
, f
, EQ_EXPR
, int_4
);
4075 /* "a > 3 && a <= 3" should be impossible. */
4077 region_model_manager mgr
;
4078 region_model
model (&mgr
);
4079 ADD_SAT_CONSTRAINT (model
, a
, GT_EXPR
, int_3
);
4080 ADD_UNSAT_CONSTRAINT (model
, a
, LE_EXPR
, int_3
);
4083 /* "(a + 1) > 3 && a < 3" should be impossible. */
4085 region_model_manager mgr
;
4087 region_model
model (&mgr
);
4088 ADD_SAT_CONSTRAINT (model
, a_plus_one
, GT_EXPR
, int_3
);
4089 ADD_UNSAT_CONSTRAINT (model
, a
, LT_EXPR
, int_3
);
4092 region_model
model (&mgr
);
4093 ADD_SAT_CONSTRAINT (model
, a
, LT_EXPR
, int_3
);
4094 ADD_UNSAT_CONSTRAINT (model
, a_plus_one
, GT_EXPR
, int_3
);
4098 /* "3 < a < 4" should be impossible for integer a. */
4100 region_model_manager mgr
;
4102 region_model
model (&mgr
);
4103 ADD_SAT_CONSTRAINT (model
, int_3
, LT_EXPR
, a
);
4104 ADD_UNSAT_CONSTRAINT (model
, a
, LT_EXPR
, int_4
);
4107 region_model
model (&mgr
);
4108 ADD_SAT_CONSTRAINT (model
, int_1
, LT_EXPR
, a
);
4109 ADD_SAT_CONSTRAINT (model
, int_3
, LT_EXPR
, a
);
4110 ADD_SAT_CONSTRAINT (model
, a
, LT_EXPR
, int_5
);
4111 ADD_UNSAT_CONSTRAINT (model
, a
, LT_EXPR
, int_4
);
4114 region_model
model (&mgr
);
4115 ADD_SAT_CONSTRAINT (model
, int_1
, LT_EXPR
, a
);
4116 ADD_SAT_CONSTRAINT (model
, a
, LT_EXPR
, int_5
);
4117 ADD_SAT_CONSTRAINT (model
, int_3
, LT_EXPR
, a
);
4118 ADD_UNSAT_CONSTRAINT (model
, a
, LT_EXPR
, int_4
);
4121 region_model
model (&mgr
);
4122 ADD_SAT_CONSTRAINT (model
, a
, LT_EXPR
, int_4
);
4123 ADD_UNSAT_CONSTRAINT (model
, int_3
, LT_EXPR
, a
);
4126 region_model
model (&mgr
);
4127 ADD_SAT_CONSTRAINT (model
, a
, GT_EXPR
, int_3
);
4128 ADD_UNSAT_CONSTRAINT (model
, int_4
, GT_EXPR
, a
);
4131 region_model
model (&mgr
);
4132 ADD_SAT_CONSTRAINT (model
, int_4
, GT_EXPR
, a
);
4133 ADD_UNSAT_CONSTRAINT (model
, a
, GT_EXPR
, int_3
);
4138 /* Verify various lower-level implementation details about
4139 constraint_manager. */
4142 test_constraint_impl ()
4144 tree int_42
= build_int_cst (integer_type_node
, 42);
4145 tree int_0
= integer_zero_node
;
4147 tree x
= build_global_decl ("x", integer_type_node
);
4148 tree y
= build_global_decl ("y", integer_type_node
);
4149 tree z
= build_global_decl ("z", integer_type_node
);
4153 region_model_manager mgr
;
4154 region_model
model (&mgr
);
4156 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, y
);
4158 /* Assert various things about the insides of model. */
4159 constraint_manager
*cm
= model
.get_constraints ();
4160 ASSERT_EQ (cm
->m_constraints
.length (), 0);
4161 ASSERT_EQ (cm
->m_equiv_classes
.length (), 1);
4164 /* y <= z; x == y. */
4166 region_model_manager mgr
;
4167 region_model
model (&mgr
);
4168 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, y
);
4169 ASSERT_CONDITION_UNKNOWN (model
, x
, GE_EXPR
, z
);
4171 ADD_SAT_CONSTRAINT (model
, y
, GE_EXPR
, z
);
4172 ASSERT_CONDITION_TRUE (model
, y
, GE_EXPR
, z
);
4173 ASSERT_CONDITION_UNKNOWN (model
, x
, GE_EXPR
, z
);
4175 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, y
);
4177 /* Assert various things about the insides of model. */
4178 constraint_manager
*cm
= model
.get_constraints ();
4179 ASSERT_EQ (cm
->m_constraints
.length (), 1);
4180 ASSERT_EQ (cm
->m_equiv_classes
.length (), 2);
4182 /* Ensure that we merged the constraints. */
4183 ASSERT_CONDITION_TRUE (model
, x
, GE_EXPR
, z
);
4186 /* y <= z; y == x. */
4188 region_model_manager mgr
;
4189 region_model
model (&mgr
);
4190 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, y
);
4191 ASSERT_CONDITION_UNKNOWN (model
, x
, GE_EXPR
, z
);
4193 ADD_SAT_CONSTRAINT (model
, y
, GE_EXPR
, z
);
4194 ASSERT_CONDITION_TRUE (model
, y
, GE_EXPR
, z
);
4195 ASSERT_CONDITION_UNKNOWN (model
, x
, GE_EXPR
, z
);
4197 ADD_SAT_CONSTRAINT (model
, y
, EQ_EXPR
, x
);
4199 /* Assert various things about the insides of model. */
4200 constraint_manager
*cm
= model
.get_constraints ();
4201 ASSERT_EQ (cm
->m_constraints
.length (), 1);
4202 ASSERT_EQ (cm
->m_equiv_classes
.length (), 2);
4204 /* Ensure that we merged the constraints. */
4205 ASSERT_CONDITION_TRUE (model
, x
, GE_EXPR
, z
);
4208 /* x == 0, then x != 42. */
4210 region_model_manager mgr
;
4211 region_model
model (&mgr
);
4213 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, int_0
);
4214 ADD_SAT_CONSTRAINT (model
, x
, NE_EXPR
, int_42
);
4216 /* Assert various things about the insides of model. */
4217 constraint_manager
*cm
= model
.get_constraints ();
4218 ASSERT_EQ (cm
->m_constraints
.length (), 0);
4219 ASSERT_EQ (cm
->m_equiv_classes
.length (), 1);
4222 // TODO: selftest for merging ecs "in the middle"
4223 // where a non-final one gets overwritten
4225 // TODO: selftest where there are pre-existing constraints
4228 /* Check that operator== and hashing works as expected for the
4234 tree x
= build_global_decl ("x", integer_type_node
);
4235 tree y
= build_global_decl ("y", integer_type_node
);
4238 region_model_manager mgr
;
4239 region_model
model0 (&mgr
);
4240 region_model
model1 (&mgr
);
4242 constraint_manager
*cm0
= model0
.get_constraints ();
4243 constraint_manager
*cm1
= model1
.get_constraints ();
4245 ASSERT_EQ (cm0
->hash (), cm1
->hash ());
4246 ASSERT_EQ (*cm0
, *cm1
);
4248 ASSERT_EQ (model0
.hash (), model1
.hash ());
4249 ASSERT_EQ (model0
, model1
);
4251 ADD_SAT_CONSTRAINT (model1
, x
, EQ_EXPR
, y
);
4252 ASSERT_NE (cm0
->hash (), cm1
->hash ());
4253 ASSERT_NE (*cm0
, *cm1
);
4255 ASSERT_NE (model0
.hash (), model1
.hash ());
4256 ASSERT_NE (model0
, model1
);
4258 region_model
model2 (&mgr
);
4259 constraint_manager
*cm2
= model2
.get_constraints ();
4260 /* Make the same change to cm2. */
4261 ADD_SAT_CONSTRAINT (model2
, x
, EQ_EXPR
, y
);
4262 ASSERT_EQ (cm1
->hash (), cm2
->hash ());
4263 ASSERT_EQ (*cm1
, *cm2
);
4265 ASSERT_EQ (model1
.hash (), model2
.hash ());
4266 ASSERT_EQ (model1
, model2
);
4270 /* Verify tracking inequality of a variable against many constants. */
4273 test_many_constants ()
4275 region_model_manager mgr
;
4276 program_point
point (program_point::origin (mgr
));
4277 tree a
= build_global_decl ("a", integer_type_node
);
4279 region_model
model (&mgr
);
4280 auto_vec
<tree
> constants
;
4281 for (int i
= 0; i
< 20; i
++)
4283 tree constant
= build_int_cst (integer_type_node
, i
);
4284 constants
.safe_push (constant
);
4285 ADD_SAT_CONSTRAINT (model
, a
, NE_EXPR
, constant
);
4287 /* Merge, and check the result. */
4288 region_model
other (model
);
4290 region_model
merged (&mgr
);
4291 ASSERT_TRUE (model
.can_merge_with_p (other
, point
, &merged
));
4292 model
.canonicalize ();
4293 merged
.canonicalize ();
4294 ASSERT_EQ (model
, merged
);
4296 for (int j
= 0; j
<= i
; j
++)
4297 ASSERT_CONDITION_TRUE (model
, a
, NE_EXPR
, constants
[j
]);
4301 /* Verify that purging state relating to a variable doesn't leave stray
4302 equivalence classes (after canonicalization). */
4307 tree int_0
= integer_zero_node
;
4308 tree a
= build_global_decl ("a", integer_type_node
);
4309 tree b
= build_global_decl ("b", integer_type_node
);
4313 region_model_manager mgr
;
4314 region_model
model (&mgr
);
4315 ADD_SAT_CONSTRAINT (model
, a
, NE_EXPR
, int_0
);
4316 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 2);
4317 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 1);
4319 /* Purge state for "a". */
4320 const svalue
*sval_a
= model
.get_rvalue (a
, NULL
);
4321 model
.purge_state_involving (sval_a
, NULL
);
4322 model
.canonicalize ();
4323 /* We should have an empty constraint_manager. */
4324 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 0);
4325 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 0);
4328 /* "a != 0" && "b != 0". */
4330 region_model_manager mgr
;
4331 region_model
model (&mgr
);
4332 ADD_SAT_CONSTRAINT (model
, a
, NE_EXPR
, int_0
);
4333 ADD_SAT_CONSTRAINT (model
, b
, NE_EXPR
, int_0
);
4334 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 3);
4335 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 2);
4337 /* Purge state for "a". */
4338 const svalue
*sval_a
= model
.get_rvalue (a
, NULL
);
4339 model
.purge_state_involving (sval_a
, NULL
);
4340 model
.canonicalize ();
4341 /* We should just have the constraint/ECs involving b != 0. */
4342 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 2);
4343 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 1);
4344 ASSERT_CONDITION_TRUE (model
, b
, NE_EXPR
, int_0
);
4347 /* "a != 0" && "b == 0". */
4349 region_model_manager mgr
;
4350 region_model
model (&mgr
);
4351 ADD_SAT_CONSTRAINT (model
, a
, NE_EXPR
, int_0
);
4352 ADD_SAT_CONSTRAINT (model
, b
, EQ_EXPR
, int_0
);
4353 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 2);
4354 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 1);
4356 /* Purge state for "a". */
4357 const svalue
*sval_a
= model
.get_rvalue (a
, NULL
);
4358 model
.purge_state_involving (sval_a
, NULL
);
4359 model
.canonicalize ();
4360 /* We should just have the EC involving b == 0. */
4361 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 1);
4362 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 0);
4363 ASSERT_CONDITION_TRUE (model
, b
, EQ_EXPR
, int_0
);
4368 region_model_manager mgr
;
4369 region_model
model (&mgr
);
4370 ADD_SAT_CONSTRAINT (model
, a
, EQ_EXPR
, int_0
);
4371 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 1);
4372 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 0);
4374 /* Purge state for "a". */
4375 const svalue
*sval_a
= model
.get_rvalue (a
, NULL
);
4376 model
.purge_state_involving (sval_a
, NULL
);
4377 model
.canonicalize ();
4378 /* We should have an empty constraint_manager. */
4379 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 0);
4380 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 0);
4383 /* "a == 0" && "b != 0". */
4385 region_model_manager mgr
;
4386 region_model
model (&mgr
);
4387 ADD_SAT_CONSTRAINT (model
, a
, EQ_EXPR
, int_0
);
4388 ADD_SAT_CONSTRAINT (model
, b
, NE_EXPR
, int_0
);
4389 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 2);
4390 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 1);
4392 /* Purge state for "a". */
4393 const svalue
*sval_a
= model
.get_rvalue (a
, NULL
);
4394 model
.purge_state_involving (sval_a
, NULL
);
4395 model
.canonicalize ();
4396 /* We should just have the constraint/ECs involving b != 0. */
4397 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 2);
4398 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 1);
4399 ASSERT_CONDITION_TRUE (model
, b
, NE_EXPR
, int_0
);
4402 /* "a == 0" && "b == 0". */
4404 region_model_manager mgr
;
4405 region_model
model (&mgr
);
4406 ADD_SAT_CONSTRAINT (model
, a
, EQ_EXPR
, int_0
);
4407 ADD_SAT_CONSTRAINT (model
, b
, EQ_EXPR
, int_0
);
4408 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 1);
4409 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 0);
4411 /* Purge state for "a". */
4412 const svalue
*sval_a
= model
.get_rvalue (a
, NULL
);
4413 model
.purge_state_involving (sval_a
, NULL
);
4414 model
.canonicalize ();
4415 /* We should just have the EC involving b == 0. */
4416 ASSERT_EQ (model
.get_constraints ()->m_equiv_classes
.length (), 1);
4417 ASSERT_EQ (model
.get_constraints ()->m_constraints
.length (), 0);
4418 ASSERT_CONDITION_TRUE (model
, b
, EQ_EXPR
, int_0
);
4422 /* Implementation detail of ASSERT_DUMP_BOUNDED_RANGES_EQ. */
4425 assert_dump_bounded_range_eq (const location
&loc
,
4426 const bounded_range
&range
,
4427 const char *expected
)
4429 auto_fix_quotes sentinel
;
4431 pp_format_decoder (&pp
) = default_tree_printer
;
4432 range
.dump_to_pp (&pp
, false);
4433 ASSERT_STREQ_AT (loc
, pp_formatted_text (&pp
), expected
);
4436 /* Assert that BR.dump (false) is EXPECTED. */
4438 #define ASSERT_DUMP_BOUNDED_RANGE_EQ(BR, EXPECTED) \
4439 SELFTEST_BEGIN_STMT \
4440 assert_dump_bounded_range_eq ((SELFTEST_LOCATION), (BR), (EXPECTED)); \
4443 /* Verify that bounded_range works as expected. */
4446 test_bounded_range ()
4448 tree u8_0
= build_int_cst (unsigned_char_type_node
, 0);
4449 tree u8_1
= build_int_cst (unsigned_char_type_node
, 1);
4450 tree u8_64
= build_int_cst (unsigned_char_type_node
, 64);
4451 tree u8_128
= build_int_cst (unsigned_char_type_node
, 128);
4452 tree u8_255
= build_int_cst (unsigned_char_type_node
, 255);
4454 tree s8_0
= build_int_cst (signed_char_type_node
, 0);
4455 tree s8_1
= build_int_cst (signed_char_type_node
, 1);
4456 tree s8_2
= build_int_cst (signed_char_type_node
, 2);
4458 bounded_range
br_u8_0 (u8_0
, u8_0
);
4459 ASSERT_DUMP_BOUNDED_RANGE_EQ (br_u8_0
, "0");
4460 ASSERT_TRUE (br_u8_0
.contains_p (u8_0
));
4461 ASSERT_FALSE (br_u8_0
.contains_p (u8_1
));
4462 ASSERT_TRUE (br_u8_0
.contains_p (s8_0
));
4463 ASSERT_FALSE (br_u8_0
.contains_p (s8_1
));
4465 bounded_range
br_u8_0_1 (u8_0
, u8_1
);
4466 ASSERT_DUMP_BOUNDED_RANGE_EQ (br_u8_0_1
, "[0, 1]");
4468 bounded_range
tmp (NULL_TREE
, NULL_TREE
);
4469 ASSERT_TRUE (br_u8_0
.intersects_p (br_u8_0_1
, &tmp
));
4470 ASSERT_DUMP_BOUNDED_RANGE_EQ (tmp
, "0");
4472 bounded_range
br_u8_64_128 (u8_64
, u8_128
);
4473 ASSERT_DUMP_BOUNDED_RANGE_EQ (br_u8_64_128
, "[64, 128]");
4475 ASSERT_FALSE (br_u8_0
.intersects_p (br_u8_64_128
, NULL
));
4476 ASSERT_FALSE (br_u8_64_128
.intersects_p (br_u8_0
, NULL
));
4478 bounded_range
br_u8_128_255 (u8_128
, u8_255
);
4479 ASSERT_DUMP_BOUNDED_RANGE_EQ (br_u8_128_255
, "[128, 255]");
4480 ASSERT_TRUE (br_u8_128_255
.intersects_p (br_u8_64_128
, &tmp
));
4481 ASSERT_DUMP_BOUNDED_RANGE_EQ (tmp
, "128");
4483 bounded_range
br_s8_2 (s8_2
, s8_2
);
4484 ASSERT_DUMP_BOUNDED_RANGE_EQ (br_s8_2
, "2");
4485 bounded_range
br_s8_2_u8_255 (s8_2
, u8_255
);
4486 ASSERT_DUMP_BOUNDED_RANGE_EQ (br_s8_2_u8_255
, "[2, 255]");
4489 /* Implementation detail of ASSERT_DUMP_BOUNDED_RANGES_EQ. */
4492 assert_dump_bounded_ranges_eq (const location
&loc
,
4493 const bounded_ranges
*ranges
,
4494 const char *expected
)
4496 auto_fix_quotes sentinel
;
4498 pp_format_decoder (&pp
) = default_tree_printer
;
4499 ranges
->dump_to_pp (&pp
, false);
4500 ASSERT_STREQ_AT (loc
, pp_formatted_text (&pp
), expected
);
4503 /* Implementation detail of ASSERT_DUMP_BOUNDED_RANGES_EQ. */
4506 assert_dump_bounded_ranges_eq (const location
&loc
,
4507 const bounded_ranges
&ranges
,
4508 const char *expected
)
4510 auto_fix_quotes sentinel
;
4512 pp_format_decoder (&pp
) = default_tree_printer
;
4513 ranges
.dump_to_pp (&pp
, false);
4514 ASSERT_STREQ_AT (loc
, pp_formatted_text (&pp
), expected
);
4517 /* Assert that BRS.dump (false) is EXPECTED. */
4519 #define ASSERT_DUMP_BOUNDED_RANGES_EQ(BRS, EXPECTED) \
4520 SELFTEST_BEGIN_STMT \
4521 assert_dump_bounded_ranges_eq ((SELFTEST_LOCATION), (BRS), (EXPECTED)); \
4524 /* Verify that the bounded_ranges class works as expected. */
4527 test_bounded_ranges ()
4529 bounded_ranges_manager mgr
;
4531 tree ch0
= build_int_cst (unsigned_char_type_node
, 0);
4532 tree ch1
= build_int_cst (unsigned_char_type_node
, 1);
4533 tree ch2
= build_int_cst (unsigned_char_type_node
, 2);
4534 tree ch3
= build_int_cst (unsigned_char_type_node
, 3);
4535 tree ch128
= build_int_cst (unsigned_char_type_node
, 128);
4536 tree ch129
= build_int_cst (unsigned_char_type_node
, 129);
4537 tree ch254
= build_int_cst (unsigned_char_type_node
, 254);
4538 tree ch255
= build_int_cst (unsigned_char_type_node
, 255);
4540 const bounded_ranges
*empty
= mgr
.get_or_create_empty ();
4541 ASSERT_DUMP_BOUNDED_RANGES_EQ (empty
, "{}");
4543 const bounded_ranges
*point0
= mgr
.get_or_create_point (ch0
);
4544 ASSERT_DUMP_BOUNDED_RANGES_EQ (point0
, "{0}");
4546 const bounded_ranges
*point1
= mgr
.get_or_create_point (ch1
);
4547 ASSERT_DUMP_BOUNDED_RANGES_EQ (point1
, "{1}");
4549 const bounded_ranges
*point2
= mgr
.get_or_create_point (ch2
);
4550 ASSERT_DUMP_BOUNDED_RANGES_EQ (point2
, "{2}");
4552 const bounded_ranges
*range0_128
= mgr
.get_or_create_range (ch0
, ch128
);
4553 ASSERT_DUMP_BOUNDED_RANGES_EQ (range0_128
, "{[0, 128]}");
4555 const bounded_ranges
*range0_255
= mgr
.get_or_create_range (ch0
, ch255
);
4556 ASSERT_DUMP_BOUNDED_RANGES_EQ (range0_255
, "{[0, 255]}");
4558 ASSERT_FALSE (empty
->contain_p (ch0
));
4559 ASSERT_FALSE (empty
->contain_p (ch1
));
4560 ASSERT_FALSE (empty
->contain_p (ch255
));
4562 ASSERT_TRUE (point0
->contain_p (ch0
));
4563 ASSERT_FALSE (point0
->contain_p (ch1
));
4564 ASSERT_FALSE (point0
->contain_p (ch255
));
4566 ASSERT_FALSE (point1
->contain_p (ch0
));
4567 ASSERT_TRUE (point1
->contain_p (ch1
));
4568 ASSERT_FALSE (point0
->contain_p (ch255
));
4570 ASSERT_TRUE (range0_128
->contain_p (ch0
));
4571 ASSERT_TRUE (range0_128
->contain_p (ch1
));
4572 ASSERT_TRUE (range0_128
->contain_p (ch128
));
4573 ASSERT_FALSE (range0_128
->contain_p (ch129
));
4574 ASSERT_FALSE (range0_128
->contain_p (ch254
));
4575 ASSERT_FALSE (range0_128
->contain_p (ch255
));
4577 const bounded_ranges
*inv0_128
4578 = mgr
.get_or_create_inverse (range0_128
, unsigned_char_type_node
);
4579 ASSERT_DUMP_BOUNDED_RANGES_EQ (inv0_128
, "{[129, 255]}");
4581 const bounded_ranges
*range128_129
= mgr
.get_or_create_range (ch128
, ch129
);
4582 ASSERT_DUMP_BOUNDED_RANGES_EQ (range128_129
, "{[128, 129]}");
4584 const bounded_ranges
*inv128_129
4585 = mgr
.get_or_create_inverse (range128_129
, unsigned_char_type_node
);
4586 ASSERT_DUMP_BOUNDED_RANGES_EQ (inv128_129
, "{[0, 127], [130, 255]}");
4590 /* Intersection of disjoint ranges should be empty set. */
4591 const bounded_ranges
*intersect0_1
4592 = mgr
.get_or_create_intersection (point0
, point1
);
4593 ASSERT_DUMP_BOUNDED_RANGES_EQ (intersect0_1
, "{}");
4596 /* Various tests of "union of ranges". */
4599 /* Touching points should be merged into a range. */
4600 auto_vec
<const bounded_ranges
*> v
;
4601 v
.safe_push (point0
);
4602 v
.safe_push (point1
);
4603 const bounded_ranges
*union_0_and_1
= mgr
.get_or_create_union (v
);
4604 ASSERT_DUMP_BOUNDED_RANGES_EQ (union_0_and_1
, "{[0, 1]}");
4608 /* Overlapping and out-of-order. */
4609 auto_vec
<const bounded_ranges
*> v
;
4610 v
.safe_push (inv0_128
); // {[129, 255]}
4611 v
.safe_push (range128_129
);
4612 const bounded_ranges
*union_129_255_and_128_129
4613 = mgr
.get_or_create_union (v
);
4614 ASSERT_DUMP_BOUNDED_RANGES_EQ (union_129_255_and_128_129
, "{[128, 255]}");
4618 /* Union of R and inverse(R) should be full range of type. */
4619 auto_vec
<const bounded_ranges
*> v
;
4620 v
.safe_push (range128_129
);
4621 v
.safe_push (inv128_129
);
4622 const bounded_ranges
*union_
= mgr
.get_or_create_union (v
);
4623 ASSERT_DUMP_BOUNDED_RANGES_EQ (union_
, "{[0, 255]}");
4626 /* Union with an endpoint. */
4628 const bounded_ranges
*range2_to_255
4629 = mgr
.get_or_create_range (ch2
, ch255
);
4630 ASSERT_DUMP_BOUNDED_RANGES_EQ (range2_to_255
, "{[2, 255]}");
4631 auto_vec
<const bounded_ranges
*> v
;
4632 v
.safe_push (point0
);
4633 v
.safe_push (point2
);
4634 v
.safe_push (range2_to_255
);
4635 const bounded_ranges
*union_
= mgr
.get_or_create_union (v
);
4636 ASSERT_DUMP_BOUNDED_RANGES_EQ (union_
, "{0, [2, 255]}");
4639 /* Construct from vector of bounded_range. */
4641 auto_vec
<bounded_range
> v
;
4642 v
.safe_push (bounded_range (ch2
, ch2
));
4643 v
.safe_push (bounded_range (ch0
, ch0
));
4644 v
.safe_push (bounded_range (ch2
, ch255
));
4645 bounded_ranges
br (v
);
4646 ASSERT_DUMP_BOUNDED_RANGES_EQ (&br
, "{0, [2, 255]}");
4650 /* Various tests of "inverse". */
4653 const bounded_ranges
*range_1_to_3
= mgr
.get_or_create_range (ch1
, ch3
);
4654 ASSERT_DUMP_BOUNDED_RANGES_EQ (range_1_to_3
, "{[1, 3]}");
4655 const bounded_ranges
*inv
4656 = mgr
.get_or_create_inverse (range_1_to_3
, unsigned_char_type_node
);
4657 ASSERT_DUMP_BOUNDED_RANGES_EQ (inv
, "{0, [4, 255]}");
4660 const bounded_ranges
*range_1_to_255
4661 = mgr
.get_or_create_range (ch1
, ch255
);
4662 ASSERT_DUMP_BOUNDED_RANGES_EQ (range_1_to_255
, "{[1, 255]}");
4663 const bounded_ranges
*inv
4664 = mgr
.get_or_create_inverse (range_1_to_255
, unsigned_char_type_node
);
4665 ASSERT_DUMP_BOUNDED_RANGES_EQ (inv
, "{0}");
4668 const bounded_ranges
*range_0_to_254
4669 = mgr
.get_or_create_range (ch0
, ch254
);
4670 ASSERT_DUMP_BOUNDED_RANGES_EQ (range_0_to_254
, "{[0, 254]}");
4671 const bounded_ranges
*inv
4672 = mgr
.get_or_create_inverse (range_0_to_254
, unsigned_char_type_node
);
4673 ASSERT_DUMP_BOUNDED_RANGES_EQ (inv
, "{255}");
4677 /* "case 'a'-'z': case 'A-Z':" vs "default:", for ASCII. */
4679 tree ch65
= build_int_cst (unsigned_char_type_node
, 65);
4680 tree ch90
= build_int_cst (unsigned_char_type_node
, 90);
4682 tree ch97
= build_int_cst (unsigned_char_type_node
, 97);
4683 tree ch122
= build_int_cst (unsigned_char_type_node
, 122);
4685 const bounded_ranges
*A_to_Z
= mgr
.get_or_create_range (ch65
, ch90
);
4686 ASSERT_DUMP_BOUNDED_RANGES_EQ (A_to_Z
, "{[65, 90]}");
4687 const bounded_ranges
*a_to_z
= mgr
.get_or_create_range (ch97
, ch122
);
4688 ASSERT_DUMP_BOUNDED_RANGES_EQ (a_to_z
, "{[97, 122]}");
4689 auto_vec
<const bounded_ranges
*> v
;
4690 v
.safe_push (A_to_Z
);
4691 v
.safe_push (a_to_z
);
4692 const bounded_ranges
*label_ranges
= mgr
.get_or_create_union (v
);
4693 ASSERT_DUMP_BOUNDED_RANGES_EQ (label_ranges
, "{[65, 90], [97, 122]}");
4694 const bounded_ranges
*default_ranges
4695 = mgr
.get_or_create_inverse (label_ranges
, unsigned_char_type_node
);
4696 ASSERT_DUMP_BOUNDED_RANGES_EQ (default_ranges
,
4697 "{[0, 64], [91, 96], [123, 255]}");
4700 /* Verify ranges from ops. */
4701 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (EQ_EXPR
, ch128
),
4703 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (NE_EXPR
, ch128
),
4704 "{[0, 127], [129, 255]}");
4705 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (LT_EXPR
, ch128
),
4707 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (LE_EXPR
, ch128
),
4709 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (GE_EXPR
, ch128
),
4711 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (GT_EXPR
, ch128
),
4713 /* Ops at endpoints of type ranges. */
4714 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (LE_EXPR
, ch0
),
4716 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (LT_EXPR
, ch0
),
4718 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (NE_EXPR
, ch0
),
4720 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (GE_EXPR
, ch255
),
4722 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (GT_EXPR
, ch255
),
4724 ASSERT_DUMP_BOUNDED_RANGES_EQ (bounded_ranges (NE_EXPR
, ch255
),
4727 /* Verify that instances are consolidated by mgr. */
4728 ASSERT_EQ (mgr
.get_or_create_point (ch0
),
4729 mgr
.get_or_create_point (ch0
));
4730 ASSERT_NE (mgr
.get_or_create_point (ch0
),
4731 mgr
.get_or_create_point (ch1
));
4734 /* Verify that we can handle sufficiently simple bitmasking operations. */
4739 region_model_manager mgr
;
4741 tree int_0
= integer_zero_node
;
4742 tree int_0x80
= build_int_cst (integer_type_node
, 0x80);
4743 tree int_0xff
= build_int_cst (integer_type_node
, 0xff);
4744 tree x
= build_global_decl ("x", integer_type_node
);
4746 tree x_bit_and_0x80
= build2 (BIT_AND_EXPR
, integer_type_node
, x
, int_0x80
);
4747 tree x_bit_and_0xff
= build2 (BIT_AND_EXPR
, integer_type_node
, x
, int_0xff
);
4749 /* "x & 0x80 == 0x80". */
4751 region_model
model (&mgr
);
4752 ADD_SAT_CONSTRAINT (model
, x_bit_and_0x80
, EQ_EXPR
, int_0x80
);
4753 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0
);
4754 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0x80
);
4757 /* "x & 0x80 != 0x80". */
4759 region_model
model (&mgr
);
4760 ADD_SAT_CONSTRAINT (model
, x_bit_and_0x80
, NE_EXPR
, int_0x80
);
4761 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0
);
4762 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0x80
);
4765 /* "x & 0x80 == 0". */
4767 region_model
model (&mgr
);
4769 ADD_SAT_CONSTRAINT (model
, x_bit_and_0x80
, EQ_EXPR
, int_0
);
4770 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0
);
4771 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0x80
);
4774 /* "x & 0x80 != 0". */
4776 region_model
model (&mgr
);
4777 ADD_SAT_CONSTRAINT (model
, x_bit_and_0x80
, NE_EXPR
, int_0
);
4778 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0
);
4779 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0x80
);
4782 /* More that one bit in the mask. */
4784 /* "x & 0xff == 0x80". */
4786 region_model
model (&mgr
);
4787 ADD_SAT_CONSTRAINT (model
, x_bit_and_0xff
, EQ_EXPR
, int_0x80
);
4788 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0
);
4789 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0x80
);
4790 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0xff
);
4793 /* "x & 0xff != 0x80". */
4795 region_model
model (&mgr
);
4796 ADD_SAT_CONSTRAINT (model
, x_bit_and_0xff
, NE_EXPR
, int_0x80
);
4797 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0
);
4798 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0x80
);
4799 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0xff
);
4802 /* "x & 0xff == 0". */
4804 region_model
model (&mgr
);
4806 ADD_SAT_CONSTRAINT (model
, x_bit_and_0xff
, EQ_EXPR
, int_0
);
4807 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0
);
4808 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0x80
);
4809 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0xff
);
4812 /* "x & 0xff != 0". */
4814 region_model
model (&mgr
);
4815 ADD_SAT_CONSTRAINT (model
, x_bit_and_0xff
, NE_EXPR
, int_0
);
4816 ASSERT_CONDITION_FALSE (model
, x
, EQ_EXPR
, int_0
);
4817 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0x80
);
4818 ASSERT_CONDITION_UNKNOWN (model
, x
, EQ_EXPR
, int_0xff
);
4822 /* Run the selftests in this file, temporarily overriding
4823 flag_analyzer_transitivity with TRANSITIVITY. */
4826 run_constraint_manager_tests (bool transitivity
)
4828 int saved_flag_analyzer_transitivity
= flag_analyzer_transitivity
;
4829 flag_analyzer_transitivity
= transitivity
;
4832 test_constraint_conditions ();
4833 if (flag_analyzer_transitivity
)
4835 /* These selftests assume transitivity. */
4836 test_transitivity ();
4838 test_constant_comparisons ();
4839 test_constraint_impl ();
4841 test_many_constants ();
4843 test_bounded_range ();
4844 test_bounded_ranges ();
4847 flag_analyzer_transitivity
= saved_flag_analyzer_transitivity
;
4850 /* Run all of the selftests within this file. */
4853 analyzer_constraint_manager_cc_tests ()
4855 /* Run the tests twice: with and without transitivity. */
4856 run_constraint_manager_tests (true);
4857 run_constraint_manager_tests (false);
4860 } // namespace selftest
4862 #endif /* CHECKING_P */
4866 #endif /* #if ENABLE_ANALYZER */