]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/region-model.cc
analyzer: fix dedupe issue seen with CVE-2005-1689
[thirdparty/gcc.git] / gcc / analyzer / region-model.cc
CommitLineData
757bf1df
DM
1/* Classes for modeling the state of memory.
2 Copyright (C) 2019-2020 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tree.h"
25#include "function.h"
26#include "basic-block.h"
27#include "gimple.h"
28#include "gimple-iterator.h"
29#include "graphviz.h"
30#include "options.h"
31#include "cgraph.h"
32#include "tree-dfa.h"
33#include "stringpool.h"
34#include "convert.h"
35#include "target.h"
36#include "fold-const.h"
37#include "tree-pretty-print.h"
38#include "diagnostic-color.h"
39#include "diagnostic-metadata.h"
40#include "diagnostic-core.h"
41#include "tristate.h"
42#include "selftest.h"
43#include "function.h"
44#include "analyzer/analyzer.h"
45#include "analyzer/analyzer-logging.h"
46#include "ordered-hash-map.h"
47#include "options.h"
48#include "cgraph.h"
49#include "cfg.h"
50#include "digraph.h"
51#include "analyzer/supergraph.h"
52#include "sbitmap.h"
53#include "analyzer/region-model.h"
54#include "analyzer/constraint-manager.h"
55#include "diagnostic-event-id.h"
56#include "analyzer/sm.h"
57#include "diagnostic-event-id.h"
58#include "analyzer/sm.h"
59#include "analyzer/pending-diagnostic.h"
60#include "analyzer/analyzer-selftests.h"
61
62#if ENABLE_ANALYZER
63
64/* Dump T to PP in language-independent form, for debugging/logging/dumping
65 purposes. */
66
67static void
68dump_tree (pretty_printer *pp, tree t)
69{
70 dump_generic_node (pp, t, 0, TDF_SLIM, 0);
71}
72
73/* Dump this path_var to PP (which must support %E for trees).
74
75 Express the stack depth using an "@DEPTH" suffix, so e.g. given
76 void foo (int j);
77 void bar (int i)
78 {
79 foo (i);
80 }
81 then:
82 - the "i" in "bar" would be "(i @ 0)"
83 - the "j" in "foo" would be "(j @ 1)". */
84
85void
86path_var::dump (pretty_printer *pp) const
87{
88PUSH_IGNORE_WFORMAT
89 if (m_tree == NULL_TREE)
90 pp_string (pp, "NULL");
91 if (CONSTANT_CLASS_P (m_tree))
92 pp_printf (pp, "%qE", m_tree);
93 else
94 pp_printf (pp, "(%qE @ %i)", m_tree, m_stack_depth);
95POP_IGNORE_WFORMAT
96}
97
98/* For use in printing a comma-separated list. */
99
100static void
101dump_separator (pretty_printer *pp, bool *is_first)
102{
103 if (!*is_first)
104 pp_string (pp, ", ");
105 *is_first = false;
106}
107
108/* Concrete subclass of constraint_manager that wires it up to a region_model
109 (whilst allowing the constraint_manager and region_model to be somewhat
110 at arms length).
111 TODO: revisit this; maybe put the region_model * into the constraint_manager
112 base class. */
113
114class impl_constraint_manager : public constraint_manager
115{
116 public:
117 impl_constraint_manager (region_model *model)
118 : constraint_manager (),
119 m_model (model)
120 {}
121
122 impl_constraint_manager (const impl_constraint_manager &other,
123 region_model *model)
124 : constraint_manager (other),
125 m_model (model)
126 {}
127
128 constraint_manager *clone (region_model *model) const
129 {
130 return new impl_constraint_manager (*this, model);
131 }
132
133 tree maybe_get_constant (svalue_id sid) const FINAL OVERRIDE
134 {
135 svalue *svalue = m_model->get_svalue (sid);
136 return svalue->maybe_get_constant ();
137 }
138
139 svalue_id get_sid_for_constant (tree cst) const FINAL OVERRIDE
140 {
141 gcc_assert (CONSTANT_CLASS_P (cst));
142 return m_model->get_rvalue (cst, NULL);
143 }
144
145 int get_num_svalues () const FINAL OVERRIDE
146 {
147 return m_model->get_num_svalues ();
148 }
149
150 private:
151 region_model *m_model;
152};
153
154/* class svalue_id. */
155
156/* Print this svalue_id to PP. */
157
158void
159svalue_id::print (pretty_printer *pp) const
160{
161 if (null_p ())
162 pp_printf (pp, "null");
163 else
164 pp_printf (pp, "sv%i", m_idx);
165}
166
167/* Print this svalue_id in .dot format to PP. */
168
169void
170svalue_id::dump_node_name_to_pp (pretty_printer *pp) const
171{
172 gcc_assert (!null_p ());
173 pp_printf (pp, "svalue_%i", m_idx);
174}
175
176/* Assert that this object is valid (w.r.t. MODEL). */
177
178void
179svalue_id::validate (const region_model &model) const
180{
181 gcc_assert (null_p () || m_idx < (int)model.get_num_svalues ());
182}
183
184/* class region_id. */
185
186/* Print this region_id to PP. */
187
188void
189region_id::print (pretty_printer *pp) const
190{
191 if (null_p ())
192 pp_printf (pp, "null");
193 else
194 pp_printf (pp, "r%i", m_idx);
195}
196
197/* Print this region_id in .dot format to PP. */
198
199void
200region_id::dump_node_name_to_pp (pretty_printer *pp) const
201{
202 gcc_assert (!null_p ());
203 pp_printf (pp, "region_%i", m_idx);
204}
205
206/* Assert that this object is valid (w.r.t. MODEL). */
207
208void
209region_id::validate (const region_model &model) const
210{
211 gcc_assert (null_p () || m_idx < (int)model.get_num_regions ());
212}
213
214/* class id_set. */
215
216/* id_set<region_id>'s ctor. */
217
218template<>
219id_set<region_id>::id_set (const region_model *model)
220: m_bitmap (model->get_num_regions ())
221{
222 bitmap_clear (m_bitmap);
223}
224
225/* class svalue and its various subclasses. */
226
227/* class svalue. */
228
229/* svalue's equality operator. Most of the work is done by the
230 a "compare_fields" implementation on each subclass. */
231
232bool
233svalue::operator== (const svalue &other) const
234{
235 enum svalue_kind this_kind = get_kind ();
236 enum svalue_kind other_kind = other.get_kind ();
237 if (this_kind != other_kind)
238 return false;
239
240 if (m_type != other.m_type)
241 return false;
242
243 switch (this_kind)
244 {
245 default:
246 gcc_unreachable ();
247 case SK_REGION:
248 {
249 const region_svalue &this_sub
250 = (const region_svalue &)*this;
251 const region_svalue &other_sub
252 = (const region_svalue &)other;
253 return this_sub.compare_fields (other_sub);
254 }
255 break;
256 case SK_CONSTANT:
257 {
258 const constant_svalue &this_sub
259 = (const constant_svalue &)*this;
260 const constant_svalue &other_sub
261 = (const constant_svalue &)other;
262 return this_sub.compare_fields (other_sub);
263 }
264 break;
265 case SK_UNKNOWN:
266 {
267 const unknown_svalue &this_sub
268 = (const unknown_svalue &)*this;
269 const unknown_svalue &other_sub
270 = (const unknown_svalue &)other;
271 return this_sub.compare_fields (other_sub);
272 }
273 break;
274 case SK_POISONED:
275 {
276 const poisoned_svalue &this_sub
277 = (const poisoned_svalue &)*this;
278 const poisoned_svalue &other_sub
279 = (const poisoned_svalue &)other;
280 return this_sub.compare_fields (other_sub);
281 }
282 break;
283 case SK_SETJMP:
284 {
285 const setjmp_svalue &this_sub
286 = (const setjmp_svalue &)*this;
287 const setjmp_svalue &other_sub
288 = (const setjmp_svalue &)other;
289 return this_sub.compare_fields (other_sub);
290 }
291 break;
292 }
293}
294
295/* Generate a hash value for this svalue. Most of the work is done by the
296 add_to_hash vfunc. */
297
298hashval_t
299svalue::hash () const
300{
301 inchash::hash hstate;
302 if (m_type)
303 hstate.add_int (TYPE_UID (m_type));
304 add_to_hash (hstate);
305 return hstate.end ();
306}
307
308/* Print this svalue and its ID to PP. */
309
310void
311svalue::print (const region_model &model,
312 svalue_id this_sid,
313 pretty_printer *pp) const
314{
315 this_sid.print (pp);
316 pp_string (pp, ": {");
317
318PUSH_IGNORE_WFORMAT
319 if (m_type)
320 {
321 gcc_assert (TYPE_P (m_type));
322 pp_printf (pp, "type: %qT, ", m_type);
323 }
324POP_IGNORE_WFORMAT
325
326 /* vfunc. */
327 print_details (model, this_sid, pp);
328
329 pp_string (pp, "}");
330}
331
332/* Dump this svalue in the form of a .dot record to PP. */
333
334void
335svalue::dump_dot_to_pp (const region_model &model,
336 svalue_id this_sid,
337 pretty_printer *pp) const
338{
339 this_sid.dump_node_name_to_pp (pp);
340 pp_printf (pp, " [label=\"");
341 pp_write_text_to_stream (pp);
342 this_sid.print (pp);
343 pp_string (pp, ": {");
344 print (model, this_sid, pp);
345 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
346 pp_string (pp, "}\"];");
347 pp_newline (pp);
348}
349
350/* Base implementation of svalue::remap_region_ids vfunc. */
351
352void
353svalue::remap_region_ids (const region_id_map &)
354{
355 /* Empty. */
356}
357
358/* Base implementation of svalue::walk_for_canonicalization vfunc. */
359
360void
361svalue::walk_for_canonicalization (canonicalization *) const
362{
363 /* Empty. */
364}
365
366/* Base implementation of svalue::get_child_sid vfunc. */
367
368svalue_id
369svalue::get_child_sid (region *parent ATTRIBUTE_UNUSED,
370 region *child,
371 region_model &model,
372 region_model_context *ctxt ATTRIBUTE_UNUSED)
373{
374 svalue *new_child_value = clone ();
375 if (child->get_type ())
376 new_child_value->m_type = child->get_type ();
377 svalue_id new_child_sid = model.add_svalue (new_child_value);
378 return new_child_sid;
379}
380
381/* If this svalue is a constant_svalue, return the underlying tree constant.
382 Otherwise return NULL_TREE. */
383
384tree
385svalue::maybe_get_constant () const
386{
387 if (const constant_svalue *cst_sval = dyn_cast_constant_svalue ())
388 return cst_sval->get_constant ();
389 else
390 return NULL_TREE;
391}
392
393/* class region_svalue : public svalue. */
394
395/* Compare the fields of this region_svalue with OTHER, returning true
396 if they are equal.
397 For use by svalue::operator==. */
398
399bool
400region_svalue::compare_fields (const region_svalue &other) const
401{
402 return m_rid == other.m_rid;
403}
404
405/* Implementation of svalue::add_to_hash vfunc for region_svalue. */
406
407void
408region_svalue::add_to_hash (inchash::hash &hstate) const
409{
410 inchash::add (m_rid, hstate);
411}
412
413/* Implementation of svalue::print_details vfunc for region_svalue. */
414
415void
416region_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
417 svalue_id this_sid ATTRIBUTE_UNUSED,
418 pretty_printer *pp) const
419{
420 if (m_rid.null_p ())
421 pp_string (pp, "NULL");
422 else
423 {
424 pp_string (pp, "&");
425 m_rid.print (pp);
426 }
427}
428
429/* Implementation of svalue::dump_dot_to_pp for region_svalue. */
430
431void
432region_svalue::dump_dot_to_pp (const region_model &model,
433 svalue_id this_sid,
434 pretty_printer *pp) const
435{
436 svalue::dump_dot_to_pp (model, this_sid, pp);
437
438 /* If non-NULL, add an edge to the pointed-to region. */
439 if (!m_rid.null_p ())
440 {
441 this_sid.dump_node_name_to_pp (pp);
442 pp_string (pp, " -> ");
443 m_rid.dump_node_name_to_pp (pp);
444 pp_string (pp, ";");
445 pp_newline (pp);
446 }
447}
448
449/* Implementation of svalue::remap_region_ids vfunc for region_svalue. */
450
451void
452region_svalue::remap_region_ids (const region_id_map &map)
453{
454 map.update (&m_rid);
455}
456
457/* Merge REGION_SVAL_A and REGION_SVAL_B using MERGER, writing the result
458 into *MERGED_SID. */
459
460void
461region_svalue::merge_values (const region_svalue &region_sval_a,
462 const region_svalue &region_sval_b,
463 svalue_id *merged_sid,
464 tree type,
465 model_merger *merger)
466{
467 region_id a_rid = region_sval_a.get_pointee ();
468 region_id b_rid = region_sval_b.get_pointee ();
469
470 /* Both are non-NULL. */
471 gcc_assert (!a_rid.null_p () && !b_rid.null_p ());
472
473 /* Have these ptr-values already been merged? */
474
475 region_id a_rid_in_m
476 = merger->m_map_regions_from_a_to_m.get_dst_for_src (a_rid);
477 region_id b_rid_in_m
478 = merger->m_map_regions_from_b_to_m.get_dst_for_src (b_rid);
479
480 /* "null_p" here means "we haven't seen this ptr-value before".
481 If we've seen one but not the other, or we have different
482 regions, then the merged ptr has to be "unknown". */
483 if (a_rid_in_m != b_rid_in_m)
484 {
485 svalue *merged_sval = new unknown_svalue (type);
486 *merged_sid = merger->m_merged_model->add_svalue (merged_sval);
487 return;
488 }
489
490 /* Have we seen this yet? If so, reuse the value. */
491 if (!a_rid_in_m.null_p ())
492 {
493 *merged_sid
494 = merger->m_merged_model->get_or_create_ptr_svalue (type, a_rid_in_m);
495 return;
496 }
497
498 /* Otherwise we have A/B regions that haven't been referenced yet. */
499
500 /* Are the regions the "same", when seen from the tree point-of-view.
501 If so, create a merged pointer to it. */
502 path_var pv_a = merger->m_model_a->get_representative_path_var (a_rid);
503 path_var pv_b = merger->m_model_b->get_representative_path_var (b_rid);
504 if (pv_a.m_tree
505 && pv_a == pv_b)
506 {
507 region_id merged_pointee_rid
508 = merger->m_merged_model->get_lvalue (pv_a, NULL);
509 *merged_sid
510 = merger->m_merged_model->get_or_create_ptr_svalue (type,
511 merged_pointee_rid);
512 merger->record_regions (a_rid, b_rid, merged_pointee_rid);
513 return;
514 }
515
516 /* Handle an A/B pair of ptrs that both point at heap regions.
517 If they both have a heap region in the merger model, merge them. */
518 region *region_a = merger->m_model_a->get_region (a_rid);
519 region *region_b = merger->m_model_b->get_region (b_rid);
520 region_id a_parent_rid = region_a->get_parent ();
521 region_id b_parent_rid = region_b->get_parent ();
522 region *parent_region_a = merger->m_model_a->get_region (a_parent_rid);
523 region *parent_region_b = merger->m_model_b->get_region (b_parent_rid);
524 if (parent_region_a
525 && parent_region_b
526 && parent_region_a->get_kind () == RK_HEAP
527 && parent_region_b->get_kind () == RK_HEAP)
528 {
529 /* We have an A/B pair of ptrs that both point at heap regions. */
530 /* presumably we want to see if each A/B heap region already
531 has a merged region, and, if so, is it the same one. */
532 // This check is above
533
534 region_id merged_pointee_rid
535 = merger->m_merged_model->add_new_malloc_region ();
536 *merged_sid
537 = merger->m_merged_model->get_or_create_ptr_svalue
538 (type, merged_pointee_rid);
539 merger->record_regions (a_rid, b_rid, merged_pointee_rid);
540 return;
541 }
542
543 /* Two different non-NULL pointers? Merge to unknown. */
544 svalue *merged_sval = new unknown_svalue (type);
545 *merged_sid = merger->m_merged_model->add_svalue (merged_sval);
546 return;
547}
548
549/* Implementation of svalue::walk_for_canonicalization vfunc for
550 region_svalue. */
551
552void
553region_svalue::walk_for_canonicalization (canonicalization *c) const
554{
555 c->walk_rid (m_rid);
556}
557
558/* Evaluate the condition LHS OP RHS.
559 Subroutine of region_model::eval_condition for when we have a pair of
560 pointers. */
561
562tristate
563region_svalue::eval_condition (region_svalue *lhs,
564 enum tree_code op,
565 region_svalue *rhs)
566{
567 /* See if they point to the same region. */
568 /* TODO: what about child regions where the child is the first child
569 (or descendent)? */
570 region_id lhs_rid = lhs->get_pointee ();
571 region_id rhs_rid = rhs->get_pointee ();
572 switch (op)
573 {
574 default:
575 gcc_unreachable ();
576
577 case EQ_EXPR:
578 if (lhs_rid == rhs_rid)
579 return tristate::TS_TRUE;
580 else
581 return tristate::TS_FALSE;
582 break;
583
584 case NE_EXPR:
585 if (lhs_rid != rhs_rid)
586 return tristate::TS_TRUE;
587 else
588 return tristate::TS_FALSE;
589 break;
590
591 case GE_EXPR:
592 case LE_EXPR:
593 if (lhs_rid == rhs_rid)
594 return tristate::TS_TRUE;
595 break;
596
597 case GT_EXPR:
598 case LT_EXPR:
599 if (lhs_rid == rhs_rid)
600 return tristate::TS_FALSE;
601 break;
602 }
603
604 return tristate::TS_UNKNOWN;
605}
606
607/* class constant_svalue : public svalue. */
608
609/* Compare the fields of this constant_svalue with OTHER, returning true
610 if they are equal.
611 For use by svalue::operator==. */
612
613bool
614constant_svalue::compare_fields (const constant_svalue &other) const
615{
616 return m_cst_expr == other.m_cst_expr;
617}
618
619/* Implementation of svalue::add_to_hash vfunc for constant_svalue. */
620
621void
622constant_svalue::add_to_hash (inchash::hash &hstate) const
623{
624 inchash::add_expr (m_cst_expr, hstate);
625}
626
627/* Merge the CST_SVAL_A and CST_SVAL_B using MERGER, writing the id of
628 the resulting svalue into *MERGED_SID. */
629
630void
631constant_svalue::merge_values (const constant_svalue &cst_sval_a,
632 const constant_svalue &cst_sval_b,
633 svalue_id *merged_sid,
634 model_merger *merger)
635{
636 tree cst_a = cst_sval_a.get_constant ();
637 tree cst_b = cst_sval_b.get_constant ();
638 svalue *merged_sval;
639 if (cst_a == cst_b)
640 {
641 /* If they are the same constant, merge as that constant value. */
642 merged_sval = new constant_svalue (cst_a);
643 }
644 else
645 {
646 /* Otherwise, we have two different constant values.
647 Merge as an unknown value.
648 TODO: impose constraints on the value?
649 (maybe just based on A, to avoid infinite chains) */
650 merged_sval = new unknown_svalue (TREE_TYPE (cst_a));
651 }
652 *merged_sid = merger->m_merged_model->add_svalue (merged_sval);
653}
654
655/* Evaluate the condition LHS OP RHS.
656 Subroutine of region_model::eval_condition for when we have a pair of
657 constants. */
658
659tristate
660constant_svalue::eval_condition (constant_svalue *lhs,
661 enum tree_code op,
662 constant_svalue *rhs)
663{
664 tree lhs_const = lhs->get_constant ();
665 tree rhs_const = rhs->get_constant ();
666
667 gcc_assert (CONSTANT_CLASS_P (lhs_const));
668 gcc_assert (CONSTANT_CLASS_P (rhs_const));
669
670 tree comparison
671 = fold_build2 (op, boolean_type_node, lhs_const, rhs_const);
672 if (comparison == boolean_true_node)
673 return tristate (tristate::TS_TRUE);
674 if (comparison == boolean_false_node)
675 return tristate (tristate::TS_FALSE);
676 return tristate::TS_UNKNOWN;
677}
678
679/* Implementation of svalue::print_details vfunc for constant_svalue. */
680
681void
682constant_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
683 svalue_id this_sid ATTRIBUTE_UNUSED,
684 pretty_printer *pp) const
685{
686PUSH_IGNORE_WFORMAT
687 pp_printf (pp, "%qE", m_cst_expr);
688POP_IGNORE_WFORMAT
689}
690
691/* Implementation of svalue::get_child_sid vfunc for constant_svalue. */
692
693svalue_id
694constant_svalue::get_child_sid (region *parent ATTRIBUTE_UNUSED,
695 region *child,
696 region_model &model,
697 region_model_context *ctxt ATTRIBUTE_UNUSED)
698{
699 /* TODO: handle the all-zeroes case by returning an all-zeroes of the
700 child type. */
701
702 /* Otherwise, we don't have a good way to get a child value out of a
703 constant.
704
705 Handle this case by using an unknown value. */
706 svalue *unknown_sval = new unknown_svalue (child->get_type ());
707 return model.add_svalue (unknown_sval);
708}
709
710/* class unknown_svalue : public svalue. */
711
712/* Compare the fields of this unknown_svalue with OTHER, returning true
713 if they are equal.
714 For use by svalue::operator==. */
715
716bool
717unknown_svalue::compare_fields (const unknown_svalue &) const
718{
719 /* I *think* we want to return true here, in that when comparing
720 two region models, we want two peer unknown_svalue instances
721 to be the "same". */
722 return true;
723}
724
725/* Implementation of svalue::add_to_hash vfunc for unknown_svalue. */
726
727void
728unknown_svalue::add_to_hash (inchash::hash &) const
729{
730 /* Empty. */
731}
732
733/* Implementation of svalue::print_details vfunc for unknown_svalue. */
734
735void
736unknown_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
737 svalue_id this_sid ATTRIBUTE_UNUSED,
738 pretty_printer *pp) const
739{
740 pp_string (pp, "unknown");
741}
742
743/* Get a string for KIND for use in debug dumps. */
744
745const char *
746poison_kind_to_str (enum poison_kind kind)
747{
748 switch (kind)
749 {
750 default:
751 gcc_unreachable ();
752 case POISON_KIND_UNINIT:
753 return "uninit";
754 case POISON_KIND_FREED:
755 return "freed";
756 case POISON_KIND_POPPED_STACK:
757 return "popped stack";
758 }
759}
760
761/* class poisoned_svalue : public svalue. */
762
763/* Compare the fields of this poisoned_svalue with OTHER, returning true
764 if they are equal.
765 For use by svalue::operator==. */
766
767bool
768poisoned_svalue::compare_fields (const poisoned_svalue &other) const
769{
770 return m_kind == other.m_kind;
771}
772
773/* Implementation of svalue::add_to_hash vfunc for poisoned_svalue. */
774
775void
776poisoned_svalue::add_to_hash (inchash::hash &hstate) const
777{
778 hstate.add_int (m_kind);
779}
780
781/* Implementation of svalue::print_details vfunc for poisoned_svalue. */
782
783void
784poisoned_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
785 svalue_id this_sid ATTRIBUTE_UNUSED,
786 pretty_printer *pp) const
787{
788 pp_printf (pp, "poisoned: %s", poison_kind_to_str (m_kind));
789}
790
791/* class setjmp_svalue's implementation is in engine.cc, so that it can use
792 the declaration of exploded_node. */
793
794/* class region and its various subclasses. */
795
796/* Get a string for KIND for use in debug dumps. */
797
798const char *
799region_kind_to_str (enum region_kind kind)
800{
801 switch (kind)
802 {
803 default:
804 gcc_unreachable ();
805 case RK_PRIMITIVE:
806 return "primitive";
807 case RK_STRUCT:
808 return "struct";
809 case RK_UNION:
810 return "union";
811 case RK_ARRAY:
812 return "array";
813 case RK_FRAME:
814 return "frame";
815 case RK_GLOBALS:
816 return "globals";
817 case RK_CODE:
818 return "code";
819 case RK_FUNCTION:
820 return "function";
821 case RK_STACK:
822 return "stack";
823 case RK_HEAP:
824 return "heap";
825 case RK_ROOT:
826 return "root";
827 case RK_SYMBOLIC:
828 return "symbolic";
829 }
830}
831
832/* class region. */
833
834/* Equality operator for region.
835 After comparing base class fields and kind, the rest of the
836 comparison is handled off to a "compare_fields" member function
837 specific to the appropriate subclass. */
838
839bool
840region::operator== (const region &other) const
841{
842 if (m_parent_rid != other.m_parent_rid)
843 return false;
844 if (m_sval_id != other.m_sval_id)
845 return false;
846 if (m_type != other.m_type)
847 return false;
848
849 enum region_kind this_kind = get_kind ();
850 enum region_kind other_kind = other.get_kind ();
851 if (this_kind != other_kind)
852 return false;
853
854 /* Compare views. */
855 if (m_view_rids.length () != other.m_view_rids.length ())
856 return false;
857 int i;
858 region_id *rid;
859 FOR_EACH_VEC_ELT (m_view_rids, i, rid)
860 if (! (*rid == other.m_view_rids[i]))
861 return false;
862
863 switch (this_kind)
864 {
865 default:
866 gcc_unreachable ();
867 case RK_PRIMITIVE:
868 {
869#if 1
870 return true;
871#else
872 const primitive_region &this_sub
873 = (const primitive_region &)*this;
874 const primitive_region &other_sub
875 = (const primitive_region &)other;
876 return this_sub.compare_fields (other_sub);
877#endif
878 }
879 case RK_STRUCT:
880 {
881 const struct_region &this_sub
882 = (const struct_region &)*this;
883 const struct_region &other_sub
884 = (const struct_region &)other;
885 return this_sub.compare_fields (other_sub);
886 }
887 case RK_UNION:
888 {
889 const union_region &this_sub
890 = (const union_region &)*this;
891 const union_region &other_sub
892 = (const union_region &)other;
893 return this_sub.compare_fields (other_sub);
894 }
895 case RK_ARRAY:
896 {
897 const array_region &this_sub
898 = (const array_region &)*this;
899 const array_region &other_sub
900 = (const array_region &)other;
901 return this_sub.compare_fields (other_sub);
902 }
903 case RK_FRAME:
904 {
905 const frame_region &this_sub
906 = (const frame_region &)*this;
907 const frame_region &other_sub
908 = (const frame_region &)other;
909 return this_sub.compare_fields (other_sub);
910 }
911 case RK_GLOBALS:
912 {
913 const globals_region &this_sub
914 = (const globals_region &)*this;
915 const globals_region &other_sub
916 = (const globals_region &)other;
917 return this_sub.compare_fields (other_sub);
918 }
919 case RK_CODE:
920 {
921 const code_region &this_sub
922 = (const code_region &)*this;
923 const code_region &other_sub
924 = (const code_region &)other;
925 return this_sub.compare_fields (other_sub);
926 }
927 case RK_FUNCTION:
928 {
929 const function_region &this_sub
930 = (const function_region &)*this;
931 const function_region &other_sub
932 = (const function_region &)other;
933 return this_sub.compare_fields (other_sub);
934 }
935 case RK_STACK:
936 {
937 const stack_region &this_sub
938 = (const stack_region &)*this;
939 const stack_region &other_sub
940 = (const stack_region &)other;
941 return this_sub.compare_fields (other_sub);
942 }
943 case RK_ROOT:
944 {
945 const root_region &this_sub
946 = (const root_region &)*this;
947 const root_region &other_sub
948 = (const root_region &)other;
949 return this_sub.compare_fields (other_sub);
950 }
951 case RK_SYMBOLIC:
952 {
953 const symbolic_region &this_sub
954 = (const symbolic_region &)*this;
955 const symbolic_region &other_sub
956 = (const symbolic_region &)other;
957 return this_sub.compare_fields (other_sub);
958 }
959 case RK_HEAP:
960 {
961 const heap_region &this_sub
962 = (const heap_region &)*this;
963 const heap_region &other_sub
964 = (const heap_region &)other;
965 return this_sub.compare_fields (other_sub);
966 }
967 }
968}
969
970/* Get the parent region of this region. */
971
972region *
973region::get_parent_region (const region_model &model) const
974{
975 return model.get_region (m_parent_rid);
976}
977
978/* Set this region's value to RHS_SID (or potentially a variant of it,
979 for some kinds of casts). */
980
981void
982region::set_value (region_model &model, region_id this_rid, svalue_id rhs_sid,
983 region_model_context *ctxt)
984{
985 /* Handle some kinds of casting. */
986 if (m_type)
987 {
988 svalue *sval = model.get_svalue (rhs_sid);
989 if (sval->get_type ())
990 rhs_sid = model.maybe_cast (m_type, rhs_sid, ctxt);
991
992 sval = model.get_svalue (rhs_sid);
993 if (sval->get_type ())
994 gcc_assert (m_type == sval->get_type ());
995 }
996
997 m_sval_id = rhs_sid;
998
999 /* Update views.
1000 If this is a view, it becomes its parent's active view.
1001 If there was already an active views, invalidate its value; otherwise
1002 if the parent itself had a value, invalidate it.
1003 If it's not a view, then deactivate any view that is active on this
1004 region. */
1005 {
1006 if (m_is_view)
1007 become_active_view (model, this_rid);
1008 else
1009 {
1010 deactivate_any_active_view (model);
1011 gcc_assert (m_active_view_rid.null_p ());
1012 }
1013 }
1014}
1015
1016/* Make this region (with id THIS_RID) the "active" view of its parent.
1017 Any other active view has its value set to "unknown" and descendent values
1018 cleared.
1019 If there wasn't an active view, then set the parent's value to unknown, and
1020 clear its descendent values (apart from this view). */
1021
1022void
1023region::become_active_view (region_model &model, region_id this_rid)
1024{
1025 gcc_assert (m_is_view);
1026
1027 region *parent_reg = model.get_region (m_parent_rid);
1028 gcc_assert (parent_reg);
1029
1030 region_id old_active_view_rid = parent_reg->m_active_view_rid;
1031
1032 if (old_active_view_rid == this_rid)
1033 {
1034 /* Already the active view: do nothing. */
1035 return;
1036 }
1037
1038 /* We have a change of active view. */
1039 parent_reg->m_active_view_rid = this_rid;
1040
1041 if (old_active_view_rid.null_p ())
1042 {
1043 /* No previous active view, but the parent and its other children
1044 might have values.
1045 If so, invalidate those values - but not that of the new view. */
1046 region_id_set below_region (&model);
1047 model.get_descendents (m_parent_rid, &below_region, this_rid);
1048 for (unsigned i = 0; i < model.get_num_regions (); i++)
1049 {
1050 region_id rid (region_id::from_int (i));
1051 if (below_region.region_p (rid))
1052 {
1053 region *other_reg = model.get_region (rid);
1054 other_reg->m_sval_id = svalue_id::null ();
1055 }
1056 }
1057 region *parent = model.get_region (m_parent_rid);
1058 parent->m_sval_id
1059 = model.add_svalue (new unknown_svalue (parent->get_type ()));
1060 }
1061 else
1062 {
1063 /* If there was an active view, invalidate it. */
1064 region *old_active_view = model.get_region (old_active_view_rid);
1065 old_active_view->deactivate_view (model, old_active_view_rid);
1066 }
1067}
1068
1069/* If this region (with id THIS_RID) has an active view, deactivate it,
1070 clearing m_active_view_rid. */
1071
1072void
1073region::deactivate_any_active_view (region_model &model)
1074{
1075 if (m_active_view_rid.null_p ())
1076 return;
1077 region *view = model.get_region (m_active_view_rid);
1078 view->deactivate_view (model, m_active_view_rid);
1079 m_active_view_rid = region_id::null ();
1080}
1081
1082/* Clear any values for regions below THIS_RID.
1083 Set the view's value to unknown. */
1084
1085void
1086region::deactivate_view (region_model &model, region_id this_view_rid)
1087{
1088 gcc_assert (is_view_p ());
1089
1090 /* Purge values from old_active_this_view_rid and all its
1091 descendents. Potentially we could use a poison value
1092 for this, but let's use unknown for now. */
1093 region_id_set below_view (&model);
1094 model.get_descendents (this_view_rid, &below_view, region_id::null ());
1095
1096 for (unsigned i = 0; i < model.get_num_regions (); i++)
1097 {
1098 region_id rid (region_id::from_int (i));
1099 if (below_view.region_p (rid))
1100 {
1101 region *other_reg = model.get_region (rid);
1102 other_reg->m_sval_id = svalue_id::null ();
1103 }
1104 }
1105
1106 m_sval_id = model.add_svalue (new unknown_svalue (get_type ()));
1107}
1108
1109/* Get a value for this region, either its value if it has one,
1110 or, failing that, "inherit" a value from first ancestor with a
1111 non-null value.
1112
1113 For example, when getting the value for a local variable within
1114 a stack frame that doesn't have one, the frame doesn't have a value
1115 either, but the stack as a whole will have an "uninitialized" poison
1116 value, so inherit that. */
1117
1118svalue_id
1119region::get_value (region_model &model, bool non_null,
1120 region_model_context *ctxt)
1121{
1122 /* If this region has a value, use it. */
1123 if (!m_sval_id.null_p ())
1124 return m_sval_id;
1125
1126 /* Otherwise, "inherit" value from first ancestor with a
1127 non-null value. */
1128
1129 region *parent = model.get_region (m_parent_rid);
1130 if (parent)
1131 {
1132 svalue_id inherited_sid
1133 = parent->get_inherited_child_sid (this, model, ctxt);
1134 if (!inherited_sid.null_p ())
1135 return inherited_sid;
1136 }
1137
1138 /* If a non-null value has been requested, then generate
1139 a new unknown value. Store it, so that repeated reads from this
1140 region will yield the same unknown value. */
1141 if (non_null)
1142 {
1143 svalue_id unknown_sid = model.add_svalue (new unknown_svalue (m_type));
1144 m_sval_id = unknown_sid;
1145 return unknown_sid;
1146 }
1147
1148 return svalue_id::null ();
1149}
1150
1151/* Get a value for CHILD, inheriting from this region.
1152
1153 Recurse, so this region will inherit a value if it doesn't already
1154 have one. */
1155
1156svalue_id
1157region::get_inherited_child_sid (region *child,
1158 region_model &model,
1159 region_model_context *ctxt)
1160{
1161 if (m_sval_id.null_p ())
1162 {
1163 /* Recurse. */
1164 if (!m_parent_rid.null_p ())
1165 {
1166 region *parent = model.get_region (m_parent_rid);
1167 m_sval_id = parent->get_inherited_child_sid (this, model, ctxt);
1168 }
1169 }
1170
1171 if (!m_sval_id.null_p ())
1172 {
1173 /* Clone the parent's value, so that attempts to update it
1174 (e.g giving a specific value to an inherited "uninitialized"
1175 value) touch the child, and not the parent. */
1176 svalue *this_value = model.get_svalue (m_sval_id);
1177 svalue_id new_child_sid
1178 = this_value->get_child_sid (this, child, model, ctxt);
1179 if (ctxt)
1180 ctxt->on_inherited_svalue (m_sval_id, new_child_sid);
1181 child->m_sval_id = new_child_sid;
1182 return new_child_sid;
1183 }
1184
1185 return svalue_id::null ();
1186}
1187
1188/* Generate a hash value for this region. The work is done by the
1189 add_to_hash vfunc. */
1190
1191hashval_t
1192region::hash () const
1193{
1194 inchash::hash hstate;
1195 add_to_hash (hstate);
1196 return hstate.end ();
1197}
1198
1199/* Print a one-liner representation of this region to PP, assuming
1200 that this region is within MODEL and its id is THIS_RID. */
1201
1202void
1203region::print (const region_model &model,
1204 region_id this_rid,
1205 pretty_printer *pp) const
1206{
1207 this_rid.print (pp);
1208 pp_string (pp, ": {");
1209
1210 /* vfunc. */
1211 print_fields (model, this_rid, pp);
1212
1213 pp_string (pp, "}");
1214}
1215
1216/* Base class implementation of region::dump_dot_to_pp vfunc. */
1217
1218void
1219region::dump_dot_to_pp (const region_model &model,
1220 region_id this_rid,
1221 pretty_printer *pp) const
1222{
1223 this_rid.dump_node_name_to_pp (pp);
1224 pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
1225 "lightgrey");
1226 pp_write_text_to_stream (pp);
1227 print (model, this_rid, pp);
1228 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
1229 pp_string (pp, "\"];");
1230 pp_newline (pp);
1231
1232 /* Add edge to svalue. */
1233 if (!m_sval_id.null_p ())
1234 {
1235 this_rid.dump_node_name_to_pp (pp);
1236 pp_string (pp, " -> ");
1237 m_sval_id.dump_node_name_to_pp (pp);
1238 pp_string (pp, ";");
1239 pp_newline (pp);
1240 }
1241
1242 /* Add edge to parent. */
1243 if (!m_parent_rid.null_p ())
1244 {
1245 this_rid.dump_node_name_to_pp (pp);
1246 pp_string (pp, " -> ");
1247 m_parent_rid.dump_node_name_to_pp (pp);
1248 pp_string (pp, ";");
1249 pp_newline (pp);
1250 }
1251}
1252
1253/* Dump a tree-like ASCII-art representation of this region to PP. */
1254
1255void
1256region::dump_to_pp (const region_model &model,
1257 region_id this_rid,
1258 pretty_printer *pp,
1259 const char *prefix,
1260 bool is_last_child) const
1261{
1262 print (model, this_rid, pp);
1263 pp_newline (pp);
1264
1265 const char *new_prefix;
1266 if (!m_parent_rid.null_p ())
1267 new_prefix = ACONCAT ((prefix, is_last_child ? " " : "| ", NULL));
1268 else
1269 new_prefix = prefix;
1270
1271 const char *begin_color = colorize_start (pp_show_color (pp), "note");
1272 const char *end_color = colorize_stop (pp_show_color (pp));
1273 char *field_prefix
1274 = ACONCAT ((begin_color, new_prefix, "|:", end_color, NULL));
1275
1276 if (!m_sval_id.null_p ())
1277 {
1278 pp_printf (pp, "%s sval: ", field_prefix);
1279 model.get_svalue (m_sval_id)->print (model, m_sval_id, pp);
1280 pp_newline (pp);
1281 }
1282 if (m_type)
1283 {
1284PUSH_IGNORE_WFORMAT
1285 pp_printf (pp, "%s type: %qT", field_prefix, m_type);
1286POP_IGNORE_WFORMAT
1287 pp_newline (pp);
1288 }
1289
1290 /* Find the children. */
1291
1292 auto_vec<region_id> child_rids;
1293 unsigned i;
1294 for (unsigned i = 0; i < model.get_num_regions (); ++i)
1295 {
1296 region_id rid = region_id::from_int (i);
1297 region *child = model.get_region (rid);
1298 if (child->m_parent_rid == this_rid)
1299 child_rids.safe_push (rid);
1300 }
1301
1302 /* Print the children, using dump_child_label to label them. */
1303
1304 region_id *child_rid;
1305 FOR_EACH_VEC_ELT (child_rids, i, child_rid)
1306 {
1307 is_last_child = (i == child_rids.length () - 1);
1308 if (!this_rid.null_p ())
1309 {
1310 const char *tail = is_last_child ? "`-" : "|-";
1311 pp_printf (pp, "%r%s%s%R", "note", new_prefix, tail);
1312 }
1313 dump_child_label (model, this_rid, *child_rid, pp);
1314 model.get_region (*child_rid)->dump_to_pp (model, *child_rid, pp,
1315 new_prefix,
1316 is_last_child);
1317 }
1318}
1319
1320/* Base implementation of region::dump_child_label vfunc. */
1321
1322void
1323region::dump_child_label (const region_model &model,
1324 region_id this_rid ATTRIBUTE_UNUSED,
1325 region_id child_rid,
1326 pretty_printer *pp) const
1327{
1328 region *child = model.get_region (child_rid);
1329 if (child->m_is_view)
1330 {
1331 gcc_assert (TYPE_P (child->get_type ()));
1332 if (m_active_view_rid == child_rid)
1333 pp_string (pp, "active ");
1334 else
1335 pp_string (pp, "inactive ");
1336PUSH_IGNORE_WFORMAT
1337 pp_printf (pp, "view as %qT: ", child->get_type ());
1338POP_IGNORE_WFORMAT
1339 }
1340}
1341
1342/* Assert that this object is valid. */
1343
1344void
1345region::validate (const region_model *model) const
1346{
1347 m_parent_rid.validate (*model);
1348 m_sval_id.validate (*model);
1349 unsigned i;
1350 region_id *view_rid;
1351 FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
1352 {
1353 gcc_assert (!view_rid->null_p ());
1354 view_rid->validate (*model);
1355 }
1356 m_active_view_rid.validate (*model);
1357}
1358
1359/* Apply MAP to svalue_ids to this region. This updates the value
1360 for the region (if any). */
1361
1362void
1363region::remap_svalue_ids (const svalue_id_map &map)
1364{
1365 map.update (&m_sval_id);
1366}
1367
1368/* Base implementation of region::remap_region_ids vfunc; subclasses should
1369 chain up to this, updating any region_id data. */
1370
1371void
1372region::remap_region_ids (const region_id_map &map)
1373{
1374 map.update (&m_parent_rid);
1375 unsigned i;
1376 region_id *view_rid;
1377 FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
1378 map.update (view_rid);
1379 map.update (&m_active_view_rid);
1380}
1381
1382/* Add a new region with id VIEW_RID as a view of this region. */
1383
1384void
1385region::add_view (region_id view_rid, region_model *model)
1386{
1387 gcc_assert (!view_rid.null_p ());
1388 region *new_view = model->get_region (view_rid);
1389 new_view->m_is_view = true;
1390 gcc_assert (!new_view->m_parent_rid.null_p ());
1391 gcc_assert (new_view->m_sval_id.null_p ());
1392
1393 //gcc_assert (new_view->get_type () != NULL_TREE);
1394 // TODO: this can sometimes be NULL, when viewing through a (void *)
1395
1396 // TODO: the type ought to not be present yet
1397
1398 m_view_rids.safe_push (view_rid);
1399}
1400
1401/* Look for a view of type TYPE of this region, returning its id if found,
1402 or null otherwise. */
1403
1404region_id
1405region::get_view (tree type, region_model *model) const
1406{
1407 unsigned i;
1408 region_id *view_rid;
1409 FOR_EACH_VEC_ELT (m_view_rids, i, view_rid)
1410 {
1411 region *view = model->get_region (*view_rid);
1412 gcc_assert (view->m_is_view);
1413 if (view->get_type () == type)
1414 return *view_rid;
1415 }
1416 return region_id::null ();
1417}
1418
1419/* region's ctor. */
1420
1421region::region (region_id parent_rid, svalue_id sval_id, tree type)
1422: m_parent_rid (parent_rid), m_sval_id (sval_id), m_type (type),
1423 m_view_rids (), m_is_view (false), m_active_view_rid (region_id::null ())
1424{
1425 gcc_assert (type == NULL_TREE || TYPE_P (type));
1426}
1427
1428/* region's copy ctor. */
1429
1430region::region (const region &other)
1431: m_parent_rid (other.m_parent_rid), m_sval_id (other.m_sval_id),
1432 m_type (other.m_type), m_view_rids (other.m_view_rids.length ()),
1433 m_is_view (other.m_is_view), m_active_view_rid (other.m_active_view_rid)
1434{
1435 int i;
1436 region_id *rid;
1437 FOR_EACH_VEC_ELT (other.m_view_rids, i, rid)
1438 m_view_rids.quick_push (*rid);
1439}
1440
1441/* Base implementation of region::add_to_hash vfunc; subclasses should
1442 chain up to this. */
1443
1444void
1445region::add_to_hash (inchash::hash &hstate) const
1446{
1447 inchash::add (m_parent_rid, hstate);
1448 inchash::add (m_sval_id, hstate);
1449 hstate.add_ptr (m_type);
1450 // TODO: views
1451}
1452
1453/* Base implementation of region::print_fields vfunc. */
1454
1455void
1456region::print_fields (const region_model &model ATTRIBUTE_UNUSED,
1457 region_id this_rid ATTRIBUTE_UNUSED,
1458 pretty_printer *pp) const
1459{
1460 pp_printf (pp, "kind: %qs", region_kind_to_str (get_kind ()));
1461
1462 pp_string (pp, ", parent: ");
1463 m_parent_rid.print (pp);
1464
1465 pp_printf (pp, ", sval: ");
1466 m_sval_id.print (pp);
1467
1468PUSH_IGNORE_WFORMAT
1469 if (m_type)
1470 pp_printf (pp, ", type: %qT", m_type);
1471POP_IGNORE_WFORMAT
1472}
1473
1474/* Determine if a pointer to this region must be non-NULL.
1475
1476 Generally, pointers to regions must be non-NULL, but pointers
1477 to symbolic_regions might, in fact, be NULL.
1478
1479 This allows us to simulate functions like malloc and calloc with:
1480 - only one "outcome" from each statement,
1481 - the idea that the pointer is on the heap if non-NULL
1482 - the possibility that the pointer could be NULL
1483 - the idea that successive values returned from malloc are non-equal
1484 - to be able to zero-fill for calloc. */
1485
1486bool
1487region::non_null_p (const region_model &model) const
1488{
1489 /* Look through views to get at the underlying region. */
1490 if (is_view_p ())
1491 return model.get_region (m_parent_rid)->non_null_p (model);
1492
1493 /* Are we within a symbolic_region? If so, it could be NULL. */
1494 if (const symbolic_region *sym_reg = dyn_cast_symbolic_region ())
1495 {
1496 if (sym_reg->m_possibly_null)
1497 return false;
1498 }
1499
1500 return true;
1501}
1502
1503/* class primitive_region : public region. */
1504
1505/* Implementation of region::clone vfunc for primitive_region. */
1506
1507region *
1508primitive_region::clone () const
1509{
1510 return new primitive_region (*this);
1511}
1512
1513/* Implementation of region::walk_for_canonicalization vfunc for
1514 primitive_region. */
1515
1516void
1517primitive_region::walk_for_canonicalization (canonicalization *) const
1518{
1519 /* Empty. */
1520}
1521
1522/* class map_region : public region. */
1523
1524/* map_region's copy ctor. */
1525
1526map_region::map_region (const map_region &other)
1527: region (other),
1528 m_map (other.m_map)
1529{
1530}
1531
1532/* Compare the fields of this map_region with OTHER, returning true
1533 if they are equal.
1534 For use by region::operator==. */
1535
1536bool
1537map_region::compare_fields (const map_region &other) const
1538{
1539 if (m_map.elements () != other.m_map.elements ())
1540 return false;
1541
1542 for (map_t::iterator iter = m_map.begin ();
1543 iter != m_map.end ();
1544 ++iter)
1545 {
1546 tree key = (*iter).first;
1547 region_id e = (*iter).second;
1548 region_id *other_slot = const_cast <map_t &> (other.m_map).get (key);
1549 if (other_slot == NULL)
1550 return false;
1551 if (e != *other_slot)
1552 return false;
1553 }
1554 return true;
1555}
1556
1557/* Implementation of region::print_fields vfunc for map_region. */
1558
1559void
1560map_region::print_fields (const region_model &model,
1561 region_id this_rid,
1562 pretty_printer *pp) const
1563{
1564 region::print_fields (model, this_rid, pp);
1565 pp_string (pp, ", map: {");
1566 for (map_t::iterator iter = m_map.begin ();
1567 iter != m_map.end ();
1568 ++iter)
1569 {
1570 if (iter != m_map.begin ())
1571 pp_string (pp, ", ");
1572 tree expr = (*iter).first;
1573 region_id child_rid = (*iter).second;
1574PUSH_IGNORE_WFORMAT
1575 pp_printf (pp, "%qE: ", expr);
1576POP_IGNORE_WFORMAT
1577 child_rid.print (pp);
1578 }
1579 pp_string (pp, "}");
1580}
1581
1582/* Implementation of region::dump_dot_to_pp vfunc for map_region. */
1583
1584void
1585map_region::dump_dot_to_pp (const region_model &model,
1586 region_id this_rid,
1587 pretty_printer *pp) const
1588{
1589 region::dump_dot_to_pp (model, this_rid, pp);
1590 for (map_t::iterator iter = m_map.begin ();
1591 iter != m_map.end ();
1592 ++iter)
1593 {
1594 // TODO: add nodes/edges to label things
1595
1596 tree expr = (*iter).first;
1597 region_id child_rid = (*iter).second;
1598
1599 pp_printf (pp, "rid_label_%i [label=\"", child_rid.as_int ());
1600 pp_write_text_to_stream (pp);
1601PUSH_IGNORE_WFORMAT
1602 pp_printf (pp, "%qE", expr);
1603POP_IGNORE_WFORMAT
1604 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
1605 pp_string (pp, "\"];");
1606 pp_newline (pp);
1607
1608 pp_printf (pp, "rid_label_%i", child_rid.as_int ());
1609 pp_string (pp, " -> ");
1610 child_rid.dump_node_name_to_pp (pp);
1611 pp_string (pp, ";");
1612 pp_newline (pp);
1613 }
1614}
1615
1616/* Implementation of region::dump_child_label vfunc for map_region. */
1617
1618void
1619map_region::dump_child_label (const region_model &model,
1620 region_id this_rid,
1621 region_id child_rid,
1622 pretty_printer *pp) const
1623{
1624 region::dump_child_label (model, this_rid, child_rid, pp);
1625
1626 for (map_t::iterator iter = m_map.begin ();
1627 iter != m_map.end ();
1628 ++iter)
1629 {
1630 if (child_rid == (*iter).second)
1631 {
1632 tree key = (*iter).first;
1633PUSH_IGNORE_WFORMAT
1634 if (DECL_P (key))
1635 pp_printf (pp, "%qD: ", key);
1636 else
1637 pp_printf (pp, "%qE: ", key);
1638POP_IGNORE_WFORMAT
1639 }
1640 }
1641}
1642
1643/* Look for a child region for KEY within this map_region.
1644 If it doesn't already exist, create a child map_region, using TYPE for
1645 its type.
1646 Return the region_id of the child (whether pre-existing, or
1647 newly-created). */
1648
1649region_id
1650map_region::get_or_create (region_model *model,
1651 region_id this_rid,
1652 tree key,
1653 tree type)
1654{
1655 gcc_assert (key);
1656 gcc_assert (valid_key_p (key));
1657 region_id *slot = m_map.get (key);
1658 if (slot)
1659 return *slot;
1660 region_id child_rid = model->add_region_for_type (this_rid, type);
1661 m_map.put (key, child_rid);
1662 return child_rid;
1663}
1664
1665/* Get the region_id for the child region for KEY within this
1666 MAP_REGION, or NULL if there is no such child region. */
1667
1668region_id *
1669map_region::get (tree key)
1670{
1671 gcc_assert (key);
1672 gcc_assert (valid_key_p (key));
1673 region_id *slot = m_map.get (key);
1674 return slot;
1675}
1676
1677/* Implementation of region::add_to_hash vfunc for map_region. */
1678
1679void
1680map_region::add_to_hash (inchash::hash &hstate) const
1681{
1682 region::add_to_hash (hstate);
1683 // TODO
1684}
1685
1686/* Implementation of region::remap_region_ids vfunc for map_region. */
1687
1688void
1689map_region::remap_region_ids (const region_id_map &map)
1690{
1691 region::remap_region_ids (map);
1692
1693 /* Remap the region ids within the map entries. */
1694 for (map_t::iterator iter = m_map.begin ();
1695 iter != m_map.end (); ++iter)
1696 map.update (&(*iter).second);
1697}
1698
1699/* Remove the binding of KEY to its child region (but not the
1700 child region itself).
1701 For use when purging unneeded SSA names. */
1702
1703void
1704map_region::unbind (tree key)
1705{
1706 gcc_assert (key);
1707 gcc_assert (valid_key_p (key));
1708 m_map.remove (key);
1709}
1710
1711/* Look for a child region with id CHILD_RID within this map_region.
1712 If one is found, return its tree key, otherwise return NULL_TREE. */
1713
1714tree
1715map_region::get_tree_for_child_region (region_id child_rid) const
1716{
1717 // TODO: do we want to store an inverse map?
1718 for (map_t::iterator iter = m_map.begin ();
1719 iter != m_map.end ();
1720 ++iter)
1721 {
1722 tree key = (*iter).first;
1723 region_id r = (*iter).second;
1724 if (r == child_rid)
1725 return key;
1726 }
1727
1728 return NULL_TREE;
1729}
1730
1731/* Look for a child region CHILD within this map_region.
1732 If one is found, return its tree key, otherwise return NULL_TREE. */
1733
1734tree
1735map_region::get_tree_for_child_region (region *child,
1736 const region_model &model) const
1737{
1738 // TODO: do we want to store an inverse map?
1739 for (map_t::iterator iter = m_map.begin ();
1740 iter != m_map.end ();
1741 ++iter)
1742 {
1743 tree key = (*iter).first;
1744 region_id r = (*iter).second;
1745 if (model.get_region (r) == child)
1746 return key;
1747 }
1748
1749 return NULL_TREE;
1750}
1751
1752/* Comparator for trees to impose a deterministic ordering on
1753 T1 and T2. */
1754
1755static int
1756tree_cmp (const_tree t1, const_tree t2)
1757{
1758 gcc_assert (t1);
1759 gcc_assert (t2);
1760
1761 /* Test tree codes first. */
1762 if (TREE_CODE (t1) != TREE_CODE (t2))
1763 return TREE_CODE (t1) - TREE_CODE (t2);
1764
1765 /* From this point on, we know T1 and T2 have the same tree code. */
1766
1767 if (DECL_P (t1))
1768 {
1769 if (DECL_NAME (t1) && DECL_NAME (t2))
1770 return strcmp (IDENTIFIER_POINTER (DECL_NAME (t1)),
1771 IDENTIFIER_POINTER (DECL_NAME (t2)));
1772 else
1773 {
1774 if (DECL_NAME (t1))
1775 return -1;
1776 else if (DECL_NAME (t2))
1777 return 1;
1778 else
1779 return DECL_UID (t1) - DECL_UID (t2);
1780 }
1781 }
1782
1783 switch (TREE_CODE (t1))
1784 {
1785 case SSA_NAME:
1786 {
1787 if (SSA_NAME_VAR (t1) && SSA_NAME_VAR (t2))
1788 {
1789 int var_cmp = tree_cmp (SSA_NAME_VAR (t1), SSA_NAME_VAR (t2));
1790 if (var_cmp)
1791 return var_cmp;
1792 return SSA_NAME_VERSION (t1) - SSA_NAME_VERSION (t2);
1793 }
1794 else
1795 {
1796 if (SSA_NAME_VAR (t1))
1797 return -1;
1798 else if (SSA_NAME_VAR (t2))
1799 return 1;
1800 else
1801 return SSA_NAME_VERSION (t1) - SSA_NAME_VERSION (t2);
1802 }
1803 }
1804 break;
1805
1806 case INTEGER_CST:
1807 return tree_int_cst_compare (t1, t2);
1808
1809 case REAL_CST:
1810 {
1811 real_value *rv1 = TREE_REAL_CST_PTR (t1);
1812 real_value *rv2 = TREE_REAL_CST_PTR (t2);
1813 if (real_compare (LT_EXPR, rv1, rv2))
1814 return -1;
1815 if (real_compare (LT_EXPR, rv2, rv1))
1816 return 1;
1817 return 0;
1818 }
1819
1820 case STRING_CST:
1821 return strcmp (TREE_STRING_POINTER (t1),
1822 TREE_STRING_POINTER (t2));
1823
1824 default:
1825 gcc_unreachable ();
1826 break;
1827 }
1828
1829 gcc_unreachable ();
1830
1831 return 0;
1832}
1833
1834/* qsort comparator for trees to impose a deterministic ordering on
1835 P1 and P2. */
1836
1837static int
1838tree_cmp (const void *p1, const void *p2)
1839{
1840 const_tree t1 = *(const_tree const *)p1;
1841 const_tree t2 = *(const_tree const *)p2;
1842
1843 int result = tree_cmp (t1, t2);
1844
1845 /* Check that the ordering is symmetric */
1846#if CHECKING_P
1847 int reversed = tree_cmp (t2, t1);
1848 gcc_assert (reversed == -result);
1849#endif
1850
1851 /* We should only have 0 for equal pairs. */
1852#if 0
1853 gcc_assert (result != 0
1854 || t1 == t2);
1855#endif
1856
1857 return result;
1858}
1859
1860/* Attempt to merge MAP_REGION_A and MAP_REGION_B into MERGED_MAP_REGION,
1861 which has region_id MERGED_RID, using MERGER.
1862 Return true if the merger is possible, false otherwise. */
1863
1864bool
1865map_region::can_merge_p (const map_region *map_region_a,
1866 const map_region *map_region_b,
1867 map_region *merged_map_region,
1868 region_id merged_rid,
1869 model_merger *merger)
1870{
1871 for (map_t::iterator iter = map_region_a->m_map.begin ();
1872 iter != map_region_a->m_map.end ();
1873 ++iter)
1874 {
1875 tree key_a = (*iter).first;
1876 region_id rid_a = (*iter).second;
1877
1878 if (const region_id *slot_b
1879 = const_cast<map_region *>(map_region_b)->m_map.get (key_a))
1880 {
1881 region_id rid_b = *slot_b;
1882
1883 region *child_region_a = merger->get_region_a <region> (rid_a);
1884 region *child_region_b = merger->get_region_b <region> (rid_b);
1885
1886 gcc_assert (child_region_a->get_type ()
1887 == child_region_b->get_type ());
1888
1889 gcc_assert (child_region_a->get_kind ()
1890 == child_region_b->get_kind ());
1891
1892 region_id child_merged_rid
1893 = merged_map_region->get_or_create (merger->m_merged_model,
1894 merged_rid,
1895 key_a,
1896 child_region_a->get_type ());
1897
1898 region *child_merged_region
1899 = merger->m_merged_model->get_region (child_merged_rid);
1900
1901 /* Consider values. */
1902 svalue_id child_a_sid = child_region_a->get_value_direct ();
1903 svalue_id child_b_sid = child_region_b->get_value_direct ();
1904 svalue_id child_merged_sid;
1905 if (!merger->can_merge_values_p (child_a_sid, child_b_sid,
1906 &child_merged_sid))
1907 return false;
1908 if (!child_merged_sid.null_p ())
1909 child_merged_region->set_value (*merger->m_merged_model,
1910 child_merged_rid,
1911 child_merged_sid,
1912 NULL);
1913
1914 if (map_region *map_region_a = child_region_a->dyn_cast_map_region ())
1915 {
1916 /* Recurse. */
1917 if (!can_merge_p (map_region_a,
1918 as_a <map_region *> (child_region_b),
1919 as_a <map_region *> (child_merged_region),
1920 child_merged_rid,
1921 merger))
1922 return false;
1923 }
1924
1925 }
1926 else
1927 {
1928 /* TODO: region is present in A, but absent in B. */
1929 }
1930 }
1931
1932 /* TODO: check for keys in B that aren't in A. */
1933
1934 return true;
1935}
1936
1937
1938/* Implementation of region::walk_for_canonicalization vfunc for
1939 map_region. */
1940
1941void
1942map_region::walk_for_canonicalization (canonicalization *c) const
1943{
1944 auto_vec<tree> keys (m_map.elements ());
1945 for (map_t::iterator iter = m_map.begin ();
1946 iter != m_map.end ();
1947 ++iter)
1948 {
1949 tree key_a = (*iter).first;
1950 keys.quick_push (key_a);
1951 }
1952 keys.qsort (tree_cmp);
1953
1954 unsigned i;
1955 tree key;
1956 FOR_EACH_VEC_ELT (keys, i, key)
1957 {
1958 region_id rid = *const_cast<map_region *>(this)->m_map.get (key);
1959 c->walk_rid (rid);
1960 }
1961}
1962
1963/* For debugging purposes: look for a child region for a decl named
1964 IDENTIFIER (or an SSA_NAME for such a decl), returning its value,
1965 or svalue_id::null if none are found. */
1966
1967svalue_id
1968map_region::get_value_by_name (tree identifier,
1969 const region_model &model) const
1970{
1971 for (map_t::iterator iter = m_map.begin ();
1972 iter != m_map.end ();
1973 ++iter)
1974 {
1975 tree key = (*iter).first;
1976 if (TREE_CODE (key) == SSA_NAME)
1977 if (SSA_NAME_VAR (key))
1978 key = SSA_NAME_VAR (key);
1979 if (DECL_P (key))
1980 if (DECL_NAME (key) == identifier)
1981 {
1982 region_id rid = (*iter).second;
1983 region *region = model.get_region (rid);
1984 return region->get_value (const_cast<region_model &>(model),
1985 false, NULL);
1986 }
1987 }
1988 return svalue_id::null ();
1989}
1990
1991/* class struct_or_union_region : public map_region. */
1992
1993/* Implementation of map_region::valid_key_p vfunc for
1994 struct_or_union_region. */
1995
1996bool
1997struct_or_union_region::valid_key_p (tree key) const
1998{
1999 return TREE_CODE (key) == FIELD_DECL;
2000}
2001
2002/* Compare the fields of this struct_or_union_region with OTHER, returning
2003 true if they are equal.
2004 For use by region::operator==. */
2005
2006bool
2007struct_or_union_region::compare_fields (const struct_or_union_region &other)
2008 const
2009{
2010 return map_region::compare_fields (other);
2011}
2012
2013/* class struct_region : public struct_or_union_region. */
2014
2015/* Implementation of region::clone vfunc for struct_region. */
2016
2017region *
2018struct_region::clone () const
2019{
2020 return new struct_region (*this);
2021}
2022
2023/* Compare the fields of this struct_region with OTHER, returning true
2024 if they are equal.
2025 For use by region::operator==. */
2026
2027bool
2028struct_region::compare_fields (const struct_region &other) const
2029{
2030 return struct_or_union_region::compare_fields (other);
2031}
2032
2033/* class union_region : public struct_or_union_region. */
2034
2035/* Implementation of region::clone vfunc for union_region. */
2036
2037region *
2038union_region::clone () const
2039{
2040 return new union_region (*this);
2041}
2042
2043/* Compare the fields of this union_region with OTHER, returning true
2044 if they are equal.
2045 For use by region::operator==. */
2046
2047bool
2048union_region::compare_fields (const union_region &other) const
2049{
2050 return struct_or_union_region::compare_fields (other);
2051}
2052
2053/* class frame_region : public map_region. */
2054
2055/* Compare the fields of this frame_region with OTHER, returning true
2056 if they are equal.
2057 For use by region::operator==. */
2058
2059bool
2060frame_region::compare_fields (const frame_region &other) const
2061{
2062 if (!map_region::compare_fields (other))
2063 return false;
2064 if (m_fun != other.m_fun)
2065 return false;
2066 if (m_depth != other.m_depth)
2067 return false;
2068 return true;
2069}
2070
2071/* Implementation of region::clone vfunc for frame_region. */
2072
2073region *
2074frame_region::clone () const
2075{
2076 return new frame_region (*this);
2077}
2078
2079/* Implementation of map_region::valid_key_p vfunc for frame_region. */
2080
2081bool
2082frame_region::valid_key_p (tree key) const
2083{
2084 // TODO: could also check that VAR_DECLs are locals
2085 return (TREE_CODE (key) == PARM_DECL
2086 || TREE_CODE (key) == VAR_DECL
2087 || TREE_CODE (key) == SSA_NAME
2088 || TREE_CODE (key) == RESULT_DECL);
2089}
2090
2091/* Implementation of region::print_fields vfunc for frame_region. */
2092
2093void
2094frame_region::print_fields (const region_model &model,
2095 region_id this_rid,
2096 pretty_printer *pp) const
2097{
2098 map_region::print_fields (model, this_rid, pp);
2099 pp_printf (pp, ", function: %qs, depth: %i", function_name (m_fun), m_depth);
2100}
2101
2102/* Implementation of region::add_to_hash vfunc for frame_region. */
2103
2104void
2105frame_region::add_to_hash (inchash::hash &hstate) const
2106{
2107 map_region::add_to_hash (hstate);
2108 hstate.add_ptr (m_fun);
2109 hstate.add_int (m_depth);
2110}
2111
2112/* class globals_region : public scope_region. */
2113
2114/* Compare the fields of this globals_region with OTHER, returning true
2115 if they are equal.
2116 For use by region::operator==. */
2117
2118bool
2119globals_region::compare_fields (const globals_region &other) const
2120{
2121 return map_region::compare_fields (other);
2122}
2123
2124/* Implementation of region::clone vfunc for globals_region. */
2125
2126region *
2127globals_region::clone () const
2128{
2129 return new globals_region (*this);
2130}
2131
2132/* Implementation of map_region::valid_key_p vfunc for globals_region. */
2133
2134bool
2135globals_region::valid_key_p (tree key) const
2136{
2137 return TREE_CODE (key) == VAR_DECL;
2138}
2139
2140/* class code_region : public map_region. */
2141
2142/* Compare the fields of this code_region with OTHER, returning true
2143 if they are equal.
2144 For use by region::operator==. */
2145
2146bool
2147code_region::compare_fields (const code_region &other) const
2148{
2149 return map_region::compare_fields (other);
2150}
2151
2152/* Implementation of region::clone vfunc for code_region. */
2153
2154region *
2155code_region::clone () const
2156{
2157 return new code_region (*this);
2158}
2159
2160/* Implementation of map_region::valid_key_p vfunc for code_region. */
2161
2162bool
2163code_region::valid_key_p (tree key) const
2164{
2165 return TREE_CODE (key) == FUNCTION_DECL;
2166}
2167
2168/* class array_region : public region. */
2169
2170/* array_region's copy ctor. */
2171
2172array_region::array_region (const array_region &other)
2173: region (other),
2174 m_map (other.m_map)
2175{
2176}
2177
2178/* Get a child region for the element with index INDEX_SID. */
2179
2180region_id
2181array_region::get_element (region_model *model,
2182 region_id this_rid,
2183 svalue_id index_sid,
2184 region_model_context *ctxt ATTRIBUTE_UNUSED)
2185{
2186 tree element_type = TREE_TYPE (get_type ());
2187 svalue *index_sval = model->get_svalue (index_sid);
2188 if (tree cst_index = index_sval->maybe_get_constant ())
2189 {
2190 key_t key = key_from_constant (cst_index);
2191 region_id element_rid
2192 = get_or_create (model, this_rid, key, element_type);
2193 return element_rid;
2194 }
2195
2196 return model->get_or_create_view (this_rid, element_type);
2197}
2198
2199/* Implementation of region::clone vfunc for array_region. */
2200
2201region *
2202array_region::clone () const
2203{
2204 return new array_region (*this);
2205}
2206
2207/* Compare the fields of this array_region with OTHER, returning true
2208 if they are equal.
2209 For use by region::operator==. */
2210
2211bool
2212array_region::compare_fields (const array_region &other) const
2213{
2214 if (m_map.elements () != other.m_map.elements ())
2215 return false;
2216
2217 for (map_t::iterator iter = m_map.begin ();
2218 iter != m_map.end ();
2219 ++iter)
2220 {
2221 int key = (*iter).first;
2222 region_id e = (*iter).second;
2223 region_id *other_slot = const_cast <map_t &> (other.m_map).get (key);
2224 if (other_slot == NULL)
2225 return false;
2226 if (e != *other_slot)
2227 return false;
2228 }
2229 return true;
2230}
2231
2232/* Implementation of region::print_fields vfunc for array_region. */
2233
2234void
2235array_region::print_fields (const region_model &model,
2236 region_id this_rid,
2237 pretty_printer *pp) const
2238{
2239 region::print_fields (model, this_rid, pp);
2240 pp_string (pp, ", array: {");
2241 for (map_t::iterator iter = m_map.begin ();
2242 iter != m_map.end ();
2243 ++iter)
2244 {
2245 if (iter != m_map.begin ())
2246 pp_string (pp, ", ");
2247 int key = (*iter).first;
2248 region_id child_rid = (*iter).second;
2249PUSH_IGNORE_WFORMAT
2250 pp_printf (pp, "[%i]: ", key);
2251POP_IGNORE_WFORMAT
2252 child_rid.print (pp);
2253 }
2254 pp_string (pp, "}");
2255}
2256
2257/* Implementation of region::dump_dot_to_pp vfunc for array_region. */
2258
2259void
2260array_region::dump_dot_to_pp (const region_model &model,
2261 region_id this_rid,
2262 pretty_printer *pp) const
2263{
2264 region::dump_dot_to_pp (model, this_rid, pp);
2265 for (map_t::iterator iter = m_map.begin ();
2266 iter != m_map.end ();
2267 ++iter)
2268 {
2269 // TODO: add nodes/edges to label things
2270
2271 int key = (*iter).first;
2272 region_id child_rid = (*iter).second;
2273
2274 pp_printf (pp, "rid_label_%i [label=\"", child_rid.as_int ());
2275 pp_write_text_to_stream (pp);
2276PUSH_IGNORE_WFORMAT
2277 pp_printf (pp, "%qi", key);
2278POP_IGNORE_WFORMAT
2279 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
2280 pp_string (pp, "\"];");
2281 pp_newline (pp);
2282
2283 pp_printf (pp, "rid_label_%i", child_rid.as_int ());
2284 pp_string (pp, " -> ");
2285 child_rid.dump_node_name_to_pp (pp);
2286 pp_string (pp, ";");
2287 pp_newline (pp);
2288 }
2289}
2290
2291/* Implementation of region::dump_child_label vfunc for array_region. */
2292
2293void
2294array_region::dump_child_label (const region_model &model,
2295 region_id this_rid,
2296 region_id child_rid,
2297 pretty_printer *pp) const
2298{
2299 region::dump_child_label (model, this_rid, child_rid, pp);
2300
2301 for (map_t::iterator iter = m_map.begin ();
2302 iter != m_map.end ();
2303 ++iter)
2304 {
2305 if (child_rid == (*iter).second)
2306 {
2307 int key = (*iter).first;
2308 pp_printf (pp, "[%i]: ", key);
2309 }
2310 }
2311}
2312
2313/* Look for a child region for KEY within this array_region.
2314 If it doesn't already exist, create a child array_region, using TYPE for
2315 its type.
2316 Return the region_id of the child (whether pre-existing, or
2317 newly-created). */
2318
2319region_id
2320array_region::get_or_create (region_model *model,
2321 region_id this_rid,
2322 key_t key,
2323 tree type)
2324{
2325 region_id *slot = m_map.get (key);
2326 if (slot)
2327 return *slot;
2328 region_id child_rid = model->add_region_for_type (this_rid, type);
2329 m_map.put (key, child_rid);
2330 return child_rid;
2331}
2332
2333/* Get the region_id for the child region for KEY within this
2334 ARRAY_REGION, or NULL if there is no such child region. */
2335
2336region_id *
2337array_region::get (key_t key)
2338{
2339 region_id *slot = m_map.get (key);
2340 return slot;
2341}
2342
2343/* Implementation of region::add_to_hash vfunc for array_region. */
2344
2345void
2346array_region::add_to_hash (inchash::hash &hstate) const
2347{
2348 region::add_to_hash (hstate);
2349 // TODO
2350}
2351
2352/* Implementation of region::remap_region_ids vfunc for array_region. */
2353
2354void
2355array_region::remap_region_ids (const region_id_map &map)
2356{
2357 region::remap_region_ids (map);
2358
2359 /* Remap the region ids within the map entries. */
2360 for (map_t::iterator iter = m_map.begin ();
2361 iter != m_map.end (); ++iter)
2362 map.update (&(*iter).second);
2363}
2364
2365/* Look for a child region with id CHILD_RID within this array_region.
2366 If one is found, write its key to *OUT and return true,
2367 otherwise return false. */
2368
2369bool
2370array_region::get_key_for_child_region (region_id child_rid, key_t *out) const
2371{
2372 // TODO: do we want to store an inverse map?
2373 for (map_t::iterator iter = m_map.begin ();
2374 iter != m_map.end ();
2375 ++iter)
2376 {
2377 key_t key = (*iter).first;
2378 region_id r = (*iter).second;
2379 if (r == child_rid)
2380 {
2381 *out = key;
2382 return true;
2383 }
2384 }
2385
2386 return false;
2387}
2388
2389/* qsort comparator for int. */
2390
2391static int
2392int_cmp (const void *p1, const void *p2)
2393{
2394 int i1 = *(const int *)p1;
2395 int i2 = *(const int *)p2;
2396
2397 return i1 - i2;
2398}
2399
2400/* Implementation of region::walk_for_canonicalization vfunc for
2401 array_region. */
2402
2403void
2404array_region::walk_for_canonicalization (canonicalization *c) const
2405{
2406 auto_vec<int> keys (m_map.elements ());
2407 for (map_t::iterator iter = m_map.begin ();
2408 iter != m_map.end ();
2409 ++iter)
2410 {
2411 int key_a = (*iter).first;
2412 keys.quick_push (key_a);
2413 }
2414 keys.qsort (int_cmp);
2415
2416 unsigned i;
2417 int key;
2418 FOR_EACH_VEC_ELT (keys, i, key)
2419 {
2420 region_id rid = *const_cast<array_region *>(this)->m_map.get (key);
2421 c->walk_rid (rid);
2422 }
2423}
2424
2425/* Convert constant CST into an array_region::key_t. */
2426
2427array_region::key_t
2428array_region::key_from_constant (tree cst)
2429{
2430 gcc_assert (CONSTANT_CLASS_P (cst));
2431 wide_int w = wi::to_wide (cst);
2432 key_t result = w.to_shwi ();
2433 return result;
2434}
2435
2436/* class function_region : public map_region. */
2437
2438/* Compare the fields of this function_region with OTHER, returning true
2439 if they are equal.
2440 For use by region::operator==. */
2441
2442bool
2443function_region::compare_fields (const function_region &other) const
2444{
2445 return map_region::compare_fields (other);
2446}
2447
2448/* Implementation of region::clone vfunc for function_region. */
2449
2450region *
2451function_region::clone () const
2452{
2453 return new function_region (*this);
2454}
2455
2456/* Implementation of map_region::valid_key_p vfunc for function_region. */
2457
2458bool
2459function_region::valid_key_p (tree key) const
2460{
2461 return TREE_CODE (key) == LABEL_DECL;
2462}
2463
2464/* class stack_region : public region. */
2465
2466/* stack_region's copy ctor. */
2467
2468stack_region::stack_region (const stack_region &other)
2469: region (other),
2470 m_frame_rids (other.m_frame_rids.length ())
2471{
2472 int i;
2473 region_id *frame_rid;
2474 FOR_EACH_VEC_ELT (other.m_frame_rids, i, frame_rid)
2475 m_frame_rids.quick_push (*frame_rid);
2476}
2477
2478/* Compare the fields of this stack_region with OTHER, returning true
2479 if they are equal.
2480 For use by region::operator==. */
2481
2482bool
2483stack_region::compare_fields (const stack_region &other) const
2484{
2485 if (m_frame_rids.length () != other.m_frame_rids.length ())
2486 return false;
2487
2488 int i;
2489 region_id *frame_rid;
2490 FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
2491 if (m_frame_rids[i] != other.m_frame_rids[i])
2492 return false;
2493
2494 return true;
2495}
2496
2497/* Implementation of region::clone vfunc for stack_region. */
2498
2499region *
2500stack_region::clone () const
2501{
2502 return new stack_region (*this);
2503}
2504
2505/* Implementation of region::print_fields vfunc for stack_region. */
2506
2507void
2508stack_region::print_fields (const region_model &model,
2509 region_id this_rid,
2510 pretty_printer *pp) const
2511{
2512 region::print_fields (model, this_rid, pp);
2513 // TODO
2514}
2515
2516/* Implementation of region::dump_child_label vfunc for stack_region. */
2517
2518void
2519stack_region::dump_child_label (const region_model &model,
2520 region_id this_rid ATTRIBUTE_UNUSED,
2521 region_id child_rid,
2522 pretty_printer *pp) const
2523{
2524 function *fun = model.get_region<frame_region> (child_rid)->get_function ();
2525 pp_printf (pp, "frame for %qs: ", function_name (fun));
2526}
2527
2528/* Push FRAME_RID (for a frame_region) onto this stack. */
2529
2530void
2531stack_region::push_frame (region_id frame_rid)
2532{
2533 m_frame_rids.safe_push (frame_rid);
2534}
2535
2536/* Get the region_id of the top-most frame in this stack, if any. */
2537
2538region_id
2539stack_region::get_current_frame_id () const
2540{
2541 if (m_frame_rids.length () > 0)
2542 return m_frame_rids[m_frame_rids.length () - 1];
2543 else
2544 return region_id::null ();
2545}
2546
2547/* Pop the topmost frame_region from this stack.
2548
2549 Purge the frame region and all its descendent regions.
2550 Convert any pointers that point into such regions into
2551 POISON_KIND_POPPED_STACK svalues.
2552
2553 Return the ID of any return value from the frame.
2554
2555 If PURGE, then purge all unused svalues, with the exception of any
2556 return value for the frame, which is temporarily
2557 preserved in case no regions reference it, so it can
2558 be written into a region in the caller.
2559
2560 Accumulate stats on purged entities into STATS. */
2561
2562svalue_id
2563stack_region::pop_frame (region_model *model, bool purge, purge_stats *stats,
2564 region_model_context *ctxt)
2565{
2566 gcc_assert (m_frame_rids.length () > 0);
2567
2568 region_id frame_rid = get_current_frame_id ();
2569 frame_region *frame = model->get_region<frame_region> (frame_rid);
2570
2571 /* Evaluate the result, within the callee frame. */
2572 svalue_id result_sid;
2573 tree fndecl = frame->get_function ()->decl;
2574 tree result = DECL_RESULT (fndecl);
2575 if (result && TREE_TYPE (result) != void_type_node)
2576 result_sid = model->get_rvalue (result, ctxt);
2577
2578 /* Pop the frame RID. */
2579 m_frame_rids.pop ();
2580
2581 model->delete_region_and_descendents (frame_rid,
2582 POISON_KIND_POPPED_STACK,
2583 stats,
2584 ctxt ? ctxt->get_logger () : NULL);
2585
2586 /* Delete unused svalues, but don't delete the return value. */
2587 if (purge)
2588 model->purge_unused_svalues (stats, ctxt, &result_sid);
2589
2590 model->validate ();
2591
2592 return result_sid;
2593}
2594
2595/* Implementation of region::add_to_hash vfunc for stack_region. */
2596
2597void
2598stack_region::add_to_hash (inchash::hash &hstate) const
2599{
2600 region::add_to_hash (hstate);
2601
2602 int i;
2603 region_id *frame_rid;
2604 FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
2605 inchash::add (*frame_rid, hstate);
2606}
2607
2608/* Implementation of region::remap_region_ids vfunc for stack_region. */
2609
2610void
2611stack_region::remap_region_ids (const region_id_map &map)
2612{
2613 region::remap_region_ids (map);
2614 int i;
2615 region_id *frame_rid;
2616 FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
2617 map.update (&m_frame_rids[i]);
2618}
2619
2620/* Attempt to merge STACK_REGION_A and STACK_REGION_B using MERGER.
2621 Return true if the merger is possible, false otherwise. */
2622
2623bool
2624stack_region::can_merge_p (const stack_region *stack_region_a,
2625 const stack_region *stack_region_b,
2626 model_merger *merger)
2627{
2628 if (stack_region_a->get_num_frames ()
2629 != stack_region_b->get_num_frames ())
2630 return false;
2631
2632 region_model *merged_model = merger->m_merged_model;
2633
2634 region_id rid_merged_stack
2635 = merged_model->get_root_region ()->ensure_stack_region (merged_model);
2636
2637 stack_region *merged_stack
2638 = merged_model->get_region <stack_region> (rid_merged_stack);
2639
2640 for (unsigned i = 0; i < stack_region_a->get_num_frames (); i++)
2641 {
2642 region_id rid_a = stack_region_a->get_frame_rid (i);
2643 frame_region *frame_a = merger->get_region_a <frame_region> (rid_a);
2644
2645 region_id rid_b = stack_region_b->get_frame_rid (i);
2646 frame_region *frame_b = merger->get_region_b <frame_region> (rid_b);
2647
2648 if (frame_a->get_function () != frame_b->get_function ())
2649 return false;
2650 frame_region *merged_frame = new frame_region (rid_merged_stack,
2651 frame_a->get_function (),
2652 frame_a->get_depth ());
2653 region_id rid_merged_frame = merged_model->add_region (merged_frame);
2654 merged_stack->push_frame (rid_merged_frame);
2655
2656 if (!map_region::can_merge_p (frame_a, frame_b,
2657 merged_frame, rid_merged_frame,
2658 merger))
2659 return false;
2660 }
2661
2662 return true;
2663}
2664
2665/* Implementation of region::walk_for_canonicalization vfunc for
2666 stack_region. */
2667
2668void
2669stack_region::walk_for_canonicalization (canonicalization *c) const
2670{
2671 int i;
2672 region_id *frame_rid;
2673 FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
2674 c->walk_rid (*frame_rid);
2675}
2676
2677/* For debugging purposes: look for a grandchild region within one of
2678 the child frame regions, where the grandchild is for a decl named
2679 IDENTIFIER (or an SSA_NAME for such a decl):
2680
2681 stack_region
2682 `-frame_region
2683 `-region for decl named IDENTIFIER
2684
2685 returning its value, or svalue_id::null if none are found. */
2686
2687svalue_id
2688stack_region::get_value_by_name (tree identifier,
2689 const region_model &model) const
2690{
2691 int i;
2692 region_id *frame_rid;
2693 FOR_EACH_VEC_ELT (m_frame_rids, i, frame_rid)
2694 {
2695 frame_region *frame = model.get_region<frame_region> (*frame_rid);
2696 svalue_id sid = frame->get_value_by_name (identifier, model);
2697 if (!sid.null_p ())
2698 return sid;
2699 }
2700
2701 return svalue_id::null ();
2702}
2703
2704/* class heap_region : public region. */
2705
2706/* heap_region's copy ctor. */
2707
2708heap_region::heap_region (const heap_region &other)
2709: region (other)
2710{
2711}
2712
2713/* Compare the fields of this heap_region with OTHER, returning true
2714 if they are equal.
2715 For use by region::operator==. */
2716
2717bool
2718heap_region::compare_fields (const heap_region &) const
2719{
2720 /* Empty. */
2721 return true;
2722}
2723
2724/* Implementation of region::clone vfunc for heap_region. */
2725
2726region *
2727heap_region::clone () const
2728{
2729 return new heap_region (*this);
2730}
2731
2732/* Implementation of region::walk_for_canonicalization vfunc for
2733 heap_region. */
2734
2735void
2736heap_region::walk_for_canonicalization (canonicalization *) const
2737{
2738 /* Empty. */
2739}
2740
2741/* class root_region : public region. */
2742
2743/* root_region's default ctor. */
2744
2745root_region::root_region ()
2746: region (region_id::null (),
2747 svalue_id::null (),
2748 NULL_TREE)
2749{
2750}
2751
2752/* root_region's copy ctor. */
2753
2754root_region::root_region (const root_region &other)
2755: region (other),
2756 m_stack_rid (other.m_stack_rid),
2757 m_globals_rid (other.m_globals_rid),
2758 m_code_rid (other.m_code_rid),
2759 m_heap_rid (other.m_heap_rid)
2760{
2761}
2762
2763/* Compare the fields of this root_region with OTHER, returning true
2764 if they are equal.
2765 For use by region::operator==. */
2766
2767bool
2768root_region::compare_fields (const root_region &other) const
2769{
2770 if (m_stack_rid != other.m_stack_rid)
2771 return false;
2772 if (m_globals_rid != other.m_globals_rid)
2773 return false;
2774 if (m_code_rid != other.m_code_rid)
2775 return false;
2776 if (m_heap_rid != other.m_heap_rid)
2777 return false;
2778 return true;
2779}
2780
2781/* Implementation of region::clone vfunc for root_region. */
2782
2783region *
2784root_region::clone () const
2785{
2786 return new root_region (*this);
2787}
2788
2789/* Implementation of region::print_fields vfunc for root_region. */
2790
2791void
2792root_region::print_fields (const region_model &model,
2793 region_id this_rid,
2794 pretty_printer *pp) const
2795{
2796 region::print_fields (model, this_rid, pp);
2797 // TODO
2798}
2799
2800/* Implementation of region::dump_child_label vfunc for root_region. */
2801
2802void
2803root_region::dump_child_label (const region_model &model ATTRIBUTE_UNUSED,
2804 region_id this_rid ATTRIBUTE_UNUSED,
2805 region_id child_rid,
2806 pretty_printer *pp) const
2807{
2808 if (child_rid == m_stack_rid)
2809 pp_printf (pp, "stack: ");
2810 else if (child_rid == m_globals_rid)
2811 pp_printf (pp, "globals: ");
2812 else if (child_rid == m_code_rid)
2813 pp_printf (pp, "code: ");
2814 else if (child_rid == m_heap_rid)
2815 pp_printf (pp, "heap: ");
2816}
2817
2818/* Create a new frame_region for a call to FUN and push it onto
2819 the stack.
2820
2821 If ARG_SIDS is non-NULL, use it to populate the parameters
2822 in the new frame.
2823 Otherwise, populate them with unknown values.
2824
2825 Return the region_id of the new frame. */
2826
2827region_id
2828root_region::push_frame (region_model *model, function *fun,
2829 vec<svalue_id> *arg_sids,
2830 region_model_context *ctxt)
2831{
2832 gcc_assert (fun);
2833 /* arg_sids can be NULL. */
2834
2835 ensure_stack_region (model);
2836 stack_region *stack = model->get_region <stack_region> (m_stack_rid);
2837
2838 frame_region *region = new frame_region (m_stack_rid, fun,
2839 stack->get_num_frames ());
2840 region_id frame_rid = model->add_region (region);
2841
2842 // TODO: unify these cases by building a vec of unknown?
2843
2844 if (arg_sids)
2845 {
2846 /* Arguments supplied from a caller frame. */
2847
2848 tree fndecl = fun->decl;
2849 unsigned idx = 0;
2850 for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
2851 iter_parm = DECL_CHAIN (iter_parm), ++idx)
2852 {
2853 /* If there's a mismatching declaration, the call stmt might
2854 not have enough args. Handle this case by leaving the
2855 rest of the params as uninitialized. */
2856 if (idx >= arg_sids->length ())
2857 break;
2858 svalue_id arg_sid = (*arg_sids)[idx];
2859 region_id parm_rid
2860 = region->get_or_create (model, frame_rid, iter_parm,
2861 TREE_TYPE (iter_parm));
2862 model->set_value (parm_rid, arg_sid, ctxt);
2863
2864 /* Also do it for default SSA name (sharing the same unknown
2865 value). */
2866 tree parm_default_ssa = ssa_default_def (fun, iter_parm);
2867 if (parm_default_ssa)
2868 {
2869 region_id defssa_rid
2870 = region->get_or_create (model, frame_rid, parm_default_ssa,
2871 TREE_TYPE (iter_parm));
2872 model->set_value (defssa_rid, arg_sid, ctxt);
2873 }
2874 }
2875 }
2876 else
2877 {
2878 /* No known arguments (a top-level call within the analysis). */
2879
2880 /* Params have a defined, unknown value; they should not inherit
2881 from the poisoned uninit value. */
2882 tree fndecl = fun->decl;
2883 for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
2884 iter_parm = DECL_CHAIN (iter_parm))
2885 {
2886 region_id parm_rid
2887 = region->get_or_create (model, frame_rid, iter_parm,
2888 TREE_TYPE (iter_parm));
2889 svalue_id parm_sid
2890 = model->set_to_new_unknown_value (parm_rid, TREE_TYPE (iter_parm),
2891 ctxt);
2892
2893 /* Also do it for default SSA name (sharing the same unknown
2894 value). */
2895 tree parm_default_ssa = ssa_default_def (fun, iter_parm);
2896 if (parm_default_ssa)
2897 {
2898 region_id defssa_rid
2899 = region->get_or_create (model, frame_rid, parm_default_ssa,
2900 TREE_TYPE (iter_parm));
2901 model->get_region (defssa_rid)->set_value (*model, defssa_rid,
2902 parm_sid, ctxt);
2903 }
2904 }
2905 }
2906
2907 stack->push_frame (frame_rid);
2908
2909 return frame_rid;
2910}
2911
2912/* Get the region_id of the top-most frame in this root_region's stack,
2913 if any. */
2914
2915region_id
2916root_region::get_current_frame_id (const region_model &model) const
2917{
2918 stack_region *stack = model.get_region <stack_region> (m_stack_rid);
2919 if (stack)
2920 return stack->get_current_frame_id ();
2921 else
2922 return region_id::null ();
2923}
2924
2925/* Pop the topmost frame_region from this root_region's stack;
2926 see the comment for stack_region::pop_frame. */
2927
2928svalue_id
2929root_region::pop_frame (region_model *model, bool purge, purge_stats *out,
2930 region_model_context *ctxt)
2931{
2932 stack_region *stack = model->get_region <stack_region> (m_stack_rid);
2933 return stack->pop_frame (model, purge, out, ctxt);
2934}
2935
2936/* Return the region_id of the stack region, creating it if doesn't
2937 already exist. */
2938
2939region_id
2940root_region::ensure_stack_region (region_model *model)
2941{
2942 if (m_stack_rid.null_p ())
2943 {
2944 svalue_id uninit_sid
2945 = model->add_svalue (new poisoned_svalue (POISON_KIND_UNINIT,
2946 NULL_TREE));
2947 m_stack_rid
2948 = model->add_region (new stack_region (model->get_root_rid (),
2949 uninit_sid));
2950 }
2951 return m_stack_rid;
2952}
2953
2954/* Return the stack region (which could be NULL). */
2955
2956stack_region *
2957root_region::get_stack_region (const region_model *model) const
2958{
2959 return model->get_region <stack_region> (m_stack_rid);
2960}
2961
2962/* Return the region_id of the globals region, creating it if doesn't
2963 already exist. */
2964
2965region_id
2966root_region::ensure_globals_region (region_model *model)
2967{
2968 if (m_globals_rid.null_p ())
2969 m_globals_rid
2970 = model->add_region (new globals_region (model->get_root_rid ()));
2971 return m_globals_rid;
2972}
2973
2974/* Return the code region (which could be NULL). */
2975
2976code_region *
2977root_region::get_code_region (const region_model *model) const
2978{
2979 return model->get_region <code_region> (m_code_rid);
2980}
2981
2982/* Return the region_id of the code region, creating it if doesn't
2983 already exist. */
2984
2985region_id
2986root_region::ensure_code_region (region_model *model)
2987{
2988 if (m_code_rid.null_p ())
2989 m_code_rid
2990 = model->add_region (new code_region (model->get_root_rid ()));
2991 return m_code_rid;
2992}
2993
2994/* Return the globals region (which could be NULL). */
2995
2996globals_region *
2997root_region::get_globals_region (const region_model *model) const
2998{
2999 return model->get_region <globals_region> (m_globals_rid);
3000}
3001
3002/* Return the region_id of the heap region, creating it if doesn't
3003 already exist. */
3004
3005region_id
3006root_region::ensure_heap_region (region_model *model)
3007{
3008 if (m_heap_rid.null_p ())
3009 {
3010 svalue_id uninit_sid
3011 = model->add_svalue (new poisoned_svalue (POISON_KIND_UNINIT,
3012 NULL_TREE));
3013 m_heap_rid
3014 = model->add_region (new heap_region (model->get_root_rid (),
3015 uninit_sid));
3016 }
3017 return m_heap_rid;
3018}
3019
3020/* Return the heap region (which could be NULL). */
3021
3022heap_region *
3023root_region::get_heap_region (const region_model *model) const
3024{
3025 return model->get_region <heap_region> (m_heap_rid);
3026}
3027
3028/* Implementation of region::remap_region_ids vfunc for root_region. */
3029
3030void
3031root_region::remap_region_ids (const region_id_map &map)
3032{
3033 map.update (&m_stack_rid);
3034 map.update (&m_globals_rid);
3035 map.update (&m_code_rid);
3036 map.update (&m_heap_rid);
3037}
3038
3039/* Attempt to merge ROOT_REGION_A and ROOT_REGION_B into
3040 MERGED_ROOT_REGION using MERGER.
3041 Return true if the merger is possible, false otherwise. */
3042
3043bool
3044root_region::can_merge_p (const root_region *root_region_a,
3045 const root_region *root_region_b,
3046 root_region *merged_root_region,
3047 model_merger *merger)
3048{
3049 /* We can only merge if the stacks are sufficiently similar. */
3050 stack_region *stack_a = root_region_a->get_stack_region (merger->m_model_a);
3051 stack_region *stack_b = root_region_b->get_stack_region (merger->m_model_b);
3052 if (stack_a && stack_b)
3053 {
3054 /* If the two models both have a stack, attempt to merge them. */
3055 merged_root_region->ensure_stack_region (merger->m_merged_model);
3056 if (!stack_region::can_merge_p (stack_a, stack_b, merger))
3057 return false;
3058 }
3059 else if (stack_a || stack_b)
3060 /* Don't attempt to merge if one model has a stack and the other
3061 doesn't. */
3062 return false;
3063
3064 map_region *globals_a = root_region_a->get_globals_region (merger->m_model_a);
3065 map_region *globals_b = root_region_b->get_globals_region (merger->m_model_b);
3066 if (globals_a && globals_b)
3067 {
3068 /* If both models have globals regions, attempt to merge them. */
3069 region_id merged_globals_rid
3070 = merged_root_region->ensure_globals_region (merger->m_merged_model);
3071 map_region *merged_globals
3072 = merged_root_region->get_globals_region (merger->m_merged_model);
3073 if (!map_region::can_merge_p (globals_a, globals_b,
3074 merged_globals, merged_globals_rid,
3075 merger))
3076 return false;
3077 }
3078 /* otherwise, merge as "no globals". */
3079
3080 map_region *code_a = root_region_a->get_code_region (merger->m_model_a);
3081 map_region *code_b = root_region_b->get_code_region (merger->m_model_b);
3082 if (code_a && code_b)
3083 {
3084 /* If both models have code regions, attempt to merge them. */
3085 region_id merged_code_rid
3086 = merged_root_region->ensure_code_region (merger->m_merged_model);
3087 map_region *merged_code
3088 = merged_root_region->get_code_region (merger->m_merged_model);
3089 if (!map_region::can_merge_p (code_a, code_b,
3090 merged_code, merged_code_rid,
3091 merger))
3092 return false;
3093 }
3094 /* otherwise, merge as "no code". */
3095
3096 heap_region *heap_a = root_region_a->get_heap_region (merger->m_model_a);
3097 heap_region *heap_b = root_region_b->get_heap_region (merger->m_model_b);
3098 if (heap_a && heap_b)
3099 {
3100 /* If both have a heap, create a "merged" heap.
3101 Actually merging the heap contents happens via the region_svalue
3102 instances, as needed, when seeing pairs of region_svalue instances. */
3103 merged_root_region->ensure_heap_region (merger->m_merged_model);
3104 }
3105 /* otherwise, merge as "no heap". */
3106
3107 return true;
3108}
3109
3110/* Implementation of region::add_to_hash vfunc for root_region. */
3111
3112void
3113root_region::add_to_hash (inchash::hash &hstate) const
3114{
3115 region::add_to_hash (hstate);
3116 inchash::add (m_stack_rid, hstate);
3117 inchash::add (m_globals_rid, hstate);
3118 inchash::add (m_code_rid, hstate);
3119 inchash::add (m_heap_rid, hstate);
3120}
3121
3122/* Implementation of region::walk_for_canonicalization vfunc for
3123 root_region. */
3124
3125void
3126root_region::walk_for_canonicalization (canonicalization *c) const
3127{
3128 c->walk_rid (m_stack_rid);
3129 c->walk_rid (m_globals_rid);
3130 c->walk_rid (m_code_rid);
3131 c->walk_rid (m_heap_rid);
3132}
3133
3134/* For debugging purposes: look for a descendant region for a local
3135 or global decl named IDENTIFIER (or an SSA_NAME for such a decl),
3136 returning its value, or svalue_id::null if none are found. */
3137
3138svalue_id
3139root_region::get_value_by_name (tree identifier,
3140 const region_model &model) const
3141{
3142 if (stack_region *stack = get_stack_region (&model))
3143 {
3144 svalue_id sid = stack->get_value_by_name (identifier, model);
3145 if (!sid.null_p ())
3146 return sid;
3147 }
3148 if (map_region *globals = get_globals_region (&model))
3149 {
3150 svalue_id sid = globals->get_value_by_name (identifier, model);
3151 if (!sid.null_p ())
3152 return sid;
3153 }
3154 return svalue_id::null ();
3155}
3156
3157/* class symbolic_region : public map_region. */
3158
3159/* symbolic_region's copy ctor. */
3160
3161symbolic_region::symbolic_region (const symbolic_region &other)
3162: region (other),
3163 m_possibly_null (other.m_possibly_null)
3164{
3165}
3166
3167/* Compare the fields of this symbolic_region with OTHER, returning true
3168 if they are equal.
3169 For use by region::operator==. */
3170
3171bool
3172symbolic_region::compare_fields (const symbolic_region &other) const
3173{
3174 return m_possibly_null == other.m_possibly_null;
3175}
3176
3177/* Implementation of region::clone vfunc for symbolic_region. */
3178
3179region *
3180symbolic_region::clone () const
3181{
3182 return new symbolic_region (*this);
3183}
3184
3185/* Implementation of region::walk_for_canonicalization vfunc for
3186 symbolic_region. */
3187
3188void
3189symbolic_region::walk_for_canonicalization (canonicalization *) const
3190{
3191 /* Empty. */
3192}
3193
3194/* class region_model. */
3195
3196/* region_model's default ctor. */
3197
3198region_model::region_model ()
3199{
3200 m_root_rid = add_region (new root_region ());
3201 m_constraints = new impl_constraint_manager (this);
3202 // TODO
3203}
3204
3205/* region_model's copy ctor. */
3206
3207region_model::region_model (const region_model &other)
3208: m_svalues (other.m_svalues.length ()),
3209 m_regions (other.m_regions.length ()),
3210 m_root_rid (other.m_root_rid)
3211{
3212 /* Clone the svalues and regions. */
3213 int i;
3214
3215 svalue *svalue;
3216 FOR_EACH_VEC_ELT (other.m_svalues, i, svalue)
3217 m_svalues.quick_push (svalue->clone ());
3218
3219 region *region;
3220 FOR_EACH_VEC_ELT (other.m_regions, i, region)
3221 m_regions.quick_push (region->clone ());
3222
3223 m_constraints = other.m_constraints->clone (this);
3224}
3225
3226/* region_model's dtor. */
3227
3228region_model::~region_model ()
3229{
3230 delete m_constraints;
3231}
3232
3233/* region_model's assignment operator. */
3234
3235region_model &
3236region_model::operator= (const region_model &other)
3237{
3238 unsigned i;
3239 svalue *svalue;
3240 region *region;
3241
3242 /* Delete existing content. */
3243 FOR_EACH_VEC_ELT (m_svalues, i, svalue)
3244 delete svalue;
3245 m_svalues.truncate (0);
3246
3247 FOR_EACH_VEC_ELT (m_regions, i, region)
3248 delete region;
3249 m_regions.truncate (0);
3250
3251 delete m_constraints;
3252
3253 /* Clone the svalues and regions. */
3254 m_svalues.reserve (other.m_svalues.length (), true);
3255 FOR_EACH_VEC_ELT (other.m_svalues, i, svalue)
3256 m_svalues.quick_push (svalue->clone ());
3257
3258 m_regions.reserve (other.m_regions.length (), true);
3259 FOR_EACH_VEC_ELT (other.m_regions, i, region)
3260 m_regions.quick_push (region->clone ());
3261
3262 m_root_rid = other.m_root_rid;
3263
3264 m_constraints = other.m_constraints->clone (this);
3265
3266 return *this;
3267}
3268
3269/* Equality operator for region_model.
3270
3271 Amongst other things this directly compares the svalue and region
3272 vectors and so for this to be meaningful both this and OTHER should
3273 have been canonicalized. */
3274
3275bool
3276region_model::operator== (const region_model &other) const
3277{
3278 if (m_root_rid != other.m_root_rid)
3279 return false;
3280
3281 if (m_svalues.length () != other.m_svalues.length ())
3282 return false;
3283
3284 if (m_regions.length () != other.m_regions.length ())
3285 return false;
3286
3287 if (*m_constraints != *other.m_constraints)
3288 return false;
3289
3290 unsigned i;
3291 svalue *svalue;
3292 FOR_EACH_VEC_ELT (other.m_svalues, i, svalue)
3293 if (!(*m_svalues[i] == *other.m_svalues[i]))
3294 return false;
3295
3296 region *region;
3297 FOR_EACH_VEC_ELT (other.m_regions, i, region)
3298 if (!(*m_regions[i] == *other.m_regions[i]))
3299 return false;
3300
3301 gcc_checking_assert (hash () == other.hash ());
3302
3303 return true;
3304}
3305
3306/* Generate a hash value for this region_model. */
3307
3308hashval_t
3309region_model::hash () const
3310{
3311 hashval_t result = 0;
3312 int i;
3313
3314 svalue *svalue;
3315 FOR_EACH_VEC_ELT (m_svalues, i, svalue)
3316 result ^= svalue->hash ();
3317
3318 region *region;
3319 FOR_EACH_VEC_ELT (m_regions, i, region)
3320 result ^= region->hash ();
3321
3322 result ^= m_constraints->hash ();
3323
3324 return result;
3325}
3326
3327/* Print an all-on-one-line representation of this region_model to PP,
3328 which must support %E for trees. */
3329
3330void
3331region_model::print (pretty_printer *pp) const
3332{
3333 int i;
3334
3335 pp_string (pp, "svalues: [");
3336 svalue *svalue;
3337 FOR_EACH_VEC_ELT (m_svalues, i, svalue)
3338 {
3339 if (i > 0)
3340 pp_string (pp, ", ");
3341 print_svalue (svalue_id::from_int (i), pp);
3342 }
3343
3344 pp_string (pp, "], regions: [");
3345
3346 region *region;
3347 FOR_EACH_VEC_ELT (m_regions, i, region)
3348 {
3349 if (i > 0)
3350 pp_string (pp, ", ");
3351 region->print (*this, region_id::from_int (i), pp);
3352 }
3353
3354 pp_string (pp, "], constraints: ");
3355
3356 m_constraints->print (pp);
3357}
3358
3359/* Print the svalue with id SID to PP. */
3360
3361void
3362region_model::print_svalue (svalue_id sid, pretty_printer *pp) const
3363{
3364 get_svalue (sid)->print (*this, sid, pp);
3365}
3366
3367/* Dump a .dot representation of this region_model to PP, showing
3368 the values and the hierarchy of regions. */
3369
3370void
3371region_model::dump_dot_to_pp (pretty_printer *pp) const
3372{
3373 graphviz_out gv (pp);
3374
3375 pp_string (pp, "digraph \"");
3376 pp_write_text_to_stream (pp);
3377 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
3378 pp_string (pp, "\" {\n");
3379
3380 gv.indent ();
3381
3382 pp_string (pp, "overlap=false;\n");
3383 pp_string (pp, "compound=true;\n");
3384
3385 int i;
3386
3387 svalue *svalue;
3388 FOR_EACH_VEC_ELT (m_svalues, i, svalue)
3389 svalue->dump_dot_to_pp (*this, svalue_id::from_int (i), pp);
3390
3391 region *region;
3392 FOR_EACH_VEC_ELT (m_regions, i, region)
3393 region->dump_dot_to_pp (*this, region_id::from_int (i), pp);
3394
3395 /* TODO: constraints. */
3396
3397 /* Terminate "digraph" */
3398 gv.outdent ();
3399 pp_string (pp, "}");
3400 pp_newline (pp);
3401}
3402
3403/* Dump a .dot representation of this region_model to FP. */
3404
3405void
3406region_model::dump_dot_to_file (FILE *fp) const
3407{
3408 pretty_printer pp;
3409 pp_format_decoder (&pp) = default_tree_printer;
3410 pp.buffer->stream = fp;
3411 dump_dot_to_pp (&pp);
3412 pp_flush (&pp);
3413}
3414
3415/* Dump a .dot representation of this region_model to PATH. */
3416
3417void
3418region_model::dump_dot (const char *path) const
3419{
3420 FILE *fp = fopen (path, "w");
3421 dump_dot_to_file (fp);
3422 fclose (fp);
3423}
3424
3425/* Dump a multiline representation of this model to PP, showing the
3426 region hierarchy, the svalues, and any constraints.
3427
3428 If SUMMARIZE is true, show only the most pertient information,
3429 in a form that attempts to be less verbose.
3430 Otherwise, show all information. */
3431
3432void
3433region_model::dump_to_pp (pretty_printer *pp, bool summarize) const
3434{
3435 if (summarize)
3436 {
3437 bool is_first = true;
3438 region_id frame_id = get_current_frame_id ();
3439 frame_region *frame = get_region <frame_region> (frame_id);
3440 if (frame)
3441 dump_summary_of_map (pp, frame, &is_first);
3442
3443 region_id globals_id = get_globals_region_id ();
3444 map_region *globals = get_region <map_region> (globals_id);
3445 if (globals)
3446 dump_summary_of_map (pp, globals, &is_first);
3447
3448 unsigned i;
3449
3450 equiv_class *ec;
3451 FOR_EACH_VEC_ELT (m_constraints->m_equiv_classes, i, ec)
3452 {
3453 for (unsigned j = 0; j < ec->m_vars.length (); j++)
3454 {
3455 svalue_id lhs_sid = ec->m_vars[j];
3456 tree lhs_tree = get_representative_tree (lhs_sid);
3457 if (lhs_tree == NULL_TREE)
3458 continue;
3459 for (unsigned k = j + 1; k < ec->m_vars.length (); k++)
3460 {
3461 svalue_id rhs_sid = ec->m_vars[k];
3462 tree rhs_tree = get_representative_tree (rhs_sid);
3463 if (rhs_tree
3464 && !(CONSTANT_CLASS_P (lhs_tree)
3465 && CONSTANT_CLASS_P (rhs_tree)))
3466 {
3467 dump_separator (pp, &is_first);
3468 dump_tree (pp, lhs_tree);
3469 pp_string (pp, " == ");
3470 dump_tree (pp, rhs_tree);
3471 }
3472 }
3473 }
3474 }
3475
3476 constraint *c;
3477 FOR_EACH_VEC_ELT (m_constraints->m_constraints, i, c)
3478 {
3479 const equiv_class &lhs = c->m_lhs.get_obj (*m_constraints);
3480 const equiv_class &rhs = c->m_rhs.get_obj (*m_constraints);
3481 svalue_id lhs_sid = lhs.get_representative ();
3482 svalue_id rhs_sid = rhs.get_representative ();
3483 tree lhs_tree = get_representative_tree (lhs_sid);
3484 tree rhs_tree = get_representative_tree (rhs_sid);
3485 if (lhs_tree && rhs_tree
3486 && !(CONSTANT_CLASS_P (lhs_tree) && CONSTANT_CLASS_P (rhs_tree)))
3487 {
3488 dump_separator (pp, &is_first);
3489 dump_tree (pp, lhs_tree);
3490 pp_printf (pp, " %s ", constraint_op_code (c->m_op));
3491 dump_tree (pp, rhs_tree);
3492 }
3493 }
3494
3495 return;
3496 }
3497
3498 get_region (m_root_rid)->dump_to_pp (*this, m_root_rid, pp, "", true);
3499
3500 pp_string (pp, "svalues:");
3501 pp_newline (pp);
3502 int i;
3503 svalue *svalue;
3504 FOR_EACH_VEC_ELT (m_svalues, i, svalue)
3505 {
3506 pp_string (pp, " ");
3507 svalue_id sid = svalue_id::from_int (i);
3508 print_svalue (sid, pp);
3509 pp_newline (pp);
3510 }
3511
3512 pp_string (pp, "constraint manager:");
3513 pp_newline (pp);
3514 m_constraints->dump_to_pp (pp);
3515}
3516
3517/* Dump a multiline representation of this model to FILE. */
3518
3519void
3520region_model::dump (FILE *fp, bool summarize) const
3521{
3522 pretty_printer pp;
3523 pp_format_decoder (&pp) = default_tree_printer;
3524 pp_show_color (&pp) = pp_show_color (global_dc->printer);
3525 pp.buffer->stream = fp;
3526 dump_to_pp (&pp, summarize);
3527 pp_flush (&pp);
3528}
3529
3530/* Dump a multiline representation of this model to stderr. */
3531
3532DEBUG_FUNCTION void
3533region_model::dump (bool summarize) const
3534{
3535 dump (stderr, summarize);
3536}
3537
3538/* Dump RMODEL fully to stderr (i.e. without summarization). */
3539
3540DEBUG_FUNCTION void
3541region_model::debug () const
3542{
3543 dump (false);
3544}
3545
3546/* Dump VEC to PP, in the form "{VEC elements}: LABEL". */
3547
3548static void
3549dump_vec_of_tree (pretty_printer *pp,
3550 bool *is_first,
3551 const auto_vec<tree> &vec,
3552 const char *label)
3553{
3554 if (vec.length () == 0)
3555 return;
3556
3557 dump_separator (pp, is_first);
3558 pp_printf (pp, "{");
3559 unsigned i;
3560 tree key;
3561 FOR_EACH_VEC_ELT (vec, i, key)
3562 {
3563 if (i > 0)
3564 pp_string (pp, ", ");
3565 dump_tree (pp, key);
3566 }
3567 pp_printf (pp, "}: %s", label);
3568}
3569
3570/* Dump *MAP_REGION to PP in compact form, updating *IS_FIRST.
3571 Subroutine of region_model::dump_to_pp for use on stack frames and for
3572 the "globals" region. */
3573
3574void
3575region_model::dump_summary_of_map (pretty_printer *pp,
3576 map_region *map_region,
3577 bool *is_first) const
3578{
3579 /* Get the keys, sorted by tree_cmp. In particular, this ought
3580 to alphabetize any decls. */
3581 auto_vec<tree> keys (map_region->elements ());
3582 for (map_region::iterator_t iter = map_region->begin ();
3583 iter != map_region->end ();
3584 ++iter)
3585 {
3586 tree key_a = (*iter).first;
3587 keys.quick_push (key_a);
3588 }
3589 keys.qsort (tree_cmp);
3590
3591 /* Print pointers, constants, and poisoned values that aren't "uninit";
3592 gather keys for unknown and uninit values. */
3593 unsigned i;
3594 tree key;
3595 auto_vec<tree> unknown_keys;
3596 auto_vec<tree> uninit_keys;
3597 FOR_EACH_VEC_ELT (keys, i, key)
3598 {
3599 region_id child_rid = *map_region->get (key);
3600
3601 region *child_region = get_region (child_rid);
3602 if (!child_region)
3603 continue;
3604 svalue_id sid = child_region->get_value_direct ();
3605 if (sid.null_p ())
3606 continue;
3607 svalue *sval = get_svalue (sid);
3608 switch (sval->get_kind ())
3609 {
3610 default:
3611 gcc_unreachable ();
3612 case SK_REGION:
3613 {
3614 region_svalue *region_sval = as_a <region_svalue *> (sval);
3615 region_id pointee_rid = region_sval->get_pointee ();
3616 tree pointee = get_representative_path_var (pointee_rid).m_tree;
3617 dump_separator (pp, is_first);
3618 dump_tree (pp, key);
3619 pp_string (pp, ": ");
3620 if (pointee)
3621 {
3622 pp_character (pp, '&');
3623 dump_tree (pp, pointee);
3624 }
3625 else
3626 pp_string (pp, "NULL");
3627 }
3628 break;
3629 case SK_CONSTANT:
3630 dump_separator (pp, is_first);
3631 dump_tree (pp, key);
3632 pp_string (pp, ": ");
3633 dump_tree (pp, sval->dyn_cast_constant_svalue ()->get_constant ());
3634 break;
3635 case SK_UNKNOWN:
3636 unknown_keys.safe_push (key);
3637 break;
3638 case SK_POISONED:
3639 {
3640 poisoned_svalue *poisoned_sval = as_a <poisoned_svalue *> (sval);
3641 enum poison_kind pkind = poisoned_sval->get_poison_kind ();
3642 if (pkind == POISON_KIND_UNINIT)
3643 uninit_keys.safe_push (key);
3644 else
3645 {
3646 dump_separator (pp, is_first);
3647 dump_tree (pp, key);
3648 pp_printf (pp, ": %s", poison_kind_to_str (pkind));
3649 }
3650 }
3651 break;
3652 case SK_SETJMP:
3653 dump_separator (pp, is_first);
3654 pp_printf (pp, "setjmp: EN: %i",
3655 sval->dyn_cast_setjmp_svalue ()->get_index ());
3656 break;
3657 }
3658 }
3659
3660 /* Print unknown and uninitialized values in consolidated form. */
3661 dump_vec_of_tree (pp, is_first, unknown_keys, "unknown");
3662 dump_vec_of_tree (pp, is_first, uninit_keys, "uninit");
3663}
3664
3665/* Assert that this object is valid. */
3666
3667void
3668region_model::validate () const
3669{
3670 /* Skip this in a release build. */
3671#if !CHECKING_P
3672 return;
3673#endif
3674
3675 m_constraints->validate ();
3676
3677 unsigned i;
3678 region *r;
3679 FOR_EACH_VEC_ELT (m_regions, i, r)
3680 r->validate (this);
3681
3682 // TODO: anything else?
3683
3684 /* Verify that the stack region (if any) has an "uninitialized" value. */
3685 region *stack_region = get_root_region ()->get_stack_region (this);
3686 if (stack_region)
3687 {
3688 svalue_id stack_value_sid = stack_region->get_value_direct ();
3689 svalue *stack_value = get_svalue (stack_value_sid);
3690 gcc_assert (stack_value->get_kind () == SK_POISONED);
3691 poisoned_svalue *subclass = stack_value->dyn_cast_poisoned_svalue ();
3692 gcc_assert (subclass);
3693 gcc_assert (subclass->get_poison_kind () == POISON_KIND_UNINIT);
3694 }
3695}
3696
3697/* Global data for use by svalue_id_cmp_by_constant_svalue. */
3698
3699static region_model *svalue_id_cmp_by_constant_svalue_model = NULL;
3700
3701/* Comparator for use by region_model::canonicalize. */
3702
3703static int
3704svalue_id_cmp_by_constant_svalue (const void *p1, const void *p2)
3705{
3706 const svalue_id *sid1 = (const svalue_id *)p1;
3707 const svalue_id *sid2 = (const svalue_id *)p2;
3708 gcc_assert (!sid1->null_p ());
3709 gcc_assert (!sid2->null_p ());
3710 gcc_assert (svalue_id_cmp_by_constant_svalue_model);
3711 const svalue &sval1
3712 = *svalue_id_cmp_by_constant_svalue_model->get_svalue (*sid1);
3713 const svalue &sval2
3714 = *svalue_id_cmp_by_constant_svalue_model->get_svalue (*sid2);
3715 gcc_assert (sval1.get_kind () == SK_CONSTANT);
3716 gcc_assert (sval2.get_kind () == SK_CONSTANT);
3717
3718 tree cst1 = ((const constant_svalue &)sval1).get_constant ();
3719 tree cst2 = ((const constant_svalue &)sval2).get_constant ();
3720 return tree_cmp (cst1, cst2);
3721}
3722
3723/* Reorder the regions and svalues into a deterministic "canonical" order,
3724 to maximize the chance of equality.
3725 If non-NULL, notify CTXT about the svalue id remapping. */
3726
3727void
3728region_model::canonicalize (region_model_context *ctxt)
3729{
3730 /* Walk all regions and values in a deterministic order, visiting
3731 rids and sids, generating a rid and sid map. */
3732 canonicalization c (*this);
3733
3734 /* (1): Walk all svalues, putting constants first, sorting the constants
3735 (thus imposing an ordering on any constants that are purely referenced
3736 by constraints).
3737 Ignore other svalues for now. */
3738 {
3739 unsigned i;
3740 auto_vec<svalue_id> sids;
3741 svalue *sval;
3742 FOR_EACH_VEC_ELT (m_svalues, i, sval)
3743 {
3744 if (sval->get_kind () == SK_CONSTANT)
3745 sids.safe_push (svalue_id::from_int (i));
3746 }
3747 svalue_id_cmp_by_constant_svalue_model = this;
3748 sids.qsort (svalue_id_cmp_by_constant_svalue);
3749 svalue_id_cmp_by_constant_svalue_model = NULL;
3750 svalue_id *sid;
3751 FOR_EACH_VEC_ELT (sids, i, sid)
3752 c.walk_sid (*sid);
3753 }
3754
3755 /* (2): Walk all regions (and thus their values) in a deterministic
3756 order. */
3757 c.walk_rid (m_root_rid);
3758
3759 /* (3): Ensure we've visited everything, as we don't want to purge
3760 at this stage. Anything we visit for the first time here has
3761 arbitrary order. */
3762 {
3763 unsigned i;
3764 region *region;
3765 FOR_EACH_VEC_ELT (m_regions, i, region)
3766 c.walk_rid (region_id::from_int (i));
3767 svalue *sval;
3768 FOR_EACH_VEC_ELT (m_svalues, i, sval)
3769 c.walk_sid (svalue_id::from_int (i));
3770 }
3771
3772 /* (4): We now have a reordering of the regions and values.
3773 Apply it. */
3774 remap_svalue_ids (c.m_sid_map);
3775 remap_region_ids (c.m_rid_map);
3776 if (ctxt)
3777 ctxt->remap_svalue_ids (c.m_sid_map);
3778
3779 /* (5): Canonicalize the constraint_manager (it has already had its
3780 svalue_ids remapped above). This makes use of the new svalue_id
3781 values, and so must happen last. */
3782 m_constraints->canonicalize (get_num_svalues ());
3783
3784 validate ();
3785}
3786
3787/* Return true if this region_model is in canonical form. */
3788
3789bool
3790region_model::canonicalized_p () const
3791{
3792 region_model copy (*this);
3793 copy.canonicalize (NULL);
3794 return *this == copy;
3795}
3796
3797/* A subclass of pending_diagnostic for complaining about uses of
3798 poisoned values. */
3799
3800class poisoned_value_diagnostic
3801: public pending_diagnostic_subclass<poisoned_value_diagnostic>
3802{
3803public:
3804 poisoned_value_diagnostic (tree expr, enum poison_kind pkind)
3805 : m_expr (expr), m_pkind (pkind)
3806 {}
3807
3808 const char *get_kind () const FINAL OVERRIDE { return "poisoned_value_diagnostic"; }
3809
3810 bool operator== (const poisoned_value_diagnostic &other) const
3811 {
3812 return m_expr == other.m_expr;
3813 }
3814
3815 bool emit (rich_location *rich_loc) FINAL OVERRIDE
3816 {
3817 switch (m_pkind)
3818 {
3819 default:
3820 gcc_unreachable ();
3821 case POISON_KIND_UNINIT:
3822 {
3823 diagnostic_metadata m;
3824 m.add_cwe (457); /* "CWE-457: Use of Uninitialized Variable". */
3825 return warning_at (rich_loc, m,
3826 OPT_Wanalyzer_use_of_uninitialized_value,
3827 "use of uninitialized value %qE",
3828 m_expr);
3829 }
3830 break;
3831 case POISON_KIND_FREED:
3832 {
3833 diagnostic_metadata m;
3834 m.add_cwe (416); /* "CWE-416: Use After Free". */
3835 return warning_at (rich_loc, m,
3836 OPT_Wanalyzer_use_after_free,
3837 "use after %<free%> of %qE",
3838 m_expr);
3839 }
3840 break;
3841 case POISON_KIND_POPPED_STACK:
3842 {
3843 diagnostic_metadata m;
3844 /* TODO: which CWE? */
3845 return warning_at (rich_loc, m,
3846 OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame,
3847 "use of pointer %qE within stale stack frame",
3848 m_expr);
3849 }
3850 break;
3851 }
3852 }
3853
3854 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
3855 {
3856 switch (m_pkind)
3857 {
3858 default:
3859 gcc_unreachable ();
3860 case POISON_KIND_UNINIT:
3861 return ev.formatted_print ("use of uninitialized value %qE here",
3862 m_expr);
3863 case POISON_KIND_FREED:
3864 return ev.formatted_print ("use after %<free%> of %qE here",
3865 m_expr);
3866 case POISON_KIND_POPPED_STACK:
3867 return ev.formatted_print
3868 ("use of pointer %qE within stale stack frame here",
3869 m_expr);
3870 }
3871 }
3872
3873private:
3874 tree m_expr;
3875 enum poison_kind m_pkind;
3876};
3877
3878/* Determine if EXPR is poisoned, and if so, queue a diagnostic to CTXT. */
3879
3880void
3881region_model::check_for_poison (tree expr, region_model_context *ctxt)
3882{
3883 if (!ctxt)
3884 return;
3885
3886 // TODO: this is disabled for now (too many false positives)
3887 return;
3888
3889 svalue_id expr_sid = get_rvalue (expr, ctxt);
3890 gcc_assert (!expr_sid.null_p ());
3891 svalue *expr_svalue = get_svalue (expr_sid);
3892 gcc_assert (expr_svalue);
3893 if (const poisoned_svalue *poisoned_sval
3894 = expr_svalue->dyn_cast_poisoned_svalue ())
3895 {
3896 enum poison_kind pkind = poisoned_sval->get_poison_kind ();
3897 ctxt->warn (new poisoned_value_diagnostic (expr, pkind));
3898 }
3899}
3900
3901/* Update this model for the ASSIGN stmt, using CTXT to report any
3902 diagnostics. */
3903
3904void
3905region_model::on_assignment (const gassign *assign, region_model_context *ctxt)
3906{
3907 tree lhs = gimple_assign_lhs (assign);
3908 tree rhs1 = gimple_assign_rhs1 (assign);
3909
3910 region_id lhs_rid = get_lvalue (lhs, ctxt);
3911
3912 /* Check for uses of poisoned values. */
3913 switch (get_gimple_rhs_class (gimple_expr_code (assign)))
3914 {
3915 case GIMPLE_INVALID_RHS:
3916 gcc_unreachable ();
3917 break;
3918 case GIMPLE_TERNARY_RHS:
3919 check_for_poison (gimple_assign_rhs3 (assign), ctxt);
3920 /* Fallthru */
3921 case GIMPLE_BINARY_RHS:
3922 check_for_poison (gimple_assign_rhs2 (assign), ctxt);
3923 /* Fallthru */
3924 case GIMPLE_UNARY_RHS:
3925 case GIMPLE_SINGLE_RHS:
3926 check_for_poison (gimple_assign_rhs1 (assign), ctxt);
3927 }
3928
3929 if (lhs_rid.null_p ())
3930 return;
3931 // TODO: issue a warning for this case
3932
3933 enum tree_code op = gimple_assign_rhs_code (assign);
3934 switch (op)
3935 {
3936 default:
3937 {
3938 if (0)
3939 sorry_at (assign->location, "unhandled assignment op: %qs",
3940 get_tree_code_name (op));
3941 set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
3942 }
3943 break;
3944
3945 case BIT_FIELD_REF:
3946 {
3947 // TODO
3948 }
3949 break;
3950
3951 case CONSTRUCTOR:
3952 {
3953 /* e.g. "x ={v} {CLOBBER};" */
3954 // TODO
3955 }
3956 break;
3957
3958 case POINTER_PLUS_EXPR:
3959 {
3960 /* e.g. "_1 = a_10(D) + 12;" */
3961 tree ptr = rhs1;
3962 tree offset = gimple_assign_rhs2 (assign);
3963
3964 svalue_id ptr_sid = get_rvalue (ptr, ctxt);
3965 svalue_id offset_sid = get_rvalue (offset, ctxt);
3966 region_id element_rid
3967 = get_or_create_pointer_plus_expr (TREE_TYPE (TREE_TYPE (ptr)),
3968 ptr_sid, offset_sid,
3969 ctxt);
3970 svalue_id element_ptr_sid
3971 = get_or_create_ptr_svalue (TREE_TYPE (ptr), element_rid);
3972 set_value (lhs_rid, element_ptr_sid, ctxt);
3973 }
3974 break;
3975
3976 case POINTER_DIFF_EXPR:
3977 {
3978 /* e.g. "_1 = p_2(D) - q_3(D);". */
3979
3980 /* TODO. */
3981
3982 set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
3983 }
3984 break;
3985
3986 case ADDR_EXPR:
3987 {
3988 /* LHS = &RHS; */
3989 svalue_id ptr_sid = get_rvalue (rhs1, ctxt);
3990 set_value (lhs_rid, ptr_sid, ctxt);
3991 }
3992 break;
3993
3994 case MEM_REF:
3995 {
3996 region_id rhs_rid = get_lvalue (rhs1, ctxt);
3997 svalue_id rhs_sid
3998 = get_region (rhs_rid)->get_value (*this, true, ctxt);
3999 set_value (lhs_rid, rhs_sid, ctxt);
4000 }
4001 break;
4002
4003 case REAL_CST:
4004 case INTEGER_CST:
4005 case ARRAY_REF:
4006 {
4007 /* LHS = RHS; */
4008 svalue_id cst_sid = get_rvalue (rhs1, ctxt);
4009 set_value (lhs_rid, cst_sid, ctxt);
4010 }
4011 break;
4012
4013 case FIX_TRUNC_EXPR:
4014 case FLOAT_EXPR:
4015 case NOP_EXPR:
4016 // cast: TODO
4017 // fall though for now
4018 case SSA_NAME:
4019 case VAR_DECL:
4020 case PARM_DECL:
4021 {
4022 /* LHS = VAR; */
4023 svalue_id var_sid = get_rvalue (rhs1, ctxt);
4024 set_value (lhs_rid, var_sid, ctxt);
4025 }
4026 break;
4027
4028 case EQ_EXPR:
4029 case GE_EXPR:
4030 case LE_EXPR:
4031 case NE_EXPR:
4032 case GT_EXPR:
4033 case LT_EXPR:
4034 {
4035 tree rhs2 = gimple_assign_rhs2 (assign);
4036
4037 // TODO: constraints between svalues
4038 svalue_id rhs1_sid = get_rvalue (rhs1, ctxt);
4039 svalue_id rhs2_sid = get_rvalue (rhs2, ctxt);
4040
4041 tristate t = eval_condition (rhs1_sid, op, rhs2_sid);
4042 if (t.is_known ())
4043 set_value (lhs_rid,
4044 get_rvalue (t.is_true ()
4045 ? boolean_true_node
4046 : boolean_false_node,
4047 ctxt),
4048 ctxt);
4049 else
4050 set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
4051 }
4052 break;
4053
4054 case NEGATE_EXPR:
4055 case BIT_NOT_EXPR:
4056 {
4057 // TODO: unary ops
4058
4059 // TODO: constant?
4060
4061 set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
4062 }
4063 break;
4064
4065 case PLUS_EXPR:
4066 case MINUS_EXPR:
4067 case MULT_EXPR:
4068 case TRUNC_DIV_EXPR:
4069 case TRUNC_MOD_EXPR:
4070 case LSHIFT_EXPR:
4071 case RSHIFT_EXPR:
4072 case BIT_IOR_EXPR:
4073 case BIT_XOR_EXPR:
4074 case BIT_AND_EXPR:
4075 case MIN_EXPR:
4076 case MAX_EXPR:
4077 {
4078 /* Binary ops. */
4079 tree rhs2 = gimple_assign_rhs2 (assign);
4080
4081 svalue_id rhs1_sid = get_rvalue (rhs1, ctxt);
4082 svalue_id rhs2_sid = get_rvalue (rhs2, ctxt);
4083
4084 if (tree rhs1_cst = maybe_get_constant (rhs1_sid))
4085 if (tree rhs2_cst = maybe_get_constant (rhs2_sid))
4086 {
4087 tree result = fold_build2 (op, TREE_TYPE (lhs),
4088 rhs1_cst, rhs2_cst);
4089 if (CONSTANT_CLASS_P (result))
4090 {
4091 svalue_id result_sid
4092 = get_or_create_constant_svalue (result);
4093 set_value (lhs_rid, result_sid, ctxt);
4094 return;
4095 }
4096 }
4097 set_to_new_unknown_value (lhs_rid, TREE_TYPE (lhs), ctxt);
4098 }
4099 break;
4100
4101 case COMPONENT_REF:
4102 {
4103 /* LHS = op0.op1; */
4104 region_id child_rid = get_lvalue (rhs1, ctxt);
4105 svalue_id child_sid
4106 = get_region (child_rid)->get_value (*this, true, ctxt);
4107 set_value (lhs_rid, child_sid, ctxt);
4108 }
4109 break;
4110 }
4111}
4112
4113/* Update this model for the CALL stmt, using CTXT to report any
4114 diagnostics - the first half.
4115
4116 Updates to the region_model that should be made *before* sm-states
4117 are updated are done here; other updates to the region_model are done
4118 in region_model::on_call_post. */
4119
4120void
4121region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
4122{
4123 region_id lhs_rid;
4124 tree lhs_type = NULL_TREE;
4125 if (tree lhs = gimple_call_lhs (call))
4126 {
4127 lhs_rid = get_lvalue (lhs, ctxt);
4128 lhs_type = TREE_TYPE (lhs);
4129 }
4130
4131 /* Check for uses of poisoned values.
4132 For now, special-case "free", to avoid warning about "use-after-free"
4133 when "double free" would be more precise. */
4134 if (!is_special_named_call_p (call, "free", 1))
4135 for (unsigned i = 0; i < gimple_call_num_args (call); i++)
4136 check_for_poison (gimple_call_arg (call, i), ctxt);
4137
4138 if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
4139 {
4140 if (is_named_call_p (callee_fndecl, "malloc", call, 1))
4141 {
4142 // TODO: capture size as a svalue?
4143 region_id new_rid = add_new_malloc_region ();
4144 if (!lhs_rid.null_p ())
4145 {
4146 svalue_id ptr_sid
4147 = get_or_create_ptr_svalue (lhs_type, new_rid);
4148 set_value (lhs_rid, ptr_sid, ctxt);
4149 }
4150 return;
4151 }
4152 else if (is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1))
4153 {
4154 region_id frame_rid = get_current_frame_id ();
4155 region_id new_rid
4156 = add_region (new symbolic_region (frame_rid, false));
4157 if (!lhs_rid.null_p ())
4158 {
4159 svalue_id ptr_sid
4160 = get_or_create_ptr_svalue (lhs_type, new_rid);
4161 set_value (lhs_rid, ptr_sid, ctxt);
4162 }
4163 return;
4164 }
4165 else if (is_named_call_p (callee_fndecl, "strlen", call, 1))
4166 {
4167 region_id buf_rid = deref_rvalue (gimple_call_arg (call, 0), ctxt);
4168 svalue_id buf_sid
4169 = get_region (buf_rid)->get_value (*this, true, ctxt);
4170 if (tree cst_expr = maybe_get_constant (buf_sid))
4171 {
4172 if (TREE_CODE (cst_expr) == STRING_CST
4173 && !lhs_rid.null_p ())
4174 {
4175 /* TREE_STRING_LENGTH is sizeof, not strlen. */
4176 int sizeof_cst = TREE_STRING_LENGTH (cst_expr);
4177 int strlen_cst = sizeof_cst - 1;
4178 tree t_cst = build_int_cst (lhs_type, strlen_cst);
4179 svalue_id result_sid
4180 = get_or_create_constant_svalue (t_cst);
4181 set_value (lhs_rid, result_sid, ctxt);
4182 return;
4183 }
4184 }
4185 /* Otherwise an unknown value. */
4186 }
4187 else if (is_named_call_p (callee_fndecl,
4188 "__analyzer_dump_num_heap_regions", call, 0))
4189 {
4190 /* Handle the builtin "__analyzer_dump_num_heap_regions" by emitting
4191 a warning (for use in DejaGnu tests). */
4192 int num_heap_regions = 0;
4193 region_id heap_rid = get_root_region ()->ensure_heap_region (this);
4194 unsigned i;
4195 region *region;
4196 FOR_EACH_VEC_ELT (m_regions, i, region)
4197 if (region->get_parent () == heap_rid)
4198 num_heap_regions++;
4199 /* Use quotes to ensure the output isn't truncated. */
4200 warning_at (call->location, 0,
4201 "num heap regions: %qi", num_heap_regions);
4202 }
4203 }
4204
4205 /* Unrecognized call. */
4206
4207 /* Unknown return value. */
4208 if (!lhs_rid.null_p ())
4209 set_to_new_unknown_value (lhs_rid, lhs_type, ctxt);
4210
4211 /* TODO: also, any pointer arguments might have been written through,
4212 or the things they point to (implying a graph traversal, which
4213 presumably we need to do before overwriting the old value). */
4214}
4215
4216/* Update this model for the CALL stmt, using CTXT to report any
4217 diagnostics - the second half.
4218
4219 Updates to the region_model that should be made *after* sm-states
4220 are updated are done here; other updates to the region_model are done
4221 in region_model::on_call_pre. */
4222
4223void
4224region_model::on_call_post (const gcall *call, region_model_context *ctxt)
4225{
4226 /* Update for "free" here, after sm-handling.
4227
4228 If the ptr points to an underlying heap region, delete the region,
4229 poisoning pointers to it and regions within it.
4230
4231 We delay this until after sm-state has been updated so that the
4232 sm-handling can transition all of the various casts of the pointer
4233 to a "freed" state *before* we delete the related region here.
4234
4235 This has to be done here so that the sm-handling can use the fact
4236 that they point to the same region to establish that they are equal
4237 (in region_model::eval_condition_without_cm), and thus transition
4238 all pointers to the region to the "freed" state together, regardless
4239 of casts. */
4240 if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
4241 if (is_named_call_p (callee_fndecl, "free", call, 1))
4242 {
4243 tree ptr = gimple_call_arg (call, 0);
4244 svalue_id ptr_sid = get_rvalue (ptr, ctxt);
4245 svalue *ptr_sval = get_svalue (ptr_sid);
4246 if (region_svalue *ptr_to_region_sval
4247 = ptr_sval->dyn_cast_region_svalue ())
4248 {
4249 /* If the ptr points to an underlying heap region, delete it,
4250 poisoning pointers. */
4251 region_id pointee_rid = ptr_to_region_sval->get_pointee ();
4252 region_id heap_rid = get_root_region ()->ensure_heap_region (this);
4253 if (!pointee_rid.null_p ()
4254 && get_region (pointee_rid)->get_parent () == heap_rid)
4255 {
4256 purge_stats stats;
4257 delete_region_and_descendents (pointee_rid,
4258 POISON_KIND_FREED,
4259 &stats, ctxt->get_logger ());
4260 purge_unused_svalues (&stats, ctxt);
4261 validate ();
4262 // TODO: do anything with stats?
4263 }
4264 }
4265 return;
4266 }
4267}
4268
4269/* Update this model for the RETURN_STMT, using CTXT to report any
4270 diagnostics. */
4271
4272void
4273region_model::on_return (const greturn *return_stmt, region_model_context *ctxt)
4274{
4275 tree callee = get_current_function ()->decl;
4276 tree lhs = DECL_RESULT (callee);
4277 tree rhs = gimple_return_retval (return_stmt);
4278
4279 if (lhs && rhs)
4280 set_value (get_lvalue (lhs, ctxt), get_rvalue (rhs, ctxt), ctxt);
4281}
4282
4283/* Update this model for a call and return of "setjmp" at CALL within ENODE,
4284 using CTXT to report any diagnostics.
4285
4286 This is for the initial direct invocation of setjmp (which returns 0),
4287 as opposed to any second return due to longjmp. */
4288
4289void
4290region_model::on_setjmp (const gcall *call, const exploded_node *enode,
4291 region_model_context *ctxt)
4292{
4293 region_id buf_rid = deref_rvalue (gimple_call_arg (call, 0), ctxt);
4294 region *buf = get_region (buf_rid);
4295
4296 /* Create a setjmp_svalue for ENODE and store it in BUF_RID's region. */
4297 if (buf)
4298 {
4299 svalue *sval = new setjmp_svalue (enode, buf->get_type ());
4300 svalue_id new_sid = add_svalue (sval);
4301 set_value (buf_rid, new_sid, ctxt);
4302 }
4303
4304 /* Direct calls to setjmp return 0. */
4305 if (tree lhs = gimple_call_lhs (call))
4306 {
4307 tree zero = build_int_cst (TREE_TYPE (lhs), 0);
4308 svalue_id new_sid = get_or_create_constant_svalue (zero);
4309 region_id lhs_rid = get_lvalue (lhs, ctxt);
4310 set_value (lhs_rid, new_sid, ctxt);
4311 }
4312}
4313
4314/* Update this region_model for rewinding from a "longjmp" at LONGJMP_CALL
4315 to a "setjmp" at SETJMP_CALL where the final stack depth should be
4316 SETJMP_STACK_DEPTH. Purge any stack frames, potentially reporting on
4317 leaks to CTXT. */
4318
4319void
4320region_model::on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
4321 int setjmp_stack_depth,
4322 region_model_context *ctxt)
4323{
4324 /* Evaluate the val, using the frame of the "longjmp". */
4325 tree fake_retval = gimple_call_arg (longjmp_call, 1);
4326 svalue_id fake_retval_sid = get_rvalue (fake_retval, ctxt);
4327
4328 /* Pop any frames until we reach the stack depth of the function where
4329 setjmp was called. */
4330 gcc_assert (get_stack_depth () >= setjmp_stack_depth);
4331 while (get_stack_depth () > setjmp_stack_depth)
4332 {
4333 /* Don't purge unused svalues yet, as we're using fake_retval_sid. */
4334 pop_frame (false, NULL, ctxt);
4335 }
4336
4337 gcc_assert (get_stack_depth () == setjmp_stack_depth);
4338
4339 /* Assign to LHS of "setjmp" in new_state. */
4340 if (tree lhs = gimple_call_lhs (setjmp_call))
4341 {
4342 /* Passing 0 as the val to longjmp leads to setjmp returning 1. */
4343 tree t_zero = build_int_cst (TREE_TYPE (fake_retval), 0);
4344 svalue_id zero_sid = get_or_create_constant_svalue (t_zero);
4345 tristate eq_zero = eval_condition (fake_retval_sid, EQ_EXPR, zero_sid);
4346 /* If we have 0, use 1. */
4347 if (eq_zero.is_true ())
4348 {
4349 tree t_one = build_int_cst (TREE_TYPE (fake_retval), 1);
4350 svalue_id one_sid = get_or_create_constant_svalue (t_one);
4351 fake_retval_sid = one_sid;
4352 }
4353 else
4354 {
4355 /* Otherwise note that the value is nonzero. */
4356 m_constraints->add_constraint (fake_retval_sid, NE_EXPR, zero_sid);
4357 }
4358
4359 region_id lhs_rid = get_lvalue (lhs, ctxt);
4360 set_value (lhs_rid, fake_retval_sid, ctxt);
4361 }
4362
4363 /* Now that we've assigned the fake_retval, we can purge the unused
4364 svalues, which could detect leaks. */
4365 purge_unused_svalues (NULL, ctxt, NULL);
4366 validate ();
4367}
4368
4369/* Update this region_model for a phi stmt of the form
4370 LHS = PHI <...RHS...>.
4371 where RHS is for the appropriate edge. */
4372
4373void
4374region_model::handle_phi (tree lhs, tree rhs, bool is_back_edge,
4375 region_model_context *ctxt)
4376{
4377 /* For now, don't bother tracking the .MEM SSA names. */
4378 if (tree var = SSA_NAME_VAR (lhs))
4379 if (TREE_CODE (var) == VAR_DECL)
4380 if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
4381 return;
4382
4383 svalue_id rhs_sid = get_rvalue (rhs, ctxt);
4384
4385 if (is_back_edge && get_svalue (rhs_sid)->get_kind () != SK_UNKNOWN)
4386 {
4387 /* If we have a back edge, we probably have a loop.
4388 Use an unknown value, to avoid effectively unrolling the
4389 loop.
4390 To terminate, we need to avoid generating a series of
4391 models with an unbounded monotonically increasing number of
4392 redundant unknown values; hence we need to purge svalues
4393 before inserting the state into the exploded graph, to
4394 collect unused svalues. */
4395 set_to_new_unknown_value (get_lvalue (lhs, ctxt), TREE_TYPE (lhs), ctxt);
4396 }
4397 else
4398 set_value (get_lvalue (lhs, ctxt), rhs_sid, ctxt);
4399}
4400
4401/* Implementation of region_model::get_lvalue; the latter adds type-checking.
4402
4403 Get the id of the region for PV within this region_model,
4404 emitting any diagnostics to CTXT. */
4405
4406region_id
4407region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
4408{
4409 tree expr = pv.m_tree;
4410
4411 gcc_assert (expr);
4412
4413 switch (TREE_CODE (expr))
4414 {
4415 default:
4416 gcc_unreachable ();
4417
4418 case ARRAY_REF:
4419 {
4420 tree array = TREE_OPERAND (expr, 0);
4421 tree index = TREE_OPERAND (expr, 1);
4422#if 0
4423 // TODO: operands 2 and 3, if present:
4424 gcc_assert (TREE_OPERAND (expr, 2) == NULL_TREE);
4425 gcc_assert (TREE_OPERAND (expr, 3) == NULL_TREE);
4426#endif
4427
4428 region_id array_rid = get_lvalue (array, ctxt);
4429 svalue_id index_sid = get_rvalue (index, ctxt);
4430 array_region *array_reg = get_region<array_region> (array_rid);
4431 return array_reg->get_element (this, array_rid, index_sid, ctxt);
4432 }
4433 break;
4434
4435 case MEM_REF:
4436 {
4437 tree ptr = TREE_OPERAND (expr, 0);
4438 tree offset = TREE_OPERAND (expr, 1);
4439 svalue_id ptr_sid = get_rvalue (ptr, ctxt);
4440 svalue_id offset_sid = get_rvalue (offset, ctxt);
4441 return get_or_create_mem_ref (TREE_TYPE (expr), ptr_sid,
4442 offset_sid, ctxt);
4443 }
4444 break;
4445
4446 case VAR_DECL:
4447 /* Handle globals. */
4448 if (is_global_var (expr))
4449 {
4450 region_id globals_rid
4451 = get_root_region ()->ensure_globals_region (this);
4452 map_region *globals = get_region<map_region> (globals_rid);
4453 region_id var_rid = globals->get_or_create (this, globals_rid, expr,
4454 TREE_TYPE (expr));
4455 return var_rid;
4456 }
4457
4458 /* Fall through. */
4459
4460 case SSA_NAME:
4461 case PARM_DECL:
4462 case RESULT_DECL:
4463 {
4464 gcc_assert (TREE_CODE (expr) == SSA_NAME
4465 || TREE_CODE (expr) == PARM_DECL
4466 || TREE_CODE (expr) == VAR_DECL
4467 || TREE_CODE (expr) == RESULT_DECL);
4468
4469 int stack_depth = pv.m_stack_depth;
4470 stack_region *stack = get_root_region ()->get_stack_region (this);
4471 gcc_assert (stack);
4472 region_id frame_rid = stack->get_frame_rid (stack_depth);
4473 frame_region *frame = get_region <frame_region> (frame_rid);
4474 gcc_assert (frame);
4475 region_id child_rid = frame->get_or_create (this, frame_rid, expr,
4476 TREE_TYPE (expr));
4477 return child_rid;
4478 }
4479
4480 case COMPONENT_REF:
4481 {
4482 /* obj.field */
4483 tree obj = TREE_OPERAND (expr, 0);
4484 tree field = TREE_OPERAND (expr, 1);
4485 region_id obj_rid = get_lvalue (obj, ctxt);
4486 region_id struct_or_union_rid
4487 = get_or_create_view (obj_rid, TREE_TYPE (obj));
4488 return get_field_region (struct_or_union_rid, field);
4489 }
4490 break;
4491
4492 case STRING_CST:
4493 {
4494 tree cst_type = TREE_TYPE (expr);
4495 array_region *cst_region = new array_region (m_root_rid, cst_type);
4496 region_id cst_rid = add_region (cst_region);
4497 svalue_id cst_sid = get_or_create_constant_svalue (expr);
4498 cst_region->set_value (*this, cst_rid, cst_sid, ctxt);
4499 return cst_rid;
4500 }
4501 break;
4502 }
4503}
4504
4505/* Assert that SRC_TYPE can be converted to DST_TYPE as a no-op. */
4506
4507#define ASSERT_COMPAT_TYPES(SRC_TYPE, DST_TYPE) \
4508 gcc_checking_assert (useless_type_conversion_p ((SRC_TYPE), (DST_TYPE)))
4509
4510/* Get the id of the region for PV within this region_model,
4511 emitting any diagnostics to CTXT. */
4512
4513region_id
4514region_model::get_lvalue (path_var pv, region_model_context *ctxt)
4515{
4516 if (pv.m_tree == NULL_TREE)
4517 return region_id::null ();
4518
4519 region_id result_rid = get_lvalue_1 (pv, ctxt);
4520 ASSERT_COMPAT_TYPES (get_region (result_rid)->get_type (),
4521 TREE_TYPE (pv.m_tree));
4522 return result_rid;
4523}
4524
4525/* Get the region_id for EXPR within this region_model (assuming the most
4526 recent stack frame if it's a local). */
4527
4528region_id
4529region_model::get_lvalue (tree expr, region_model_context *ctxt)
4530{
4531 return get_lvalue (path_var (expr, get_stack_depth () - 1), ctxt);
4532}
4533
4534/* Implementation of region_model::get_rvalue; the latter adds type-checking.
4535
4536 Get the value of PV within this region_model,
4537 emitting any diagnostics to CTXT. */
4538
4539svalue_id
4540region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt)
4541{
4542 gcc_assert (pv.m_tree);
4543
4544 switch (TREE_CODE (pv.m_tree))
4545 {
4546 default:
4547 {
4548 svalue *unknown_sval = new unknown_svalue (TREE_TYPE (pv.m_tree));
4549 return add_svalue (unknown_sval);
4550 }
4551 break;
4552
4553 case ADDR_EXPR:
4554 {
4555 /* "&EXPR". */
4556 tree expr = pv.m_tree;
4557 tree op0 = TREE_OPERAND (expr, 0);
4558 if (TREE_CODE (op0) == FUNCTION_DECL)
4559 return get_svalue_for_fndecl (TREE_TYPE (expr), op0);
4560 else if (TREE_CODE (op0) == LABEL_DECL)
4561 return get_svalue_for_label (TREE_TYPE (expr), op0);
4562 region_id expr_rid = get_lvalue (op0, ctxt);
4563 return get_or_create_ptr_svalue (TREE_TYPE (expr), expr_rid);
4564 }
4565 break;
4566
4567 case ARRAY_REF:
4568 {
4569 region_id element_rid = get_lvalue (pv, ctxt);
4570 return get_region (element_rid)->get_value (*this, true, ctxt);
4571 }
4572
4573 case INTEGER_CST:
4574 case REAL_CST:
4575 case STRING_CST:
4576 return get_or_create_constant_svalue (pv.m_tree);
4577
4578 case COMPONENT_REF:
4579 case MEM_REF:
4580 case SSA_NAME:
4581 case VAR_DECL:
4582 case PARM_DECL:
4583 case RESULT_DECL:
4584 {
4585 region_id var_rid = get_lvalue (pv, ctxt);
4586 return get_region (var_rid)->get_value (*this, true, ctxt);
4587 }
4588 }
4589}
4590
4591/* Get the value of PV within this region_model,
4592 emitting any diagnostics to CTXT. */
4593
4594svalue_id
4595region_model::get_rvalue (path_var pv, region_model_context *ctxt)
4596{
4597 if (pv.m_tree == NULL_TREE)
4598 return svalue_id::null ();
4599 svalue_id result_sid = get_rvalue_1 (pv, ctxt);
4600
4601 ASSERT_COMPAT_TYPES (get_svalue (result_sid)->get_type (),
4602 TREE_TYPE (pv.m_tree));
4603
4604 return result_sid;
4605}
4606
4607/* Get the value of EXPR within this region_model (assuming the most
4608 recent stack frame if it's a local). */
4609
4610svalue_id
4611region_model::get_rvalue (tree expr, region_model_context *ctxt)
4612{
4613 return get_rvalue (path_var (expr, get_stack_depth () - 1), ctxt);
4614}
4615
4616/* Return an svalue_id for a pointer to RID of type PTR_TYPE, reusing
4617 existing pointer values if one is available. */
4618
4619svalue_id
4620region_model::get_or_create_ptr_svalue (tree ptr_type, region_id rid)
4621{
4622 /* Reuse existing region_svalue, if one of the right type is
4623 available. */
4624 /* In theory we could stash a svalue_id in "region", but differing
4625 pointer types muddles things.
4626 For now, just do a linear search through all existing svalues. */
4627 int i;
4628 svalue *svalue;
4629 FOR_EACH_VEC_ELT (m_svalues, i, svalue)
4630 if (region_svalue *ptr_svalue = svalue->dyn_cast_region_svalue ())
4631 if (ptr_svalue->get_pointee () == rid
4632 && ptr_svalue->get_type () == ptr_type)
4633 return svalue_id::from_int (i);
4634
4635 return add_svalue (new region_svalue (ptr_type, rid));
4636}
4637
4638/* Return an svalue_id for a constant_svalue for CST_EXPR,
4639 creating the constant_svalue if necessary.
4640 The constant_svalue instances are reused, based on pointer equality
4641 of trees */
4642
4643svalue_id
4644region_model::get_or_create_constant_svalue (tree cst_expr)
4645{
4646 gcc_assert (cst_expr);
4647
4648 /* Reuse one if it already exists. */
4649 // TODO: maybe store a map, rather than do linear search?
4650 int i;
4651 svalue *svalue;
4652 FOR_EACH_VEC_ELT (m_svalues, i, svalue)
4653 if (svalue->maybe_get_constant () == cst_expr)
4654 return svalue_id::from_int (i);
4655
4656 svalue_id cst_sid = add_svalue (new constant_svalue (cst_expr));
4657 return cst_sid;
4658}
4659
4660/* Return an svalue_id for a region_svalue for FNDECL,
4661 creating the function_region if necessary. */
4662
4663svalue_id
4664region_model::get_svalue_for_fndecl (tree ptr_type, tree fndecl)
4665{
4666 gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
4667 region_id function_rid = get_region_for_fndecl (fndecl);
4668 return get_or_create_ptr_svalue (ptr_type, function_rid);
4669}
4670
4671/* Return a region_id for a function_region for FNDECL,
4672 creating it if necessary. */
4673
4674region_id
4675region_model::get_region_for_fndecl (tree fndecl)
4676{
4677 gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
4678
4679 region_id code_rid = get_root_region ()->ensure_code_region (this);
4680 code_region *code = get_root_region ()->get_code_region (this);
4681
4682 return code->get_or_create (this, code_rid, fndecl, TREE_TYPE (fndecl));
4683}
4684
4685/* Return an svalue_id for a region_svalue for LABEL,
4686 creating the label_region if necessary. */
4687
4688svalue_id
4689region_model::get_svalue_for_label (tree ptr_type, tree label)
4690{
4691 gcc_assert (TREE_CODE (label) == LABEL_DECL);
4692 region_id label_rid = get_region_for_label (label);
4693 return get_or_create_ptr_svalue (ptr_type, label_rid);
4694}
4695
4696/* Return a region_id for a label_region for LABEL,
4697 creating it if necessary. */
4698
4699region_id
4700region_model::get_region_for_label (tree label)
4701{
4702 gcc_assert (TREE_CODE (label) == LABEL_DECL);
4703
4704 tree fndecl = DECL_CONTEXT (label);
4705 gcc_assert (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL);
4706
4707 region_id func_rid = get_region_for_fndecl (fndecl);
4708 function_region *func_reg = get_region <function_region> (func_rid);
4709 return func_reg->get_or_create (this, func_rid, label, TREE_TYPE (label));
4710}
4711
4712/* Build a cast of SRC_EXPR to DST_TYPE, or return NULL_TREE.
4713
4714 Adapted from gcc::jit::playback::context::build_cast, which in turn is
4715 adapted from
4716 - c/c-typeck.c:build_c_cast
4717 - c/c-convert.c: convert
4718 - convert.h
4719 Only some kinds of cast are currently supported here. */
4720
4721static tree
4722build_cast (tree dst_type, tree src_expr)
4723{
4724 tree result = targetm.convert_to_type (dst_type, src_expr);
4725 if (result)
4726 return result;
4727 enum tree_code dst_code = TREE_CODE (dst_type);
4728 switch (dst_code)
4729 {
4730 case INTEGER_TYPE:
4731 case ENUMERAL_TYPE:
4732 result = convert_to_integer (dst_type, src_expr);
4733 goto maybe_fold;
4734
4735 case BOOLEAN_TYPE:
4736 /* Compare with c_objc_common_truthvalue_conversion and
4737 c_common_truthvalue_conversion. */
4738 /* For now, convert to: (src_expr != 0) */
4739 result = build2 (NE_EXPR, dst_type,
4740 src_expr,
4741 build_int_cst (TREE_TYPE (src_expr), 0));
4742 goto maybe_fold;
4743
4744 case REAL_TYPE:
4745 result = convert_to_real (dst_type, src_expr);
4746 goto maybe_fold;
4747
4748 case POINTER_TYPE:
4749 result = build1 (NOP_EXPR, dst_type, src_expr);
4750 goto maybe_fold;
4751
4752 default:
4753 return NULL_TREE;
4754
4755 maybe_fold:
4756 if (TREE_CODE (result) != C_MAYBE_CONST_EXPR)
4757 result = fold (result);
4758 return result;
4759 }
4760}
4761
4762/* If the type of SID's underlying value is DST_TYPE, return SID.
4763 Otherwise, attempt to create (or reuse) an svalue representing an access
4764 of SID as a DST_TYPE and return that value's svalue_id. */
4765
4766svalue_id
4767region_model::maybe_cast_1 (tree dst_type, svalue_id sid)
4768{
4769 svalue *sval = get_svalue (sid);
4770 tree src_type = sval->get_type ();
4771 if (src_type == dst_type)
4772 return sid;
4773
4774 if (POINTER_TYPE_P (dst_type)
4775 && POINTER_TYPE_P (src_type))
4776 {
4777 /* Pointer to region. */
4778 if (region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
4779 return get_or_create_ptr_svalue (dst_type, ptr_sval->get_pointee ());
4780
4781 /* Unknown pointer? Get or create a new unknown pointer of the
4782 correct type, preserving the equality between the pointers. */
4783 if (sval->dyn_cast_unknown_svalue ())
4784 {
4785 equiv_class &ec = m_constraints->get_equiv_class (sid);
4786
4787 /* Look for an existing pointer of the correct type within the EC. */
4788 int i;
4789 svalue_id *equiv_sid;
4790 FOR_EACH_VEC_ELT (ec.m_vars, i, equiv_sid)
4791 {
4792 svalue *equiv_val = get_svalue (*equiv_sid);
4793 if (equiv_val->get_type () == dst_type)
4794 return *equiv_sid;
4795 }
4796
4797 /* Otherwise, create a new unknown pointer of the correct type. */
4798 svalue *unknown_sval = new unknown_svalue (dst_type);
4799 svalue_id new_ptr_sid = add_svalue (unknown_sval);
4800 m_constraints->add_constraint (sid, EQ_EXPR, new_ptr_sid);
4801 return new_ptr_sid;
4802 }
4803 }
4804
4805 /* Attempt to cast constants. */
4806 if (tree src_cst = sval->maybe_get_constant ())
4807 {
4808 tree dst = build_cast (dst_type, src_cst);
4809 gcc_assert (dst != NULL_TREE);
4810 if (CONSTANT_CLASS_P (dst))
4811 return get_or_create_constant_svalue (dst);
4812 }
4813
4814 /* Otherwise, return a new unknown value. */
4815 svalue *unknown_sval = new unknown_svalue (dst_type);
4816 return add_svalue (unknown_sval);
4817}
4818
4819/* If the type of SID's underlying value is DST_TYPE, return SID.
4820 Otherwise, attempt to create (or reuse) an svalue representing an access
4821 of SID as a DST_TYPE and return that value's svalue_id.
4822
4823 If the result != SID, then call CTXT's on_cast vfunc (if CTXT is non-NULL),
4824 so that sm-state can be propagated from SID to the result. */
4825
4826svalue_id
4827region_model::maybe_cast (tree dst_type, svalue_id sid,
4828 region_model_context *ctxt)
4829{
4830 svalue_id result = maybe_cast_1 (dst_type, sid);
4831 if (result != sid)
4832 if (ctxt)
4833 {
4834 /* Notify ctxt about a cast, so any sm-state can be copied. */
4835 ctxt->on_cast (sid, result);
4836 }
4837 return result;
4838}
4839
4840/* Ensure that the region for OBJ_RID has a child region for FIELD;
4841 return the child region's region_id. */
4842
4843region_id
4844region_model::get_field_region (region_id struct_or_union_rid, tree field)
4845{
4846 struct_or_union_region *sou_reg
4847 = get_region<struct_or_union_region> (struct_or_union_rid);
4848
4849 /* Inherit constness from parent type. */
4850 const int qual_mask = TYPE_QUAL_CONST;
4851 int sou_quals = TYPE_QUALS (sou_reg->get_type ()) & qual_mask;
4852 tree field_type = TREE_TYPE (field);
4853 tree field_type_with_quals = build_qualified_type (field_type, sou_quals);
4854
4855 // TODO: maybe convert to a vfunc?
4856 if (sou_reg->get_kind () == RK_UNION)
4857 {
4858 /* Union.
4859 Get a view of the union as a whole, with the type of the field. */
4860 region_id view_rid
4861 = get_or_create_view (struct_or_union_rid, field_type_with_quals);
4862 return view_rid;
4863 }
4864 else
4865 {
4866 /* Struct. */
4867 region_id child_rid
4868 = sou_reg->get_or_create (this, struct_or_union_rid, field,
4869 field_type_with_quals);
4870 return child_rid;
4871 }
4872}
4873
4874/* Get a region_id for referencing PTR_SID, creating a region if need be, and
4875 potentially generating warnings via CTXT. */
4876
4877region_id
4878region_model::deref_rvalue (svalue_id ptr_sid, region_model_context *ctxt)
4879{
4880 gcc_assert (!ptr_sid.null_p ());
4881 svalue *ptr_svalue = get_svalue (ptr_sid);
4882 gcc_assert (ptr_svalue);
4883
4884 switch (ptr_svalue->get_kind ())
4885 {
4886 case SK_REGION:
4887 {
4888 region_svalue *region_sval = as_a <region_svalue *> (ptr_svalue);
4889 return region_sval->get_pointee ();
4890 }
4891
4892 case SK_CONSTANT:
4893 goto create_symbolic_region;
4894
4895 case SK_POISONED:
4896 {
4897 if (ctxt)
4898 if (tree ptr = get_representative_tree (ptr_sid))
4899 {
4900 poisoned_svalue *poisoned_sval
4901 = as_a <poisoned_svalue *> (ptr_svalue);
4902 enum poison_kind pkind = poisoned_sval->get_poison_kind ();
4903 ctxt->warn (new poisoned_value_diagnostic (ptr, pkind));
4904 }
4905 goto create_symbolic_region;
4906 }
4907
4908 case SK_UNKNOWN:
4909 {
4910 create_symbolic_region:
4911 /* We need a symbolic_region to represent this unknown region.
4912 We don't know if it on the heap, stack, or a global,
4913 so use the root region as parent. */
4914 region_id new_rid
4915 = add_region (new symbolic_region (m_root_rid, false));
4916
4917 /* We need to write the region back into the pointer,
4918 or we'll get a new, different region each time.
4919 We do this by changing the meaning of ptr_sid, replacing
4920 the unknown value with the ptr to the new region.
4921 We replace the meaning of the ID rather than simply writing
4922 to PTR's lvalue since there could be several places sharing
4923 the same unknown ptr value. */
4924 svalue *ptr_val
4925 = new region_svalue (ptr_svalue->get_type (), new_rid);
4926 replace_svalue (ptr_sid, ptr_val);
4927
4928 return new_rid;
4929 }
4930
4931 case SK_SETJMP:
4932 goto create_symbolic_region;
4933 }
4934
4935 gcc_unreachable ();
4936}
4937
4938/* Get a region_id for referencing PTR, creating a region if need be, and
4939 potentially generating warnings via CTXT. */
4940
4941region_id
4942region_model::deref_rvalue (tree ptr, region_model_context *ctxt)
4943{
4944 svalue_id ptr_sid = get_rvalue (ptr, ctxt);
4945 return deref_rvalue (ptr_sid, ctxt);
4946}
4947
4948/* Set the value of the region given by LHS_RID to the value given
4949 by RHS_SID. */
4950
4951void
4952region_model::set_value (region_id lhs_rid, svalue_id rhs_sid,
4953 region_model_context *ctxt)
4954{
4955 gcc_assert (!lhs_rid.null_p ());
4956 gcc_assert (!rhs_sid.null_p ());
4957 get_region (lhs_rid)->set_value (*this, lhs_rid, rhs_sid, ctxt);
4958}
4959
4960/* Determine what is known about the condition "LHS_SID OP RHS_SID" within
4961 this model. */
4962
4963tristate
4964region_model::eval_condition (svalue_id lhs_sid,
4965 enum tree_code op,
4966 svalue_id rhs_sid) const
4967{
4968 tristate ts = eval_condition_without_cm (lhs_sid, op, rhs_sid);
4969
4970 if (ts.is_known ())
4971 return ts;
4972
4973 /* Otherwise, try constraints. */
4974 return m_constraints->eval_condition (lhs_sid, op, rhs_sid);
4975}
4976
4977/* Determine what is known about the condition "LHS_SID OP RHS_SID" within
4978 this model, without resorting to the constraint_manager.
4979
4980 This is exposed so that impl_region_model_context::on_state_leak can
4981 check for equality part-way through region_model::purge_unused_svalues
4982 without risking creating new ECs. */
4983
4984tristate
4985region_model::eval_condition_without_cm (svalue_id lhs_sid,
4986 enum tree_code op,
4987 svalue_id rhs_sid) const
4988{
4989 svalue *lhs = get_svalue (lhs_sid);
4990 svalue *rhs = get_svalue (rhs_sid);
4991 gcc_assert (lhs);
4992 gcc_assert (rhs);
4993
4994 /* See what we know based on the values. */
4995 if (lhs && rhs)
4996 {
4997 if (lhs == rhs)
4998 {
4999 /* If we have the same svalue, then we have equality.
5000 TODO: should this definitely be the case for poisoned values? */
5001 switch (op)
5002 {
5003 default:
5004 gcc_unreachable ();
5005
5006 case EQ_EXPR:
5007 case GE_EXPR:
5008 case LE_EXPR:
5009 return tristate::TS_TRUE;
5010
5011 case NE_EXPR:
5012 case GT_EXPR:
5013 case LT_EXPR:
5014 return tristate::TS_FALSE;
5015 }
5016 }
5017
5018 /* If we have a pair of region_svalues, compare them. */
5019 if (region_svalue *lhs_ptr = lhs->dyn_cast_region_svalue ())
5020 if (region_svalue *rhs_ptr = rhs->dyn_cast_region_svalue ())
5021 {
5022 tristate res = region_svalue::eval_condition (lhs_ptr, op, rhs_ptr);
5023 if (res.is_known ())
5024 return res;
5025 /* Otherwise, only known through constraints. */
5026 }
5027
5028 /* If we have a pair of constants, compare them. */
5029 if (constant_svalue *cst_lhs = lhs->dyn_cast_constant_svalue ())
5030 if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
5031 return constant_svalue::eval_condition (cst_lhs, op, cst_rhs);
5032
5033 /* Handle comparison of a region_svalue against zero. */
5034 if (region_svalue *ptr = lhs->dyn_cast_region_svalue ())
5035 if (constant_svalue *cst_rhs = rhs->dyn_cast_constant_svalue ())
5036 if (zerop (cst_rhs->get_constant ()))
5037 {
5038 /* A region_svalue is a non-NULL pointer, except in certain
5039 special cases (see the comment for region::non_null_p. */
5040 region *pointee = get_region (ptr->get_pointee ());
5041 if (pointee->non_null_p (*this))
5042 {
5043 switch (op)
5044 {
5045 default:
5046 gcc_unreachable ();
5047
5048 case EQ_EXPR:
5049 case GE_EXPR:
5050 case LE_EXPR:
5051 return tristate::TS_FALSE;
5052
5053 case NE_EXPR:
5054 case GT_EXPR:
5055 case LT_EXPR:
5056 return tristate::TS_TRUE;
5057 }
5058 }
5059 }
5060 }
5061
5062 return tristate::TS_UNKNOWN;
5063}
5064
5065/* Attempt to add the constraint "LHS OP RHS" to this region_model.
5066 If it is consistent with existing constraints, add it, and return true.
5067 Return false if it contradicts existing constraints.
5068 Use CTXT for reporting any diagnostics associated with the accesses. */
5069
5070bool
5071region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
5072 region_model_context *ctxt)
5073{
5074 svalue_id lhs_sid = get_rvalue (lhs, ctxt);
5075 svalue_id rhs_sid = get_rvalue (rhs, ctxt);
5076
5077 tristate t_cond = eval_condition (lhs_sid, op, rhs_sid);
5078
5079 /* If we already have the condition, do nothing. */
5080 if (t_cond.is_true ())
5081 return true;
5082
5083 /* Reject a constraint that would contradict existing knowledge, as
5084 unsatisfiable. */
5085 if (t_cond.is_false ())
5086 return false;
5087
5088 /* Store the constraint. */
5089 m_constraints->add_constraint (lhs_sid, op, rhs_sid);
5090
5091 add_any_constraints_from_ssa_def_stmt (lhs, op, rhs, ctxt);
5092
5093 /* Notify the context, if any. This exists so that the state machines
5094 in a program_state can be notified about the condition, and so can
5095 set sm-state for e.g. unchecked->checked, both for cfg-edges, and
5096 when synthesizing constraints as above. */
5097 if (ctxt)
5098 ctxt->on_condition (lhs, op, rhs);
5099
5100 return true;
5101}
5102
5103/* Subroutine of region_model::add_constraint for handling optimized
5104 && and || conditionals.
5105
5106 If we have an SSA_NAME for a boolean compared against 0,
5107 look at anything implied by the def stmt and call add_constraint
5108 for it (which could recurse).
5109
5110 For example, if we have
5111 _1 = p_6 == 0B;
5112 _2 = p_8 == 0B
5113 _3 = _1 | _2
5114 and add the constraint
5115 (_3 == 0),
5116 then the def stmt for _3 implies that _1 and _2 are both false,
5117 and hence we can add the constraints:
5118 p_6 != 0B
5119 p_8 != 0B. */
5120
5121void
5122region_model::add_any_constraints_from_ssa_def_stmt (tree lhs,
5123 enum tree_code op,
5124 tree rhs,
5125 region_model_context *ctxt)
5126{
5127 if (TREE_CODE (lhs) != SSA_NAME)
5128 return;
5129
5130 if (rhs != boolean_false_node)
5131 return;
5132
5133 if (op != NE_EXPR && op != EQ_EXPR)
5134 return;
5135
5136 /* We have either
5137 - "LHS != false" (i.e. LHS is true), or
5138 - "LHS == false" (i.e. LHS is false). */
5139 bool is_true = op == NE_EXPR;
5140
5141 gimple *def_stmt = SSA_NAME_DEF_STMT (lhs);
5142 gassign *assign = dyn_cast<gassign *> (def_stmt);
5143 if (!assign)
5144 return;
5145
5146 enum tree_code rhs_code = gimple_assign_rhs_code (assign);
5147
5148 switch (rhs_code)
5149 {
5150 default:
5151 break;
5152 case BIT_AND_EXPR:
5153 {
5154 if (is_true)
5155 {
5156 /* ...and "LHS == (rhs1 & rhs2) i.e. "(rhs1 & rhs2)" is true
5157 then both rhs1 and rhs2 must be true. */
5158 tree rhs1 = gimple_assign_rhs1 (assign);
5159 tree rhs2 = gimple_assign_rhs2 (assign);
5160 add_constraint (rhs1, NE_EXPR, boolean_false_node, ctxt);
5161 add_constraint (rhs2, NE_EXPR, boolean_false_node, ctxt);
5162 }
5163 }
5164 break;
5165
5166 case BIT_IOR_EXPR:
5167 {
5168 if (!is_true)
5169 {
5170 /* ...and "LHS == (rhs1 | rhs2)
5171 i.e. "(rhs1 | rhs2)" is false
5172 then both rhs1 and rhs2 must be false. */
5173 tree rhs1 = gimple_assign_rhs1 (assign);
5174 tree rhs2 = gimple_assign_rhs2 (assign);
5175 add_constraint (rhs1, EQ_EXPR, boolean_false_node, ctxt);
5176 add_constraint (rhs2, EQ_EXPR, boolean_false_node, ctxt);
5177 }
5178 }
5179 break;
5180
5181 case EQ_EXPR:
5182 case NE_EXPR:
5183 {
5184 /* ...and "LHS == (rhs1 OP rhs2)"
5185 then rhs1 OP rhs2 must have the same logical value as LHS. */
5186 tree rhs1 = gimple_assign_rhs1 (assign);
5187 tree rhs2 = gimple_assign_rhs2 (assign);
5188 if (!is_true)
5189 rhs_code
5190 = invert_tree_comparison (rhs_code, false /* honor_nans */);
5191 add_constraint (rhs1, rhs_code, rhs2, ctxt);
5192 }
5193 break;
5194 }
5195}
5196
5197/* Determine what is known about the condition "LHS OP RHS" within
5198 this model.
5199 Use CTXT for reporting any diagnostics associated with the accesses. */
5200
5201tristate
5202region_model::eval_condition (tree lhs,
5203 enum tree_code op,
5204 tree rhs,
5205 region_model_context *ctxt)
5206{
5207 return eval_condition (get_rvalue (lhs, ctxt), op, get_rvalue (rhs, ctxt));
5208}
5209
5210/* If SID is a constant value, return the underlying tree constant.
5211 Otherwise, return NULL_TREE. */
5212
5213tree
5214region_model::maybe_get_constant (svalue_id sid) const
5215{
5216 gcc_assert (!sid.null_p ());
5217 svalue *sval = get_svalue (sid);
5218 return sval->maybe_get_constant ();
5219}
5220
5221/* Create a new child region of the heap (creating the heap region if
5222 necessary).
5223 Return the region_id of the new child region. */
5224
5225region_id
5226region_model::add_new_malloc_region ()
5227{
5228 region_id heap_rid
5229 = get_root_region ()->ensure_heap_region (this);
5230 return add_region (new symbolic_region (heap_rid, true));
5231}
5232
5233/* Attempt to return a tree that represents SID, or return NULL_TREE.
5234 Find the first region that stores the value (e.g. a local) and
5235 generate a representative tree for it. */
5236
5237tree
5238region_model::get_representative_tree (svalue_id sid) const
5239{
5240 if (sid.null_p ())
5241 return NULL_TREE;
5242
5243 unsigned i;
5244 region *region;
5245 FOR_EACH_VEC_ELT (m_regions, i, region)
5246 if (sid == region->get_value_direct ())
5247 {
5248 path_var pv = get_representative_path_var (region_id::from_int (i));
5249 if (pv.m_tree)
5250 return pv.m_tree;
5251 }
5252
5253 return maybe_get_constant (sid);
5254}
5255
5256/* Attempt to return a path_var that represents the region, or return
5257 the NULL path_var.
5258 For example, a region for a field of a local would be a path_var
5259 wrapping a COMPONENT_REF. */
5260
5261path_var
5262region_model::get_representative_path_var (region_id rid) const
5263{
5264 region *reg = get_region (rid);
5265 region *parent_region = get_region (reg->get_parent ());
5266 region_id stack_rid = get_stack_region_id ();
5267 if (!stack_rid.null_p ())
5268 if (parent_region->get_parent () == stack_rid)
5269 {
5270 frame_region *parent_frame = (frame_region *)parent_region;
5271 tree t = parent_frame->get_tree_for_child_region (rid);
5272 return path_var (t, parent_frame->get_depth ());
5273 }
5274 if (reg->get_parent () == get_globals_region_id ())
5275 {
5276 map_region *globals = get_root_region ()->get_globals_region (this);
5277 if (globals)
5278 return path_var (globals->get_tree_for_child_region (rid), -1);
5279 }
5280
5281 /* Handle e.g. fields of a local by recursing. */
5282 region_id parent_rid = reg->get_parent ();
5283 region *parent_reg = get_region (parent_rid);
5284 if (parent_reg)
5285 {
5286 if (parent_reg->get_kind () == RK_STRUCT)
5287 {
5288 map_region *parent_map_region = (map_region *)parent_reg;
5289 /* This can fail if we have a view, rather than a field. */
5290 if (tree child_key
5291 = parent_map_region->get_tree_for_child_region (rid))
5292 {
5293 path_var parent_pv = get_representative_path_var (parent_rid);
5294 if (parent_pv.m_tree && TREE_CODE (child_key) == FIELD_DECL)
5295 return path_var (build3 (COMPONENT_REF,
5296 TREE_TYPE (child_key),
5297 parent_pv.m_tree, child_key,
5298 NULL_TREE),
5299 parent_pv.m_stack_depth);
5300 }
5301 }
5302 }
5303
5304 return path_var (NULL_TREE, 0);
5305}
5306
5307/* Locate all regions that directly have value SID and append representative
5308 path_var instances for them into *OUT. */
5309
5310void
5311region_model::get_path_vars_for_svalue (svalue_id sid, vec<path_var> *out) const
5312{
5313 unsigned i;
5314 region *region;
5315 FOR_EACH_VEC_ELT (m_regions, i, region)
5316 if (sid == region->get_value_direct ())
5317 {
5318 path_var pv = get_representative_path_var (region_id::from_int (i));
5319 if (pv.m_tree)
5320 out->safe_push (pv);
5321 }
5322}
5323
5324/* Set DST_RID value to be a new unknown value of type TYPE. */
5325
5326svalue_id
5327region_model::set_to_new_unknown_value (region_id dst_rid, tree type,
5328 region_model_context *ctxt)
5329{
5330 gcc_assert (!dst_rid.null_p ());
5331 svalue_id new_sid = add_svalue (new unknown_svalue (type));
5332 set_value (dst_rid, new_sid, ctxt);
5333
5334 // TODO: presumably purge all child regions too (but do this in set_value?)
5335
5336 return new_sid;
5337}
5338
5339/* Update this model for any phis in SNODE, assuming we came from
5340 LAST_CFG_SUPEREDGE. */
5341
5342void
5343region_model::update_for_phis (const supernode *snode,
5344 const cfg_superedge *last_cfg_superedge,
5345 region_model_context *ctxt)
5346{
5347 gcc_assert (last_cfg_superedge);
5348
5349 for (gphi_iterator gpi = const_cast<supernode *>(snode)->start_phis ();
5350 !gsi_end_p (gpi); gsi_next (&gpi))
5351 {
5352 gphi *phi = gpi.phi ();
5353
5354 tree src = last_cfg_superedge->get_phi_arg (phi);
5355 tree lhs = gimple_phi_result (phi);
5356
5357 /* Update next_state based on phi. */
5358 bool is_back_edge = last_cfg_superedge->back_edge_p ();
5359 handle_phi (lhs, src, is_back_edge, ctxt);
5360 }
5361}
5362
5363/* Attempt to update this model for taking EDGE (where the last statement
5364 was LAST_STMT), returning true if the edge can be taken, false
5365 otherwise.
5366
5367 For CFG superedges where LAST_STMT is a conditional or a switch
5368 statement, attempt to add the relevant conditions for EDGE to this
5369 model, returning true if they are feasible, or false if they are
5370 impossible.
5371
5372 For call superedges, push frame information and store arguments
5373 into parameters.
5374
5375 For return superedges, pop frame information and store return
5376 values into any lhs.
5377
5378 Rejection of call/return superedges happens elsewhere, in
5379 program_point::on_edge (i.e. based on program point, rather
5380 than program state). */
5381
5382bool
5383region_model::maybe_update_for_edge (const superedge &edge,
5384 const gimple *last_stmt,
5385 region_model_context *ctxt)
5386{
5387 /* Handle frame updates for interprocedural edges. */
5388 switch (edge.m_kind)
5389 {
5390 default:
5391 break;
5392
5393 case SUPEREDGE_CALL:
5394 {
5395 const call_superedge *call_edge = as_a <const call_superedge *> (&edge);
5396 update_for_call_superedge (*call_edge, ctxt);
5397 }
5398 break;
5399
5400 case SUPEREDGE_RETURN:
5401 {
5402 const return_superedge *return_edge
5403 = as_a <const return_superedge *> (&edge);
5404 update_for_return_superedge (*return_edge, ctxt);
5405 }
5406 break;
5407
5408 case SUPEREDGE_INTRAPROCEDURAL_CALL:
5409 {
5410 const callgraph_superedge *cg_sedge
5411 = as_a <const callgraph_superedge *> (&edge);
5412 update_for_call_summary (*cg_sedge, ctxt);
5413 }
5414 break;
5415 }
5416
5417 if (last_stmt == NULL)
5418 return true;
5419
5420 /* Apply any constraints for conditionals/switch statements. */
5421
5422 if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
5423 {
5424 const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (&edge);
5425 return apply_constraints_for_gcond (*cfg_sedge, cond_stmt, ctxt);
5426 }
5427
5428 if (const gswitch *switch_stmt = dyn_cast <const gswitch *> (last_stmt))
5429 {
5430 const switch_cfg_superedge *switch_sedge
5431 = as_a <const switch_cfg_superedge *> (&edge);
5432 return apply_constraints_for_gswitch (*switch_sedge, switch_stmt, ctxt);
5433 }
5434
5435 return true;
5436}
5437
5438/* Push a new frame_region on to the stack region.
5439 Populate the frame_region with child regions for the function call's
5440 parameters, using values from the arguments at the callsite in the
5441 caller's frame. */
5442
5443void
5444region_model::update_for_call_superedge (const call_superedge &call_edge,
5445 region_model_context *ctxt)
5446{
5447 /* Build a vec of argument svalue_id, using the current top
5448 frame for resolving tree expressions. */
5449 const gcall *call_stmt = call_edge.get_call_stmt ();
5450 auto_vec<svalue_id> arg_sids (gimple_call_num_args (call_stmt));
5451
5452 for (unsigned i = 0; i < gimple_call_num_args (call_stmt); i++)
5453 {
5454 tree arg = gimple_call_arg (call_stmt, i);
5455 arg_sids.quick_push (get_rvalue (arg, ctxt));
5456 }
5457
5458 push_frame (call_edge.get_callee_function (), &arg_sids, ctxt);
5459}
5460
5461/* Pop the top-most frame_region from the stack, and store the svalue
5462 for any returned value into the region for the lvalue of the LHS of
5463 the call (if any). */
5464
5465void
5466region_model::update_for_return_superedge (const return_superedge &return_edge,
5467 region_model_context *ctxt)
5468{
5469 purge_stats stats;
5470 svalue_id result_sid = pop_frame (true, &stats, ctxt);
5471 // TODO: do something with the stats?
5472
5473 /* Set the result of the call, within the caller frame. */
5474 const gcall *call_stmt = return_edge.get_call_stmt ();
5475 tree lhs = gimple_call_lhs (call_stmt);
5476 if (lhs)
5477 set_value (get_lvalue (lhs, ctxt), result_sid, ctxt);
5478 else if (!result_sid.null_p ())
5479 {
5480 /* This could be a leak; try purging again, but this time,
5481 don't special-case the result_sid. */
5482 purge_stats stats;
5483 purge_unused_svalues (&stats, ctxt);
5484 }
5485}
5486
5487/* Update this region_model with a summary of the effect of calling
5488 and returning from CG_SEDGE.
5489
5490 TODO: Currently this is extremely simplistic: we merely set the
5491 return value to "unknown". A proper implementation would e.g. update
5492 sm-state, and presumably be reworked to support multiple outcomes. */
5493
5494void
5495region_model::update_for_call_summary (const callgraph_superedge &cg_sedge,
5496 region_model_context *ctxt)
5497{
5498 /* For now, set any return value to "unknown". */
5499 const gcall *call_stmt = cg_sedge.get_call_stmt ();
5500 tree lhs = gimple_call_lhs (call_stmt);
5501 if (lhs)
5502 set_to_new_unknown_value (get_lvalue (lhs, ctxt), TREE_TYPE (lhs), ctxt);
5503
5504 // TODO: actually implement some kind of summary here
5505}
5506
5507/* Given a true or false edge guarded by conditional statement COND_STMT,
5508 determine appropriate constraints for the edge to be taken.
5509
5510 If they are feasible, add the constraints and return true.
5511
5512 Return false if the constraints contradict existing knowledge
5513 (and so the edge should not be taken). */
5514
5515bool
5516region_model::apply_constraints_for_gcond (const cfg_superedge &sedge,
5517 const gcond *cond_stmt,
5518 region_model_context *ctxt)
5519{
5520 ::edge cfg_edge = sedge.get_cfg_edge ();
5521 gcc_assert (cfg_edge != NULL);
5522 gcc_assert (cfg_edge->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE));
5523
5524 enum tree_code op = gimple_cond_code (cond_stmt);
5525 tree lhs = gimple_cond_lhs (cond_stmt);
5526 tree rhs = gimple_cond_rhs (cond_stmt);
5527 if (cfg_edge->flags & EDGE_FALSE_VALUE)
5528 op = invert_tree_comparison (op, false /* honor_nans */);
5529 return add_constraint (lhs, op, rhs, ctxt);
5530}
5531
5532/* Given an EDGE guarded by SWITCH_STMT, determine appropriate constraints
5533 for the edge to be taken.
5534
5535 If they are feasible, add the constraints and return true.
5536
5537 Return false if the constraints contradict existing knowledge
5538 (and so the edge should not be taken). */
5539
5540bool
5541region_model::apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
5542 const gswitch *switch_stmt,
5543 region_model_context *ctxt)
5544{
5545 tree index = gimple_switch_index (switch_stmt);
5546 tree case_label = edge.get_case_label ();
5547 gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
5548 tree lower_bound = CASE_LOW (case_label);
5549 tree upper_bound = CASE_HIGH (case_label);
5550 if (lower_bound)
5551 {
5552 if (upper_bound)
5553 {
5554 /* Range. */
5555 if (!add_constraint (index, GE_EXPR, lower_bound, ctxt))
5556 return false;
5557 return add_constraint (index, LE_EXPR, upper_bound, ctxt);
5558 }
5559 else
5560 /* Single-value. */
5561 return add_constraint (index, EQ_EXPR, lower_bound, ctxt);
5562 }
5563 else
5564 {
5565 /* The default case.
5566 Add exclusions based on the other cases. */
5567 for (unsigned other_idx = 1;
5568 other_idx < gimple_switch_num_labels (switch_stmt);
5569 other_idx++)
5570 {
5571 tree other_label = gimple_switch_label (switch_stmt,
5572 other_idx);
5573 tree other_lower_bound = CASE_LOW (other_label);
5574 tree other_upper_bound = CASE_HIGH (other_label);
5575 gcc_assert (other_lower_bound);
5576 if (other_upper_bound)
5577 {
5578 /* Exclude this range-valued case.
5579 For now, we just exclude the boundary values.
5580 TODO: exclude the values within the region. */
5581 if (!add_constraint (index, NE_EXPR, other_lower_bound, ctxt))
5582 return false;
5583 if (!add_constraint (index, NE_EXPR, other_upper_bound, ctxt))
5584 return false;
5585 }
5586 else
5587 /* Exclude this single-valued case. */
5588 if (!add_constraint (index, NE_EXPR, other_lower_bound, ctxt))
5589 return false;
5590 }
5591 return true;
5592 }
5593}
5594
5595/* Get the root_region within this model (guaranteed to be non-null). */
5596
5597root_region *
5598region_model::get_root_region () const
5599{
5600 return get_region<root_region> (m_root_rid);
5601}
5602
5603/* Get the region_id of this model's stack region (if any). */
5604
5605region_id
5606region_model::get_stack_region_id () const
5607{
5608 return get_root_region ()->get_stack_region_id ();
5609}
5610
5611/* Create a new frame_region for a call to FUN and push it onto
5612 the stack.
5613
5614 If ARG_SIDS is non-NULL, use it to populate the parameters
5615 in the new frame.
5616 Otherwise, populate them with unknown values.
5617
5618 Return the region_id of the new frame_region. */
5619
5620region_id
5621region_model::push_frame (function *fun, vec<svalue_id> *arg_sids,
5622 region_model_context *ctxt)
5623{
5624 return get_root_region ()->push_frame (this, fun, arg_sids, ctxt);
5625}
5626
5627/* Get the region_id of the top-most frame in this region_model's stack,
5628 if any. */
5629
5630region_id
5631region_model::get_current_frame_id () const
5632{
5633 return get_root_region ()->get_current_frame_id (*this);
5634}
5635
5636/* Get the function of the top-most frame in this region_model's stack.
5637 There must be such a frame. */
5638
5639function *
5640region_model::get_current_function () const
5641{
5642 region_id frame_id = get_current_frame_id ();
5643 frame_region *frame = get_region<frame_region> (frame_id);
5644 return frame->get_function ();
5645}
5646
5647/* Pop the topmost frame_region from this region_model's stack;
5648 see the comment for stack_region::pop_frame. */
5649
5650svalue_id
5651region_model::pop_frame (bool purge, purge_stats *out,
5652 region_model_context *ctxt)
5653{
5654 return get_root_region ()->pop_frame (this, purge, out, ctxt);
5655}
5656
5657/* Get the number of frames in this region_model's stack. */
5658
5659int
5660region_model::get_stack_depth () const
5661{
5662 stack_region *stack = get_root_region ()->get_stack_region (this);
5663 if (stack)
5664 return stack->get_num_frames ();
5665 else
5666 return 0;
5667}
5668
5669/* Get the function * at DEPTH within the call stack. */
5670
5671function *
5672region_model::get_function_at_depth (unsigned depth) const
5673{
5674 stack_region *stack = get_root_region ()->get_stack_region (this);
5675 gcc_assert (stack);
5676 region_id frame_rid = stack->get_frame_rid (depth);
5677 frame_region *frame = get_region <frame_region> (frame_rid);
5678 return frame->get_function ();
5679}
5680
5681/* Get the region_id of this model's globals region (if any). */
5682
5683region_id
5684region_model::get_globals_region_id () const
5685{
5686 return get_root_region ()->get_globals_region_id ();
5687}
5688
5689/* Add SVAL to this model, taking ownership, and returning its new
5690 svalue_id. */
5691
5692svalue_id
5693region_model::add_svalue (svalue *sval)
5694{
5695 gcc_assert (sval);
5696 m_svalues.safe_push (sval);
5697 return svalue_id::from_int (m_svalues.length () - 1);
5698}
5699
5700/* Change the meaning of SID to be NEW_SVAL
5701 (e.g. when deferencing an unknown pointer, the pointer
5702 becomes a pointer to a symbolic region, so that all users
5703 of the former unknown pointer are now effectively pointing
5704 at the same region). */
5705
5706void
5707region_model::replace_svalue (svalue_id sid, svalue *new_sval)
5708{
5709 gcc_assert (!sid.null_p ());
5710 int idx = sid.as_int ();
5711
5712 gcc_assert (m_svalues[idx]);
5713 gcc_assert (m_svalues[idx]->get_type () == new_sval->get_type ());
5714 delete m_svalues[idx];
5715
5716 m_svalues[idx] = new_sval;
5717}
5718
5719/* Add region R to this model, taking ownership, and returning its new
5720 region_id. */
5721
5722region_id
5723region_model::add_region (region *r)
5724{
5725 gcc_assert (r);
5726 m_regions.safe_push (r);
5727 return region_id::from_int (m_regions.length () - 1);
5728}
5729
5730/* Return the svalue with id SVAL_ID, or NULL for a null id. */
5731
5732svalue *
5733region_model::get_svalue (svalue_id sval_id) const
5734{
5735 if (sval_id.null_p ())
5736 return NULL;
5737 return m_svalues[sval_id.as_int ()];
5738}
5739
5740/* Return the region with id RID, or NULL for a null id. */
5741
5742region *
5743region_model::get_region (region_id rid) const
5744{
5745 if (rid.null_p ())
5746 return NULL;
5747 return m_regions[rid.as_int ()];
5748}
5749
5750/* Make a region of an appropriate subclass for TYPE,
5751 with parent PARENT_RID. */
5752
5753static region *
5754make_region_for_type (region_id parent_rid, tree type)
5755{
5756 gcc_assert (TYPE_P (type));
5757
5758 if (INTEGRAL_TYPE_P (type)
5759 || SCALAR_FLOAT_TYPE_P (type)
5760 || POINTER_TYPE_P (type)
5761 || TREE_CODE (type) == COMPLEX_TYPE)
5762 return new primitive_region (parent_rid, type);
5763
5764 if (TREE_CODE (type) == RECORD_TYPE)
5765 return new struct_region (parent_rid, type);
5766
5767 if (TREE_CODE (type) == ARRAY_TYPE)
5768 return new array_region (parent_rid, type);
5769
5770 if (TREE_CODE (type) == UNION_TYPE)
5771 return new union_region (parent_rid, type);
5772
5773 if (TREE_CODE (type) == FUNCTION_TYPE)
5774 return new function_region (parent_rid, type);
5775
5776 /* If we have a void *, make a new symbolic region. */
5777 if (type == void_type_node)
5778 return new symbolic_region (parent_rid, false);
5779
5780 gcc_unreachable ();
5781}
5782
5783/* Add a region with type TYPE and parent PARENT_RID. */
5784
5785region_id
5786region_model::add_region_for_type (region_id parent_rid, tree type)
5787{
5788 gcc_assert (TYPE_P (type));
5789
5790 region *new_region = make_region_for_type (parent_rid, type);
5791 return add_region (new_region);
5792}
5793
5794/* Helper class for region_model::purge_unused_svalues. */
5795
5796class restrict_to_used_svalues : public purge_criteria
5797{
5798public:
5799 restrict_to_used_svalues (const auto_sbitmap &used) : m_used (used) {}
5800
5801 bool should_purge_p (svalue_id sid) const FINAL OVERRIDE
5802 {
5803 gcc_assert (!sid.null_p ());
5804 return !bitmap_bit_p (m_used, sid.as_int ());
5805 }
5806
5807private:
5808 const auto_sbitmap &m_used;
5809};
5810
5811/* Remove unused svalues from this model, accumulating stats into STATS.
5812 Unused svalues are deleted. Doing so could reorder the svalues, and
5813 thus change the meaning of svalue_ids.
5814
5815 If CTXT is non-NULL, then it is notified about svalue_id remappings,
5816 and about svalue_ids that are about to be deleted. This allows e.g.
5817 for warning about resource leaks, for the case where the svalue
5818 represents a resource handle in the user code (e.g. a FILE * or a malloc
5819 buffer).
5820
5821 Amongst other things, removing unused svalues is important for ensuring
5822 that the analysis of loops terminates. Otherwise, we could generate a
5823 succession of models with unreferenced "unknown" values, where the
5824 number of redundant unknown values could grow without bounds, and each
5825 such model would be treated as distinct.
5826
5827 If KNOWN_USED is non-NULL, treat *KNOWN_USED as used (this is for
5828 handling values being returned from functions as their frame is popped,
5829 since otherwise we'd have to simultaneously determine both the rvalue
5830 of the return expr in the callee frame and the lvalue for the gcall's
5831 assignment in the caller frame, and it seems cleaner to express all
5832 lvalue and rvalue lookups implicitly relative to a "current" frame). */
5833
5834void
5835region_model::purge_unused_svalues (purge_stats *stats,
5836 region_model_context *ctxt,
5837 svalue_id *known_used_sid)
5838{
5839 // TODO: might want to avoid a vfunc call just to do logging here:
5840 logger *logger = ctxt ? ctxt->get_logger () : NULL;
5841
5842 LOG_SCOPE (logger);
5843
5844 auto_sbitmap used (m_svalues.length ());
5845 bitmap_clear (used);
5846
5847 if (known_used_sid)
5848 if (!known_used_sid->null_p ())
5849 bitmap_set_bit (used, known_used_sid->as_int ());
5850
5851 /* Walk the regions, marking sids that are used. */
5852 unsigned i;
5853 region *r;
5854 FOR_EACH_VEC_ELT (m_regions, i, r)
5855 {
5856 svalue_id sid = r->get_value_direct ();
5857 if (!sid.null_p ())
5858 bitmap_set_bit (used, sid.as_int ());
5859 }
5860
5861 /* Now purge any constraints involving svalues we don't care about. */
5862 restrict_to_used_svalues criterion (used);
5863 m_constraints->purge (criterion, stats);
5864
5865 /* Mark any sids that are in constraints that survived. */
5866 {
5867 equiv_class *ec;
5868 FOR_EACH_VEC_ELT (m_constraints->m_equiv_classes, i, ec)
5869 {
5870 int j;
5871 svalue_id *sid;
5872 FOR_EACH_VEC_ELT (ec->m_vars, j, sid)
5873 {
5874 gcc_assert (!sid->null_p ());
5875 bitmap_set_bit (used, sid->as_int ());
5876 }
5877 }
5878 }
5879
5880 /* Build a mapping from old-sid to new-sid so that we can preserve
5881 order of the used IDs and move all redundant ones to the end.
5882 Iterate though svalue IDs, adding used ones to the front of
5883 the new list, and unused ones to the back. */
5884 svalue_id_map map (m_svalues.length ());
5885 int next_used_new_sid = 0;
5886 int after_next_unused_new_sid = m_svalues.length ();
5887 for (unsigned i = 0; i < m_svalues.length (); i++)
5888 {
5889 svalue_id src (svalue_id::from_int (i));
5890 if (bitmap_bit_p (used, i))
5891 {
5892 if (logger)
5893 logger->log ("sv%i is used", i);
5894 map.put (src, svalue_id::from_int (next_used_new_sid++));
5895 }
5896 else
5897 {
5898 if (logger)
5899 logger->log ("sv%i is unused", i);
5900 map.put (src, svalue_id::from_int (--after_next_unused_new_sid));
5901 }
5902 }
5903 /* The two insertion points should have met. */
5904 gcc_assert (next_used_new_sid == after_next_unused_new_sid);
5905
5906 /* Now walk the regions and the constraints, remapping sids,
5907 so that all the redundant svalues are at the end. */
5908 remap_svalue_ids (map);
5909
5910 if (logger)
5911 {
5912 logger->start_log_line ();
5913 logger->log_partial ("map: ");
5914 map.dump_to_pp (logger->get_printer ());
5915 logger->end_log_line ();
5916 }
5917
5918 /* Notify any client about the remapping and pending deletion.
5919 Potentially this could trigger leak warnings. */
5920 if (ctxt)
5921 {
5922 ctxt->remap_svalue_ids (map);
5923 int num_client_items_purged
5924 = ctxt->on_svalue_purge (svalue_id::from_int (next_used_new_sid), map);
5925 if (stats)
5926 stats->m_num_client_items += num_client_items_purged;
5927 }
5928
5929 /* Drop the redundant svalues from the end of the vector. */
5930 while ((signed)m_svalues.length () > next_used_new_sid)
5931 {
5932 if (logger)
5933 {
5934 svalue_id victim = svalue_id::from_int (m_svalues.length () - 1);
5935 logger->log ("deleting sv%i (was sv%i)",
5936 victim.as_int (),
5937 map.get_src_for_dst (victim).as_int ());
5938 }
5939 delete m_svalues.pop ();
5940 if (stats)
5941 stats->m_num_svalues++;
5942 }
5943
5944 if (known_used_sid)
5945 map.update (known_used_sid);
5946
5947 validate ();
5948}
5949
5950/* Renumber the svalues within this model according to MAP. */
5951
5952void
5953region_model::remap_svalue_ids (const svalue_id_map &map)
5954{
5955 /* Update IDs within regions. */
5956 unsigned i;
5957 region *r;
5958 FOR_EACH_VEC_ELT (m_regions, i, r)
5959 r->remap_svalue_ids (map);
5960
5961 /* Update IDs within ECs within constraints. */
5962 m_constraints->remap_svalue_ids (map);
5963
5964 /* Build a reordered svalues vector. */
5965 auto_vec<svalue *> new_svalues (m_svalues.length ());
5966 for (unsigned i = 0; i < m_svalues.length (); i++)
5967 {
5968 svalue_id dst (svalue_id::from_int (i));
5969 svalue_id src = map.get_src_for_dst (dst);
5970 new_svalues.quick_push (get_svalue (src));
5971 }
5972
5973 /* Copy over the reordered vec to m_svalues. */
5974 m_svalues.truncate (0);
5975 gcc_assert (m_svalues.space (new_svalues.length ()));
5976 svalue *sval;
5977 FOR_EACH_VEC_ELT (new_svalues, i, sval)
5978 m_svalues.quick_push (sval);
5979}
5980
5981/* Renumber the regions within this model according to MAP. */
5982
5983void
5984region_model::remap_region_ids (const region_id_map &map)
5985{
5986 /* Update IDs within regions. */
5987 unsigned i;
5988 region *r;
5989 FOR_EACH_VEC_ELT (m_regions, i, r)
5990 r->remap_region_ids (map);
5991
5992 /* Update IDs within svalues. */
5993 svalue *sval;
5994 FOR_EACH_VEC_ELT (m_svalues, i, sval)
5995 sval->remap_region_ids (map);
5996
5997 /* Build a reordered regions vector. */
5998 auto_vec<region *> new_regions (m_regions.length ());
5999 for (unsigned i = 0; i < m_regions.length (); i++)
6000 {
6001 region_id dst (region_id::from_int (i));
6002 region_id src = map.get_src_for_dst (dst);
6003 new_regions.quick_push (get_region (src));
6004 }
6005
6006 /* Copy over the reordered vec to m_regions. */
6007 m_regions.truncate (0);
6008 gcc_assert (m_regions.space (new_regions.length ()));
6009 FOR_EACH_VEC_ELT (new_regions, i, r)
6010 m_regions.quick_push (r);
6011}
6012
6013/* Delete all regions within SET_TO_PURGE, remapping region IDs for
6014 other regions. It's required that there are no uses of the
6015 regions within the set (or the region IDs will become invalid).
6016
6017 Accumulate stats to STATS. */
6018
6019void
6020region_model::purge_regions (const region_id_set &set_to_purge,
6021 purge_stats *stats,
6022 logger *)
6023{
6024 /* Build a mapping from old-rid to new-rid so that we can preserve
6025 order of the used IDs and move all redundant ones to the end.
6026 Iterate though region IDs, adding used ones to the front of
6027 the new list, and unused ones to the back. */
6028 region_id_map map (m_regions.length ());
6029 int next_used_new_rid = 0;
6030 int after_next_unused_new_rid = m_regions.length ();
6031 for (unsigned i = 0; i < m_regions.length (); i++)
6032 {
6033 region_id src (region_id::from_int (i));
6034 if (set_to_purge.region_p (src))
6035 map.put (src, region_id::from_int (--after_next_unused_new_rid));
6036 else
6037 map.put (src, region_id::from_int (next_used_new_rid++));
6038 }
6039 /* The two insertion points should have met. */
6040 gcc_assert (next_used_new_rid == after_next_unused_new_rid);
6041
6042 /* Now walk the regions and svalues, remapping rids,
6043 so that all the redundant regions are at the end. */
6044 remap_region_ids (map);
6045
6046 /* Drop the redundant regions from the end of the vector. */
6047 while ((signed)m_regions.length () > next_used_new_rid)
6048 {
6049 delete m_regions.pop ();
6050 if (stats)
6051 stats->m_num_regions++;
6052 }
6053}
6054
6055/* Populate *OUT with RID and all of its descendents.
6056 If EXCLUDE_RID is non-null, then don't add it or its descendents. */
6057
6058void
6059region_model::get_descendents (region_id rid, region_id_set *out,
6060 region_id exclude_rid) const
6061{
6062 out->add_region (rid);
6063
6064 bool changed = true;
6065 while (changed)
6066 {
6067 changed = false;
6068 unsigned i;
6069 region *r;
6070 FOR_EACH_VEC_ELT (m_regions, i, r)
6071 {
6072 region_id iter_rid = region_id::from_int (i);
6073 if (iter_rid == exclude_rid)
6074 continue;
6075 if (!out->region_p (iter_rid))
6076 {
6077 region_id parent_rid = r->get_parent ();
6078 if (!parent_rid.null_p ())
6079 if (out->region_p (parent_rid))
6080 {
6081 out->add_region (iter_rid);
6082 changed = true;
6083 }
6084 }
6085 }
6086 }
6087}
6088
6089/* Delete RID and all descendent regions.
6090 Find any pointers to such regions; convert convert them to
6091 poisoned values of kind PKIND.
6092 Accumulate stats on purged entities into STATS. */
6093
6094void
6095region_model::delete_region_and_descendents (region_id rid,
6096 enum poison_kind pkind,
6097 purge_stats *stats,
6098 logger *logger)
6099{
6100 /* Find all child and descendent regions. */
6101 region_id_set descendents (this);
6102 get_descendents (rid, &descendents, region_id::null ());
6103
6104 /* Find any pointers to such regions; convert to poisoned. */
6105 poison_any_pointers_to_bad_regions (descendents, pkind);
6106
6107 /* Delete all such regions. */
6108 purge_regions (descendents, stats, logger);
6109}
6110
6111/* Find any pointers to regions within BAD_REGIONS; convert them to
6112 poisoned values of kind PKIND. */
6113
6114void
6115region_model::poison_any_pointers_to_bad_regions (const region_id_set &
6116 bad_regions,
6117 enum poison_kind pkind)
6118{
6119 int i;
6120 svalue *sval;
6121 FOR_EACH_VEC_ELT (m_svalues, i, sval)
6122 if (region_svalue *ptr_sval = sval->dyn_cast_region_svalue ())
6123 {
6124 region_id ptr_dst = ptr_sval->get_pointee ();
6125 if (!ptr_dst.null_p ())
6126 if (bad_regions.region_p (ptr_dst))
6127 replace_svalue
6128 (svalue_id::from_int (i),
6129 new poisoned_svalue (pkind, sval->get_type ()));
6130 }
6131}
6132
6133/* Attempt to merge THIS with OTHER_MODEL, writing the result
6134 to OUT_MODEL, and populating SID_MAPPING. */
6135
6136bool
6137region_model::can_merge_with_p (const region_model &other_model,
6138 region_model *out_model,
6139 svalue_id_merger_mapping *sid_mapping) const
6140{
6141 gcc_assert (m_root_rid == other_model.m_root_rid);
6142 gcc_assert (m_root_rid.as_int () == 0);
6143 gcc_assert (sid_mapping);
6144 gcc_assert (out_model);
6145
6146 model_merger merger (this, &other_model, out_model, sid_mapping);
6147
6148 if (!root_region::can_merge_p (get_root_region (),
6149 other_model.get_root_region (),
6150 out_model->get_root_region (),
6151 &merger))
6152 return false;
6153
6154 /* Merge constraints. */
6155 constraint_manager::merge (*m_constraints,
6156 *other_model.m_constraints,
6157 out_model->m_constraints,
6158 merger);
6159
6160 out_model->validate ();
6161
6162 /* The merged model should be simpler (or as simple) as the inputs. */
6163#if 0
6164 gcc_assert (out_model->m_svalues.length () <= m_svalues.length ());
6165 gcc_assert (out_model->m_svalues.length ()
6166 <= other_model.m_svalues.length ());
6167#endif
6168 gcc_assert (out_model->m_regions.length () <= m_regions.length ());
6169 gcc_assert (out_model->m_regions.length ()
6170 <= other_model.m_regions.length ());
6171 // TODO: same, for constraints
6172
6173 return true;
6174}
6175
6176/* As above, but supply a placeholder svalue_id_merger_mapping
6177 instance to be used and receive output. For use in selftests. */
6178
6179bool
6180region_model::can_merge_with_p (const region_model &other_model,
6181 region_model *out_model) const
6182{
6183 svalue_id_merger_mapping sid_mapping (*this, other_model);
6184 return can_merge_with_p (other_model, out_model, &sid_mapping);
6185}
6186
6187/* For debugging purposes: look for a region within this region_model
6188 for a decl named NAME (or an SSA_NAME for such a decl),
6189 returning its value, or svalue_id::null if none are found. */
6190
6191svalue_id
6192region_model::get_value_by_name (const char *name) const
6193{
6194 gcc_assert (name);
6195 tree identifier = get_identifier (name);
6196 return get_root_region ()->get_value_by_name (identifier, *this);
6197}
6198
6199/* Generate or reuse an svalue_id within this model for an index
6200 into an array of type PTR_TYPE, based on OFFSET_SID. */
6201
6202svalue_id
6203region_model::convert_byte_offset_to_array_index (tree ptr_type,
6204 svalue_id offset_sid)
6205{
6206 gcc_assert (POINTER_TYPE_P (ptr_type));
6207
6208 if (tree offset_cst = maybe_get_constant (offset_sid))
6209 {
6210 tree elem_type = TREE_TYPE (ptr_type);
6211
6212 /* Arithmetic on void-pointers is a GNU C extension, treating the size
6213 of a void as 1.
6214 https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html
6215
6216 Returning early for this case avoids a diagnostic from within the
6217 call to size_in_bytes. */
6218 if (TREE_CODE (elem_type) == VOID_TYPE)
6219 return offset_sid;
6220
6221 /* This might not be a constant. */
6222 tree byte_size = size_in_bytes (elem_type);
6223
6224 tree index
6225 = fold_build2 (TRUNC_DIV_EXPR, integer_type_node,
6226 offset_cst, byte_size);
6227
6228 if (CONSTANT_CLASS_P (index))
6229 return get_or_create_constant_svalue (index);
6230 }
6231
6232 /* Otherwise, we don't know the array index; generate a new unknown value.
6233 TODO: do we need to capture the relationship between two unknown
6234 values (the offset and the index)? */
6235 return add_svalue (new unknown_svalue (integer_type_node));
6236}
6237
6238/* Get a region of type TYPE for PTR_SID[OFFSET_SID/sizeof (*PTR_SID)].
6239
6240 If OFFSET_SID is known to be zero, then dereference PTR_SID.
6241 Otherwise, impose a view of "typeof(*PTR_SID)[]" on *PTR_SID,
6242 and then get a view of type TYPE on the relevant array element. */
6243
6244region_id
6245region_model::get_or_create_mem_ref (tree type,
6246 svalue_id ptr_sid,
6247 svalue_id offset_sid,
6248 region_model_context *ctxt)
6249{
6250 svalue *ptr_sval = get_svalue (ptr_sid);
6251 tree ptr_type = ptr_sval->get_type ();
6252 gcc_assert (ptr_type);
6253
6254 region_id raw_rid = deref_rvalue (ptr_sid, ctxt);
6255
6256 svalue *offset_sval = get_svalue (offset_sid);
6257 tree offset_type = offset_sval->get_type ();
6258 gcc_assert (offset_type);
6259
6260 if (constant_svalue *cst_sval = offset_sval->dyn_cast_constant_svalue ())
6261 {
6262 if (zerop (cst_sval->get_constant ()))
6263 {
6264 /* Handle the zero offset case. */
6265 return get_or_create_view (raw_rid, type);
6266 }
6267
6268 /* If we're already within an array of the correct type,
6269 then we want to reuse that array, rather than starting
6270 a new view.
6271 If so, figure out our raw_rid's offset from its parent,
6272 if we can, and use that to offset OFFSET_SID, and create
6273 the element within the parent region. */
6274 region *raw_reg = get_region (raw_rid);
6275 region_id parent_rid = raw_reg->get_parent ();
6276 tree parent_type = get_region (parent_rid)->get_type ();
6277 if (parent_type
6278 && TREE_CODE (parent_type) == ARRAY_TYPE)
6279 {
6280 // TODO: check we have the correct parent type
6281 array_region *parent_array = get_region <array_region> (parent_rid);
6282 array_region::key_t key_for_raw_rid;
6283 if (parent_array->get_key_for_child_region (raw_rid,
6284 &key_for_raw_rid))
6285 {
6286 /* Convert from offset to index. */
6287 svalue_id index_sid
6288 = convert_byte_offset_to_array_index (ptr_type, offset_sid);
6289 if (tree index_cst
6290 = get_svalue (index_sid)->maybe_get_constant ())
6291 {
6292 array_region::key_t index_offset
6293 = array_region::key_from_constant (index_cst);
6294 array_region::key_t index_rel_to_parent
6295 = key_for_raw_rid + index_offset;
6296 tree index_rel_to_parent_cst
6297 = wide_int_to_tree (integer_type_node,
6298 index_rel_to_parent);
6299 svalue_id index_sid
6300 = get_or_create_constant_svalue (index_rel_to_parent_cst);
6301
6302 /* Carry on, using the parent region and adjusted index. */
6303 region_id element_rid
6304 = parent_array->get_element (this, raw_rid, index_sid,
6305 ctxt);
6306 return get_or_create_view (element_rid, type);
6307 }
6308 }
6309 }
6310 }
6311
6312 tree array_type = build_array_type (TREE_TYPE (ptr_type),
6313 integer_type_node);
6314 region_id array_view_rid = get_or_create_view (raw_rid, array_type);
6315 array_region *array_reg = get_region <array_region> (array_view_rid);
6316
6317 svalue_id index_sid
6318 = convert_byte_offset_to_array_index (ptr_type, offset_sid);
6319
6320 region_id element_rid
6321 = array_reg->get_element (this, array_view_rid, index_sid, ctxt);
6322
6323 return get_or_create_view (element_rid, type);
6324}
6325
6326/* Get a region of type TYPE for PTR_SID + OFFSET_SID.
6327
6328 If OFFSET_SID is known to be zero, then dereference PTR_SID.
6329 Otherwise, impose a view of "typeof(*PTR_SID)[]" on *PTR_SID,
6330 and then get a view of type TYPE on the relevant array element. */
6331
6332region_id
6333region_model::get_or_create_pointer_plus_expr (tree type,
6334 svalue_id ptr_sid,
6335 svalue_id offset_in_bytes_sid,
6336 region_model_context *ctxt)
6337{
6338 return get_or_create_mem_ref (type,
6339 ptr_sid,
6340 offset_in_bytes_sid,
6341 ctxt);
6342}
6343
6344/* Get or create a view of type TYPE of the region with id RAW_ID.
6345 Return the id of the view (or RAW_ID if it of the same type). */
6346
6347region_id
6348region_model::get_or_create_view (region_id raw_rid, tree type)
6349{
6350 region *raw_region = get_region (raw_rid);
6351
6352 gcc_assert (TYPE_P (type));
6353 if (type != raw_region->get_type ())
6354 {
6355 /* If the region already has a view of the requested type,
6356 reuse it. */
6357 region_id existing_view_rid = raw_region->get_view (type, this);
6358 if (!existing_view_rid.null_p ())
6359 return existing_view_rid;
6360
6361 /* Otherwise, make one (adding it to the region_model and
6362 to the viewed region). */
6363 region_id view_rid = add_region_for_type (raw_rid, type);
6364 raw_region->add_view (view_rid, this);
6365 // TODO: something to signify that this is a "view"
6366 return view_rid;
6367 }
6368
6369 return raw_rid;
6370}
6371
6372/* Attempt to get the fndecl used at CALL, if known, or NULL_TREE
6373 otherwise. */
6374
6375tree
6376region_model::get_fndecl_for_call (const gcall *call,
6377 region_model_context *ctxt)
6378{
6379 tree fn_ptr = gimple_call_fn (call);
6380 if (fn_ptr == NULL_TREE)
6381 return NULL_TREE;
6382 svalue_id fn_ptr_sid = get_rvalue (fn_ptr, ctxt);
6383 svalue *fn_ptr_sval = get_svalue (fn_ptr_sid);
6384 if (region_svalue *fn_ptr_ptr = fn_ptr_sval->dyn_cast_region_svalue ())
6385 {
6386 region_id fn_rid = fn_ptr_ptr->get_pointee ();
6387 code_region *code = get_root_region ()->get_code_region (this);
6388 if (code)
6389 {
6390 tree fn_decl = code->get_tree_for_child_region (fn_rid);
6391 return fn_decl;
6392 }
6393 }
6394
6395 return NULL_TREE;
6396}
6397
6398/* struct model_merger. */
6399
6400/* Dump a multiline representation of this merger to PP. */
6401
6402void
6403model_merger::dump_to_pp (pretty_printer *pp) const
6404{
6405 pp_string (pp, "model A:");
6406 pp_newline (pp);
6407 m_model_a->dump_to_pp (pp, false);
6408 pp_newline (pp);
6409
6410 pp_string (pp, "model B:");
6411 pp_newline (pp);
6412 m_model_b->dump_to_pp (pp, false);
6413 pp_newline (pp);
6414
6415 pp_string (pp, "merged model:");
6416 pp_newline (pp);
6417 m_merged_model->dump_to_pp (pp, false);
6418 pp_newline (pp);
6419
6420 pp_string (pp, "region map: model A to merged model:");
6421 pp_newline (pp);
6422 m_map_regions_from_a_to_m.dump_to_pp (pp);
6423 pp_newline (pp);
6424
6425 pp_string (pp, "region map: model B to merged model:");
6426 pp_newline (pp);
6427 m_map_regions_from_b_to_m.dump_to_pp (pp);
6428 pp_newline (pp);
6429
6430 m_sid_mapping->dump_to_pp (pp);
6431}
6432
6433/* Dump a multiline representation of this merger to FILE. */
6434
6435void
6436model_merger::dump (FILE *fp) const
6437{
6438 pretty_printer pp;
6439 pp_format_decoder (&pp) = default_tree_printer;
6440 pp_show_color (&pp) = pp_show_color (global_dc->printer);
6441 pp.buffer->stream = fp;
6442 dump_to_pp (&pp);
6443 pp_flush (&pp);
6444}
6445
6446/* Dump a multiline representation of this merger to stderr. */
6447
6448DEBUG_FUNCTION void
6449model_merger::dump () const
6450{
6451 dump (stderr);
6452}
6453
6454/* Attempt to merge the svalues of SID_A and SID_B (from their
6455 respective models), writing the id of the resulting svalue
6456 into *MERGED_SID.
6457 Return true if the merger is possible, false otherwise. */
6458
6459bool
6460model_merger::can_merge_values_p (svalue_id sid_a,
6461 svalue_id sid_b,
6462 svalue_id *merged_sid)
6463{
6464 gcc_assert (merged_sid);
6465 svalue *sval_a = m_model_a->get_svalue (sid_a);
6466 svalue *sval_b = m_model_b->get_svalue (sid_b);
6467
6468 /* If both are NULL, then the "values" are trivially mergeable. */
6469 if (!sval_a && !sval_b)
6470 return true;
6471
6472 /* If one is NULL and the other non-NULL, then the "values"
6473 are not mergeable. */
6474 if (!(sval_a && sval_b))
6475 return false;
6476
6477 /* Have they both already been mapped to the same new svalue_id?
6478 If so, use it. */
6479 svalue_id sid_a_in_m
6480 = m_sid_mapping->m_map_from_a_to_m.get_dst_for_src (sid_a);
6481 svalue_id sid_b_in_m
6482 = m_sid_mapping->m_map_from_b_to_m.get_dst_for_src (sid_b);
6483 if (!sid_a_in_m.null_p ()
6484 && !sid_b_in_m.null_p ()
6485 && sid_a_in_m == sid_b_in_m)
6486 {
6487 *merged_sid = sid_a_in_m;
6488 return true;
6489 }
6490
6491 tree type = sval_a->get_type ();
6492 if (type == NULL_TREE)
6493 type = sval_b->get_type ();
6494
6495 /* If the values have different kinds, or are both unknown,
6496 then merge as "unknown". */
6497 if (sval_a->get_kind () != sval_b->get_kind ()
6498 || sval_a->get_kind () == SK_UNKNOWN)
6499 {
6500 svalue *merged_sval = new unknown_svalue (type);
6501 *merged_sid = m_merged_model->add_svalue (merged_sval);
6502 record_svalues (sid_a, sid_b, *merged_sid);
6503 return true;
6504 }
6505
6506 gcc_assert (sval_a->get_kind () == sval_b->get_kind ());
6507
6508 switch (sval_a->get_kind ())
6509 {
6510 default:
6511 case SK_UNKNOWN: /* SK_UNKNOWN handled above. */
6512 gcc_unreachable ();
6513
6514 case SK_REGION:
6515 {
6516 /* If we have two region pointers, then we can merge (possibly to
6517 "unknown"). */
6518 const region_svalue &region_sval_a = *as_a <region_svalue *> (sval_a);
6519 const region_svalue &region_sval_b = *as_a <region_svalue *> (sval_b);
6520 region_svalue::merge_values (region_sval_a, region_sval_b,
6521 merged_sid, type,
6522 this);
6523 record_svalues (sid_a, sid_b, *merged_sid);
6524 return true;
6525 }
6526 break;
6527 case SK_CONSTANT:
6528 {
6529 /* If we have two constants, then we can merge. */
6530 const constant_svalue &cst_sval_a = *as_a <constant_svalue *> (sval_a);
6531 const constant_svalue &cst_sval_b = *as_a <constant_svalue *> (sval_b);
6532 constant_svalue::merge_values (cst_sval_a, cst_sval_b,
6533 merged_sid, this);
6534 record_svalues (sid_a, sid_b, *merged_sid);
6535 return true;
6536 }
6537 break;
6538
6539 case SK_POISONED:
6540 case SK_SETJMP:
6541 return false;
6542 }
6543}
6544
6545/* Record that A_RID in model A and B_RID in model B
6546 correspond to MERGED_RID in the merged model, so
6547 that pointers can be accurately merged. */
6548
6549void
6550model_merger::record_regions (region_id a_rid,
6551 region_id b_rid,
6552 region_id merged_rid)
6553{
6554 m_map_regions_from_a_to_m.put (a_rid, merged_rid);
6555 m_map_regions_from_b_to_m.put (b_rid, merged_rid);
6556}
6557
6558/* Record that A_SID in model A and B_SID in model B
6559 correspond to MERGED_SID in the merged model. */
6560
6561void
6562model_merger::record_svalues (svalue_id a_sid,
6563 svalue_id b_sid,
6564 svalue_id merged_sid)
6565{
6566 gcc_assert (m_sid_mapping);
6567 m_sid_mapping->m_map_from_a_to_m.put (a_sid, merged_sid);
6568 m_sid_mapping->m_map_from_b_to_m.put (b_sid, merged_sid);
6569}
6570
6571/* struct svalue_id_merger_mapping. */
6572
6573/* svalue_id_merger_mapping's ctor. */
6574
6575svalue_id_merger_mapping::svalue_id_merger_mapping (const region_model &a,
6576 const region_model &b)
6577: m_map_from_a_to_m (a.get_num_svalues ()),
6578 m_map_from_b_to_m (b.get_num_svalues ())
6579{
6580}
6581
6582/* Dump a multiline representation of this to PP. */
6583
6584void
6585svalue_id_merger_mapping::dump_to_pp (pretty_printer *pp) const
6586{
6587 pp_string (pp, "svalue_id map: model A to merged model:");
6588 pp_newline (pp);
6589 m_map_from_a_to_m.dump_to_pp (pp);
6590 pp_newline (pp);
6591
6592 pp_string (pp, "svalue_id map: model B to merged model:");
6593 pp_newline (pp);
6594 m_map_from_b_to_m.dump_to_pp (pp);
6595 pp_newline (pp);
6596}
6597
6598/* Dump a multiline representation of this to FILE. */
6599
6600void
6601svalue_id_merger_mapping::dump (FILE *fp) const
6602{
6603 pretty_printer pp;
6604 pp_format_decoder (&pp) = default_tree_printer;
6605 pp_show_color (&pp) = pp_show_color (global_dc->printer);
6606 pp.buffer->stream = fp;
6607 dump_to_pp (&pp);
6608 pp_flush (&pp);
6609}
6610
6611/* Dump a multiline representation of this to stderr. */
6612
6613DEBUG_FUNCTION void
6614svalue_id_merger_mapping::dump () const
6615{
6616 dump (stderr);
6617}
6618
6619/* struct canonicalization. */
6620
6621/* canonicalization's ctor. */
6622
6623canonicalization::canonicalization (const region_model &model)
6624: m_model (model),
6625 m_rid_map (model.get_num_regions ()),
6626 m_sid_map (model.get_num_svalues ()),
6627 m_next_rid_int (0),
6628 m_next_sid_int (0)
6629{
6630}
6631
6632/* If we've not seen RID yet, assign it a canonicalized region_id,
6633 and walk the region's svalue and then the region. */
6634
6635void
6636canonicalization::walk_rid (region_id rid)
6637{
6638 /* Stop if we've already seen RID. */
6639 if (!m_rid_map.get_dst_for_src (rid).null_p ())
6640 return;
6641
6642 region *region = m_model.get_region (rid);
6643 if (region)
6644 {
6645 m_rid_map.put (rid, region_id::from_int (m_next_rid_int++));
6646 walk_sid (region->get_value_direct ());
6647 region->walk_for_canonicalization (this);
6648 }
6649}
6650
6651/* If we've not seen SID yet, assign it a canonicalized svalue_id,
6652 and walk the svalue (and potentially regions e.g. for ptr values). */
6653
6654void
6655canonicalization::walk_sid (svalue_id sid)
6656{
6657 /* Stop if we've already seen SID. */
6658 if (!m_sid_map.get_dst_for_src (sid).null_p ())
6659 return;
6660
6661 svalue *sval = m_model.get_svalue (sid);
6662 if (sval)
6663 {
6664 m_sid_map.put (sid, svalue_id::from_int (m_next_sid_int++));
6665 /* Potentially walk regions e.g. for ptrs. */
6666 sval->walk_for_canonicalization (this);
6667 }
6668}
6669
6670/* Dump a multiline representation of this to PP. */
6671
6672void
6673canonicalization::dump_to_pp (pretty_printer *pp) const
6674{
6675 pp_string (pp, "region_id map:");
6676 pp_newline (pp);
6677 m_rid_map.dump_to_pp (pp);
6678 pp_newline (pp);
6679
6680 pp_string (pp, "svalue_id map:");
6681 pp_newline (pp);
6682 m_sid_map.dump_to_pp (pp);
6683 pp_newline (pp);
6684}
6685
6686/* Dump a multiline representation of this to FILE. */
6687
6688void
6689canonicalization::dump (FILE *fp) const
6690{
6691 pretty_printer pp;
6692 pp_format_decoder (&pp) = default_tree_printer;
6693 pp_show_color (&pp) = pp_show_color (global_dc->printer);
6694 pp.buffer->stream = fp;
6695 dump_to_pp (&pp);
6696 pp_flush (&pp);
6697}
6698
6699/* Dump a multiline representation of this to stderr. */
6700
6701DEBUG_FUNCTION void
6702canonicalization::dump () const
6703{
6704 dump (stderr);
6705}
6706
6707/* Update HSTATE with a hash of SID. */
6708
6709void
6710inchash::add (svalue_id sid, inchash::hash &hstate)
6711{
6712 hstate.add_int (sid.as_int ());
6713}
6714
6715/* Update HSTATE with a hash of RID. */
6716
6717void
6718inchash::add (region_id rid, inchash::hash &hstate)
6719{
6720 hstate.add_int (rid.as_int ());
6721}
6722
6723/* Dump RMODEL fully to stderr (i.e. without summarization). */
6724
6725DEBUG_FUNCTION void
6726debug (const region_model &rmodel)
6727{
6728 rmodel.dump (false);
6729}
6730
6731#if CHECKING_P
6732
6733namespace selftest {
6734
6735/* Implementation detail of the ASSERT_CONDITION_* macros. */
6736
6737void
6738assert_condition (const location &loc,
6739 region_model &model,
6740 tree lhs, tree_code op, tree rhs,
6741 tristate expected)
6742{
6743 tristate actual = model.eval_condition (lhs, op, rhs, NULL);
6744 ASSERT_EQ_AT (loc, actual, expected);
6745}
6746
6747/* Implementation detail of ASSERT_DUMP_EQ. */
6748
6749static void
6750assert_dump_eq (const location &loc,
6751 const region_model &model,
6752 bool summarize,
6753 const char *expected)
6754{
6755 auto_fix_quotes sentinel;
6756 pretty_printer pp;
6757 pp_format_decoder (&pp) = default_tree_printer;
6758 model.dump_to_pp (&pp, summarize);
6759 ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected);
6760}
6761
6762/* Assert that MODEL.dump_to_pp (SUMMARIZE) is EXPECTED. */
6763
6764#define ASSERT_DUMP_EQ(MODEL, SUMMARIZE, EXPECTED) \
6765 SELFTEST_BEGIN_STMT \
6766 assert_dump_eq ((SELFTEST_LOCATION), (MODEL), (SUMMARIZE), (EXPECTED)); \
6767 SELFTEST_END_STMT
6768
6769/* Smoketest for region_model::dump_to_pp. */
6770
6771static void
6772test_dump ()
6773{
6774 region_model model;
6775 model.get_root_region ()->ensure_stack_region (&model);
6776 model.get_root_region ()->ensure_globals_region (&model);
6777 model.get_root_region ()->ensure_heap_region (&model);
6778
6779 ASSERT_DUMP_EQ (model, false,
6780 "r0: {kind: `root', parent: null, sval: null}\n"
6781 "|-stack: r1: {kind: `stack', parent: r0, sval: sv0}\n"
6782 "| |: sval: sv0: {poisoned: uninit}\n"
6783 "|-globals: r2: {kind: `globals', parent: r0, sval: null, map: {}}\n"
6784 "`-heap: r3: {kind: `heap', parent: r0, sval: sv1}\n"
6785 " |: sval: sv1: {poisoned: uninit}\n"
6786 "svalues:\n"
6787 " sv0: {poisoned: uninit}\n"
6788 " sv1: {poisoned: uninit}\n"
6789 "constraint manager:\n"
6790 " equiv classes:\n"
6791 " constraints:\n");
6792 ASSERT_DUMP_EQ (model, true, "");
6793}
6794
6795/* Verify that calling region_model::get_rvalue repeatedly on the same
6796 tree constant retrieves the same svalue_id. */
6797
6798static void
6799test_unique_constants ()
6800{
6801 tree int_0 = build_int_cst (integer_type_node, 0);
6802 tree int_42 = build_int_cst (integer_type_node, 42);
6803
6804 test_region_model_context ctxt;
6805 region_model model;
6806 ASSERT_EQ (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_0, &ctxt));
6807 ASSERT_EQ (model.get_rvalue (int_42, &ctxt),
6808 model.get_rvalue (int_42, &ctxt));
6809 ASSERT_NE (model.get_rvalue (int_0, &ctxt), model.get_rvalue (int_42, &ctxt));
6810 ASSERT_EQ (ctxt.get_num_diagnostics (), 0);
6811}
6812
6813/* Check that operator== and hashing works as expected for the
6814 various svalue subclasses. */
6815
6816static void
6817test_svalue_equality ()
6818{
6819 tree int_42 = build_int_cst (integer_type_node, 42);
6820 tree int_0 = build_int_cst (integer_type_node, 0);
6821
6822 /* Create pairs instances of the various subclasses of svalue,
6823 testing for hash and equality between (this, this) and
6824 (this, other of same subclass). */
6825 svalue *ptr_to_r0
6826 = new region_svalue (ptr_type_node, region_id::from_int (0));
6827 svalue *ptr_to_r1
6828 = new region_svalue (ptr_type_node, region_id::from_int (1));
6829
6830 ASSERT_EQ (ptr_to_r0->hash (), ptr_to_r0->hash ());
6831 ASSERT_EQ (*ptr_to_r0, *ptr_to_r0);
6832
6833 ASSERT_NE (ptr_to_r0->hash (), ptr_to_r1->hash ());
6834 ASSERT_NE (*ptr_to_r0, *ptr_to_r1);
6835
6836 svalue *cst_int_42 = new constant_svalue (int_42);
6837 svalue *cst_int_0 = new constant_svalue (int_0);
6838
6839 ASSERT_EQ (cst_int_42->hash (), cst_int_42->hash ());
6840 ASSERT_EQ (*cst_int_42, *cst_int_42);
6841
6842 ASSERT_NE (cst_int_42->hash (), cst_int_0->hash ());
6843 ASSERT_NE (*cst_int_42, *cst_int_0);
6844
6845 svalue *uninit = new poisoned_svalue (POISON_KIND_UNINIT, NULL_TREE);
6846 svalue *freed = new poisoned_svalue (POISON_KIND_FREED, NULL_TREE);
6847
6848 ASSERT_EQ (uninit->hash (), uninit->hash ());
6849 ASSERT_EQ (*uninit, *uninit);
6850
6851 ASSERT_NE (uninit->hash (), freed->hash ());
6852 ASSERT_NE (*uninit, *freed);
6853
6854 svalue *unknown_0 = new unknown_svalue (ptr_type_node);
6855 svalue *unknown_1 = new unknown_svalue (ptr_type_node);
6856 ASSERT_EQ (unknown_0->hash (), unknown_0->hash ());
6857 ASSERT_EQ (*unknown_0, *unknown_0);
6858 ASSERT_EQ (*unknown_1, *unknown_1);
6859
6860 /* Comparisons between different kinds of svalue. */
6861 ASSERT_NE (*ptr_to_r0, *cst_int_42);
6862 ASSERT_NE (*ptr_to_r0, *uninit);
6863 ASSERT_NE (*ptr_to_r0, *unknown_0);
6864 ASSERT_NE (*cst_int_42, *ptr_to_r0);
6865 ASSERT_NE (*cst_int_42, *uninit);
6866 ASSERT_NE (*cst_int_42, *unknown_0);
6867 ASSERT_NE (*uninit, *ptr_to_r0);
6868 ASSERT_NE (*uninit, *cst_int_42);
6869 ASSERT_NE (*uninit, *unknown_0);
6870 ASSERT_NE (*unknown_0, *ptr_to_r0);
6871 ASSERT_NE (*unknown_0, *cst_int_42);
6872 ASSERT_NE (*unknown_0, *uninit);
6873
6874 delete ptr_to_r0;
6875 delete ptr_to_r1;
6876 delete cst_int_42;
6877 delete cst_int_0;
6878 delete uninit;
6879 delete freed;
6880 delete unknown_0;
6881 delete unknown_1;
6882}
6883
6884/* Check that operator== and hashing works as expected for the
6885 various region subclasses. */
6886
6887static void
6888test_region_equality ()
6889{
6890 region *r0
6891 = new primitive_region (region_id::from_int (3), integer_type_node);
6892 region *r1
6893 = new primitive_region (region_id::from_int (4), integer_type_node);
6894
6895 ASSERT_EQ (*r0, *r0);
6896 ASSERT_EQ (r0->hash (), r0->hash ());
6897 ASSERT_NE (*r0, *r1);
6898 ASSERT_NE (r0->hash (), r1->hash ());
6899
6900 delete r0;
6901 delete r1;
6902
6903 // TODO: test coverage for the map within a map_region
6904}
6905
6906/* A subclass of purge_criteria for selftests: purge all svalue_id instances. */
6907
6908class purge_all_svalue_ids : public purge_criteria
6909{
6910public:
6911 bool should_purge_p (svalue_id) const FINAL OVERRIDE
6912 {
6913 return true;
6914 }
6915};
6916
6917/* A subclass of purge_criteria: purge a specific svalue_id. */
6918
6919class purge_one_svalue_id : public purge_criteria
6920{
6921public:
6922 purge_one_svalue_id (svalue_id victim) : m_victim (victim) {}
6923
6924 purge_one_svalue_id (region_model model, tree expr)
6925 : m_victim (model.get_rvalue (expr, NULL)) {}
6926
6927 bool should_purge_p (svalue_id sid) const FINAL OVERRIDE
6928 {
6929 return sid == m_victim;
6930 }
6931
6932private:
6933 svalue_id m_victim;
6934};
6935
6936/* Check that constraint_manager::purge works for individual svalue_ids. */
6937
6938static void
6939test_purging_by_criteria ()
6940{
6941 tree int_42 = build_int_cst (integer_type_node, 42);
6942 tree int_0 = build_int_cst (integer_type_node, 0);
6943
6944 tree x = build_global_decl ("x", integer_type_node);
6945 tree y = build_global_decl ("y", integer_type_node);
6946
6947 {
6948 region_model model0;
6949 region_model model1;
6950
6951 ADD_SAT_CONSTRAINT (model1, x, EQ_EXPR, y);
6952 ASSERT_NE (model0, model1);
6953
6954 purge_stats stats_for_px;
6955 purge_one_svalue_id px (model1, x);
6956 model1.get_constraints ()->purge (px, &stats_for_px);
6957 ASSERT_EQ (stats_for_px.m_num_equiv_classes, 0);
6958
6959 purge_stats stats_for_py;
6960 purge_one_svalue_id py (model1.get_rvalue (y, NULL));
6961 model1.get_constraints ()->purge (py, &stats_for_py);
6962 ASSERT_EQ (stats_for_py.m_num_equiv_classes, 1);
6963
6964 ASSERT_EQ (*model0.get_constraints (), *model1.get_constraints ());
6965 }
6966
6967 {
6968 region_model model0;
6969 region_model model1;
6970
6971 ADD_SAT_CONSTRAINT (model1, x, EQ_EXPR, int_42);
6972 ASSERT_NE (model0, model1);
6973 ASSERT_CONDITION_TRUE (model1, x, EQ_EXPR, int_42);
6974
6975 purge_stats stats;
6976 model1.get_constraints ()->purge (purge_one_svalue_id (model1, x), &stats);
6977
6978 ASSERT_CONDITION_UNKNOWN (model1, x, EQ_EXPR, int_42);
6979 }
6980
6981 {
6982 region_model model0;
6983 region_model model1;
6984
6985 ADD_SAT_CONSTRAINT (model1, x, GE_EXPR, int_0);
6986 ADD_SAT_CONSTRAINT (model1, x, LE_EXPR, int_42);
6987 ASSERT_NE (model0, model1);
6988
6989 ASSERT_CONDITION_TRUE (model1, x, GE_EXPR, int_0);
6990 ASSERT_CONDITION_TRUE (model1, x, LE_EXPR, int_42);
6991
6992 purge_stats stats;
6993 model1.get_constraints ()->purge (purge_one_svalue_id (model1, x), &stats);
6994
6995 ASSERT_CONDITION_UNKNOWN (model1, x, GE_EXPR, int_0);
6996 ASSERT_CONDITION_UNKNOWN (model1, x, LE_EXPR, int_42);
6997 }
6998
6999 {
7000 region_model model0;
7001 region_model model1;
7002
7003 ADD_SAT_CONSTRAINT (model1, x, NE_EXPR, int_42);
7004 ADD_SAT_CONSTRAINT (model1, y, NE_EXPR, int_0);
7005 ASSERT_NE (model0, model1);
7006 ASSERT_CONDITION_TRUE (model1, x, NE_EXPR, int_42);
7007 ASSERT_CONDITION_TRUE (model1, y, NE_EXPR, int_0);
7008
7009 purge_stats stats;
7010 model1.get_constraints ()->purge (purge_one_svalue_id (model1, x), &stats);
7011 ASSERT_NE (model0, model1);
7012
7013 ASSERT_CONDITION_UNKNOWN (model1, x, NE_EXPR, int_42);
7014 ASSERT_CONDITION_TRUE (model1, y, NE_EXPR, int_0);
7015 }
7016
7017 {
7018 region_model model0;
7019 region_model model1;
7020
7021 ADD_SAT_CONSTRAINT (model1, x, NE_EXPR, int_42);
7022 ADD_SAT_CONSTRAINT (model1, y, NE_EXPR, int_0);
7023 ASSERT_NE (model0, model1);
7024 ASSERT_CONDITION_TRUE (model1, x, NE_EXPR, int_42);
7025 ASSERT_CONDITION_TRUE (model1, y, NE_EXPR, int_0);
7026
7027 purge_stats stats;
7028 model1.get_constraints ()->purge (purge_all_svalue_ids (), &stats);
7029 ASSERT_CONDITION_UNKNOWN (model1, x, NE_EXPR, int_42);
7030 ASSERT_CONDITION_UNKNOWN (model1, y, NE_EXPR, int_0);
7031 }
7032
7033}
7034
7035/* Test that region_model::purge_unused_svalues works as expected. */
7036
7037static void
7038test_purge_unused_svalues ()
7039{
7040 tree int_42 = build_int_cst (integer_type_node, 42);
7041 tree int_0 = build_int_cst (integer_type_node, 0);
7042 tree x = build_global_decl ("x", integer_type_node);
7043 tree y = build_global_decl ("y", integer_type_node);
7044
7045 test_region_model_context ctxt;
7046 region_model model;
7047 model.set_to_new_unknown_value (model.get_lvalue (x, &ctxt), TREE_TYPE (x),
7048 &ctxt);
7049 model.set_to_new_unknown_value (model.get_lvalue (x, &ctxt), TREE_TYPE (x),
7050 &ctxt);
7051 model.set_to_new_unknown_value (model.get_lvalue (x, &ctxt), TREE_TYPE (x),
7052 &ctxt);
7053 model.add_constraint (x, NE_EXPR, int_42, &ctxt);
7054
7055 model.set_value (model.get_lvalue (x, &ctxt),
7056 model.get_rvalue (int_42, &ctxt),
7057 &ctxt);
7058 model.add_constraint (y, GT_EXPR, int_0, &ctxt);
7059
7060 /* The redundant unknown values should have been purged. */
7061 purge_stats purged;
7062 model.purge_unused_svalues (&purged, NULL);
7063 ASSERT_EQ (purged.m_num_svalues, 3);
7064
7065 /* and the redundant constraint on an old, unknown value for x should
7066 have been purged. */
7067 ASSERT_EQ (purged.m_num_equiv_classes, 1);
7068 ASSERT_EQ (purged.m_num_constraints, 1);
7069 ASSERT_EQ (model.get_constraints ()->m_constraints.length (), 2);
7070
7071 /* ...but we should still have x == 42. */
7072 ASSERT_EQ (model.eval_condition (x, EQ_EXPR, int_42, &ctxt),
7073 tristate::TS_TRUE);
7074
7075 /* ...and we should still have the constraint on y. */
7076 ASSERT_EQ (model.eval_condition (y, GT_EXPR, int_0, &ctxt),
7077 tristate::TS_TRUE);
7078
7079 ASSERT_EQ (ctxt.get_num_diagnostics (), 0);
7080}
7081
7082/* Verify that simple assignments work as expected. */
7083
7084static void
7085test_assignment ()
7086{
7087 tree int_0 = build_int_cst (integer_type_node, 0);
7088 tree x = build_global_decl ("x", integer_type_node);
7089 tree y = build_global_decl ("y", integer_type_node);
7090
7091 /* "x == 0", then use of y, then "y = 0;". */
7092 region_model model;
7093 ADD_SAT_CONSTRAINT (model, x, EQ_EXPR, int_0);
7094 ASSERT_CONDITION_UNKNOWN (model, y, EQ_EXPR, int_0);
7095 model.set_value (model.get_lvalue (y, NULL),
7096 model.get_rvalue (int_0, NULL),
7097 NULL);
7098 ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, int_0);
7099 ASSERT_CONDITION_TRUE (model, y, EQ_EXPR, x);
7100
7101 ASSERT_DUMP_EQ (model, true, "y: 0, {x}: unknown, x == y");
7102}
7103
7104/* Verify the details of pushing and popping stack frames. */
7105
7106static void
7107test_stack_frames ()
7108{
7109 tree int_42 = build_int_cst (integer_type_node, 42);
7110 tree int_10 = build_int_cst (integer_type_node, 10);
7111 tree int_5 = build_int_cst (integer_type_node, 5);
7112 tree int_0 = build_int_cst (integer_type_node, 0);
7113
7114 auto_vec <tree> param_types;
7115 tree parent_fndecl = make_fndecl (integer_type_node,
7116 "parent_fn",
7117 param_types);
7118 allocate_struct_function (parent_fndecl, true);
7119
7120 tree child_fndecl = make_fndecl (integer_type_node,
7121 "child_fn",
7122 param_types);
7123 allocate_struct_function (child_fndecl, true);
7124
7125 /* "a" and "b" in the parent frame. */
7126 tree a = build_decl (UNKNOWN_LOCATION, PARM_DECL,
7127 get_identifier ("a"),
7128 integer_type_node);
7129 tree b = build_decl (UNKNOWN_LOCATION, PARM_DECL,
7130 get_identifier ("b"),
7131 integer_type_node);
7132 /* "x" and "y" in a child frame. */
7133 tree x = build_decl (UNKNOWN_LOCATION, PARM_DECL,
7134 get_identifier ("x"),
7135 integer_type_node);
7136 tree y = build_decl (UNKNOWN_LOCATION, PARM_DECL,
7137 get_identifier ("y"),
7138 integer_type_node);
7139
7140 /* "p" global. */
7141 tree p = build_global_decl ("p", ptr_type_node);
7142
7143 /* "q" global. */
7144 tree q = build_global_decl ("q", ptr_type_node);
7145
7146 test_region_model_context ctxt;
7147 region_model model;
7148
7149 /* Push stack frame for "parent_fn". */
7150 region_id parent_frame_rid
7151 = model.push_frame (DECL_STRUCT_FUNCTION (parent_fndecl), NULL, &ctxt);
7152 ASSERT_EQ (model.get_current_frame_id (), parent_frame_rid);
7153 region_id a_in_parent_rid = model.get_lvalue (a, &ctxt);
7154 model.set_value (a_in_parent_rid, model.get_rvalue (int_42, &ctxt), &ctxt);
7155 model.set_to_new_unknown_value (model.get_lvalue (b, &ctxt),
7156 integer_type_node, &ctxt);
7157 model.add_constraint (b, LT_EXPR, int_10, &ctxt);
7158 ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
7159 tristate (tristate::TS_TRUE));
7160
7161 /* Push stack frame for "child_fn". */
7162 region_id child_frame_rid
7163 = model.push_frame (DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
7164 ASSERT_EQ (model.get_current_frame_id (), child_frame_rid);
7165 region_id x_in_child_rid = model.get_lvalue (x, &ctxt);
7166 model.set_value (x_in_child_rid, model.get_rvalue (int_0, &ctxt), &ctxt);
7167 model.set_to_new_unknown_value (model.get_lvalue (y, &ctxt),
7168 integer_type_node, &ctxt);
7169 model.add_constraint (y, NE_EXPR, int_5, &ctxt);
7170 ASSERT_EQ (model.eval_condition (y, NE_EXPR, int_5, &ctxt),
7171 tristate (tristate::TS_TRUE));
7172
7173 /* Point a global pointer at a local in the child frame: p = &x. */
7174 region_id p_in_globals_rid = model.get_lvalue (p, &ctxt);
7175 model.set_value (p_in_globals_rid,
7176 model.get_or_create_ptr_svalue (ptr_type_node,
7177 x_in_child_rid),
7178 &ctxt);
7179
7180 /* Point another global pointer at p: q = &p. */
7181 region_id q_in_globals_rid = model.get_lvalue (q, &ctxt);
7182 model.set_value (q_in_globals_rid,
7183 model.get_or_create_ptr_svalue (ptr_type_node,
7184 p_in_globals_rid),
7185 &ctxt);
7186
7187 /* Test get_descendents. */
7188 region_id_set descendents (&model);
7189 model.get_descendents (child_frame_rid, &descendents, region_id::null ());
7190 ASSERT_TRUE (descendents.region_p (child_frame_rid));
7191 ASSERT_TRUE (descendents.region_p (x_in_child_rid));
7192 ASSERT_FALSE (descendents.region_p (a_in_parent_rid));
7193 ASSERT_EQ (descendents.num_regions (), 3);
7194#if 0
7195 auto_vec<region_id> test_vec;
7196 for (region_id_set::iterator_t iter = descendents.begin ();
7197 iter != descendents.end ();
7198 ++iter)
7199 test_vec.safe_push (*iter);
7200 gcc_unreachable (); // TODO
7201 //ASSERT_EQ ();
7202#endif
7203
7204 ASSERT_DUMP_EQ (model, true,
7205 "x: 0, {y}: unknown, p: &x, q: &p, b < 10, y != 5");
7206
7207 /* Pop the "child_fn" frame from the stack. */
7208 purge_stats purged;
7209 model.pop_frame (true, &purged, &ctxt);
7210
7211 /* We should have purged the unknown values for x and y. */
7212 ASSERT_EQ (purged.m_num_svalues, 2);
7213
7214 /* We should have purged the frame region and the regions for x and y. */
7215 ASSERT_EQ (purged.m_num_regions, 3);
7216
7217 /* We should have purged the constraint on y. */
7218 ASSERT_EQ (purged.m_num_equiv_classes, 1);
7219 ASSERT_EQ (purged.m_num_constraints, 1);
7220
7221 /* Verify that p (which was pointing at the local "x" in the popped
7222 frame) has been poisoned. */
7223 svalue *new_p_sval = model.get_svalue (model.get_rvalue (p, &ctxt));
7224 ASSERT_EQ (new_p_sval->get_kind (), SK_POISONED);
7225 ASSERT_EQ (new_p_sval->dyn_cast_poisoned_svalue ()->get_poison_kind (),
7226 POISON_KIND_POPPED_STACK);
7227
7228 /* Verify that q still points to p, in spite of the region
7229 renumbering. */
7230 svalue *new_q_sval = model.get_svalue (model.get_rvalue (q, &ctxt));
7231 ASSERT_EQ (new_q_sval->get_kind (), SK_REGION);
7232 ASSERT_EQ (new_q_sval->dyn_cast_region_svalue ()->get_pointee (),
7233 model.get_lvalue (p, &ctxt));
7234
7235 /* Verify that top of stack has been updated. */
7236 ASSERT_EQ (model.get_current_frame_id (), parent_frame_rid);
7237
7238 /* Verify locals in parent frame. */
7239 /* Verify "a" still has its value. */
7240 svalue *new_a_sval = model.get_svalue (model.get_rvalue (a, &ctxt));
7241 ASSERT_EQ (new_a_sval->get_kind (), SK_CONSTANT);
7242 ASSERT_EQ (new_a_sval->dyn_cast_constant_svalue ()->get_constant (),
7243 int_42);
7244 /* Verify "b" still has its constraint. */
7245 ASSERT_EQ (model.eval_condition (b, LT_EXPR, int_10, &ctxt),
7246 tristate (tristate::TS_TRUE));
7247}
7248
7249/* Verify that get_representative_path_var works as expected, that
7250 we can map from region ids to parms and back within a recursive call
7251 stack. */
7252
7253static void
7254test_get_representative_path_var ()
7255{
7256 auto_vec <tree> param_types;
7257 tree fndecl = make_fndecl (integer_type_node,
7258 "factorial",
7259 param_types);
7260 allocate_struct_function (fndecl, true);
7261
7262 /* Parm "n". */
7263 tree n = build_decl (UNKNOWN_LOCATION, PARM_DECL,
7264 get_identifier ("n"),
7265 integer_type_node);
7266
7267 region_model model;
7268
7269 /* Push 5 stack frames for "factorial", each with a param */
7270 auto_vec<region_id> parm_rids;
7271 auto_vec<svalue_id> parm_sids;
7272 for (int depth = 0; depth < 5; depth++)
7273 {
7274 region_id frame_rid
7275 = model.push_frame (DECL_STRUCT_FUNCTION (fndecl), NULL, NULL);
7276 region_id rid_n = model.get_lvalue (path_var (n, depth), NULL);
7277 parm_rids.safe_push (rid_n);
7278
7279 ASSERT_EQ (model.get_region (rid_n)->get_parent (), frame_rid);
7280
7281 svalue_id sid_n
7282 = model.set_to_new_unknown_value (rid_n, integer_type_node, NULL);
7283 parm_sids.safe_push (sid_n);
7284 }
7285
7286 /* Verify that we can recognize that the regions are the parms,
7287 at every depth. */
7288 for (int depth = 0; depth < 5; depth++)
7289 {
7290 ASSERT_EQ (model.get_representative_path_var (parm_rids[depth]),
7291 path_var (n, depth));
7292 /* ...and that we can lookup lvalues for locals for all frames,
7293 not just the top. */
7294 ASSERT_EQ (model.get_lvalue (path_var (n, depth), NULL),
7295 parm_rids[depth]);
7296 /* ...and that we can locate the svalues. */
7297 auto_vec<path_var> pvs;
7298 model.get_path_vars_for_svalue (parm_sids[depth], &pvs);
7299 ASSERT_EQ (pvs.length (), 1);
7300 ASSERT_EQ (pvs[0], path_var (n, depth));
7301 }
7302}
7303
7304/* Verify that the core regions within a region_model are in a consistent
7305 order after canonicalization. */
7306
7307static void
7308test_canonicalization_1 ()
7309{
7310 region_model model0;
7311 model0.get_root_region ()->ensure_stack_region (&model0);
7312 model0.get_root_region ()->ensure_globals_region (&model0);
7313
7314 region_model model1;
7315 model1.get_root_region ()->ensure_globals_region (&model1);
7316 model1.get_root_region ()->ensure_stack_region (&model1);
7317
7318 model0.canonicalize (NULL);
7319 model1.canonicalize (NULL);
7320 ASSERT_EQ (model0, model1);
7321}
7322
7323/* Verify that region models for
7324 x = 42; y = 113;
7325 and
7326 y = 113; x = 42;
7327 are equal after canonicalization. */
7328
7329static void
7330test_canonicalization_2 ()
7331{
7332 tree int_42 = build_int_cst (integer_type_node, 42);
7333 tree int_113 = build_int_cst (integer_type_node, 113);
7334 tree x = build_global_decl ("x", integer_type_node);
7335 tree y = build_global_decl ("y", integer_type_node);
7336
7337 region_model model0;
7338 model0.set_value (model0.get_lvalue (x, NULL),
7339 model0.get_rvalue (int_42, NULL),
7340 NULL);
7341 model0.set_value (model0.get_lvalue (y, NULL),
7342 model0.get_rvalue (int_113, NULL),
7343 NULL);
7344
7345 region_model model1;
7346 model1.set_value (model1.get_lvalue (y, NULL),
7347 model1.get_rvalue (int_113, NULL),
7348 NULL);
7349 model1.set_value (model1.get_lvalue (x, NULL),
7350 model1.get_rvalue (int_42, NULL),
7351 NULL);
7352
7353 model0.canonicalize (NULL);
7354 model1.canonicalize (NULL);
7355 ASSERT_EQ (model0, model1);
7356}
7357
7358/* Verify that constraints for
7359 x > 3 && y > 42
7360 and
7361 y > 42 && x > 3
7362 are equal after canonicalization. */
7363
7364static void
7365test_canonicalization_3 ()
7366{
7367 tree int_3 = build_int_cst (integer_type_node, 3);
7368 tree int_42 = build_int_cst (integer_type_node, 42);
7369 tree x = build_global_decl ("x", integer_type_node);
7370 tree y = build_global_decl ("y", integer_type_node);
7371
7372 region_model model0;
7373 model0.add_constraint (x, GT_EXPR, int_3, NULL);
7374 model0.add_constraint (y, GT_EXPR, int_42, NULL);
7375
7376 region_model model1;
7377 model1.add_constraint (y, GT_EXPR, int_42, NULL);
7378 model1.add_constraint (x, GT_EXPR, int_3, NULL);
7379
7380 model0.canonicalize (NULL);
7381 model1.canonicalize (NULL);
7382 ASSERT_EQ (model0, model1);
7383}
7384
7385/* Assert that if we have two region_model instances
7386 with values VAL_A and VAL_B for EXPR that they are
7387 mergable. Write the merged model to *OUT_MERGED_MODEL,
7388 and the merged svalue ptr to *OUT_MERGED_SVALUE.
7389 If VAL_A or VAL_B are NULL_TREE, don't populate EXPR
7390 for that region_model. */
7391
7392static void
7393assert_region_models_merge (tree expr, tree val_a, tree val_b,
7394 region_model *out_merged_model,
7395 svalue **out_merged_svalue)
7396{
7397 test_region_model_context ctxt;
7398 region_model model0;
7399 region_model model1;
7400 if (val_a)
7401 model0.set_value (model0.get_lvalue (expr, &ctxt),
7402 model0.get_rvalue (val_a, &ctxt),
7403 &ctxt);
7404 if (val_b)
7405 model1.set_value (model1.get_lvalue (expr, &ctxt),
7406 model1.get_rvalue (val_b, &ctxt),
7407 &ctxt);
7408
7409 /* They should be mergeable. */
7410 ASSERT_TRUE (model0.can_merge_with_p (model1, out_merged_model));
7411
7412 svalue_id merged_svalue_sid = out_merged_model->get_rvalue (expr, &ctxt);
7413 *out_merged_svalue = out_merged_model->get_svalue (merged_svalue_sid);
7414}
7415
7416/* Verify that we can merge region_model instances. */
7417
7418static void
7419test_state_merging ()
7420{
7421 tree int_42 = build_int_cst (integer_type_node, 42);
7422 tree int_113 = build_int_cst (integer_type_node, 113);
7423 tree x = build_global_decl ("x", integer_type_node);
7424 tree y = build_global_decl ("y", integer_type_node);
7425 tree z = build_global_decl ("z", integer_type_node);
7426 tree p = build_global_decl ("p", ptr_type_node);
7427
7428 tree addr_of_y = build1 (ADDR_EXPR, ptr_type_node, y);
7429 tree addr_of_z = build1 (ADDR_EXPR, ptr_type_node, z);
7430
7431 auto_vec <tree> param_types;
7432 tree test_fndecl = make_fndecl (integer_type_node, "test_fn", param_types);
7433 allocate_struct_function (test_fndecl, true);
7434
7435 /* Param "a". */
7436 tree a = build_decl (UNKNOWN_LOCATION, PARM_DECL,
7437 get_identifier ("a"),
7438 integer_type_node);
7439 tree addr_of_a = build1 (ADDR_EXPR, ptr_type_node, a);
7440
7441 {
7442 region_model model0;
7443 region_model model1;
7444 region_model merged;
7445 /* Verify empty models can be merged. */
7446 ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
7447 ASSERT_EQ (model0, merged);
7448 }
7449
7450 /* Verify that we can merge two contradictory constraints on the
7451 value for a global. */
7452 /* TODO: verify that the merged model doesn't have a value for
7453 the global */
7454 {
7455 region_model model0;
7456 region_model model1;
7457 region_model merged;
7458 test_region_model_context ctxt;
7459 model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
7460 model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
7461 ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
7462 ASSERT_NE (model0, merged);
7463 ASSERT_NE (model1, merged);
7464 }
7465
7466 /* Verify handling of a PARM_DECL. */
7467 {
7468 test_region_model_context ctxt;
7469 region_model model0;
7470 region_model model1;
7471 ASSERT_EQ (model0.get_stack_depth (), 0);
7472 model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
7473 ASSERT_EQ (model0.get_stack_depth (), 1);
7474 ASSERT_EQ (model0.get_function_at_depth (0),
7475 DECL_STRUCT_FUNCTION (test_fndecl));
7476 model1.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
7477
7478 svalue_id sid_a
7479 = model0.set_to_new_unknown_value (model0.get_lvalue (a, &ctxt),
7480 integer_type_node, &ctxt);
7481 model1.set_to_new_unknown_value (model1.get_lvalue (a, &ctxt),
7482 integer_type_node, &ctxt);
7483 ASSERT_EQ (model0, model1);
7484
7485 /* Check that get_value_by_name works for locals. */
7486 ASSERT_EQ (model0.get_value_by_name ("a"), sid_a);
7487
7488 /* They should be mergeable, and the result should be the same. */
7489 region_model merged;
7490 ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
7491 ASSERT_EQ (model0, merged);
7492 /* In particular, there should be an unknown value for "a". */
7493 svalue *merged_a_sval = merged.get_svalue (merged.get_rvalue (a, &ctxt));
7494 ASSERT_EQ (merged_a_sval->get_kind (), SK_UNKNOWN);
7495 }
7496
7497 /* Verify handling of a global. */
7498 {
7499 test_region_model_context ctxt;
7500 region_model model0;
7501 region_model model1;
7502 svalue_id sid_x
7503 = model0.set_to_new_unknown_value (model0.get_lvalue (x, &ctxt),
7504 integer_type_node, &ctxt);
7505 model1.set_to_new_unknown_value (model1.get_lvalue (x, &ctxt),
7506 integer_type_node, &ctxt);
7507 ASSERT_EQ (model0, model1);
7508
7509 /* Check that get_value_by_name works for globals. */
7510 ASSERT_EQ (model0.get_value_by_name ("x"), sid_x);
7511
7512 /* They should be mergeable, and the result should be the same. */
7513 region_model merged;
7514 ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
7515 ASSERT_EQ (model0, merged);
7516 /* In particular, there should be an unknown value for "x". */
7517 svalue *merged_x_sval = merged.get_svalue (merged.get_rvalue (x, &ctxt));
7518 ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
7519 }
7520
7521 /* Use global-handling to verify various combinations of values. */
7522
7523 /* Two equal constant values. */
7524 {
7525 region_model merged;
7526 svalue *merged_x_sval;
7527 assert_region_models_merge (x, int_42, int_42, &merged, &merged_x_sval);
7528
7529 /* In particular, there should be a constant value for "x". */
7530 ASSERT_EQ (merged_x_sval->get_kind (), SK_CONSTANT);
7531 ASSERT_EQ (merged_x_sval->dyn_cast_constant_svalue ()->get_constant (),
7532 int_42);
7533 }
7534
7535 /* Two non-equal constant values. */
7536 {
7537 region_model merged;
7538 svalue *merged_x_sval;
7539 assert_region_models_merge (x, int_42, int_113, &merged, &merged_x_sval);
7540
7541 /* In particular, there should be an unknown value for "x". */
7542 ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
7543 }
7544
7545 /* Uninit and constant. */
7546 {
7547 region_model merged;
7548 svalue *merged_x_sval;
7549 assert_region_models_merge (x, NULL_TREE, int_113, &merged, &merged_x_sval);
7550
7551 /* In particular, there should be an unknown value for "x". */
7552 ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
7553 }
7554
7555 /* Constant and uninit. */
7556 {
7557 region_model merged;
7558 svalue *merged_x_sval;
7559 assert_region_models_merge (x, int_42, NULL_TREE, &merged, &merged_x_sval);
7560
7561 /* In particular, there should be an unknown value for "x". */
7562 ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
7563 }
7564
7565 /* Unknown and constant. */
7566 // TODO
7567
7568 /* Pointers: NULL and NULL. */
7569 // TODO
7570
7571 /* Pointers: NULL and non-NULL. */
7572 // TODO
7573
7574 /* Pointers: non-NULL and non-NULL: ptr to a local. */
7575 {
7576 region_model model0;
7577 model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
7578 model0.set_to_new_unknown_value (model0.get_lvalue (a, NULL),
7579 integer_type_node, NULL);
7580 model0.set_value (model0.get_lvalue (p, NULL),
7581 model0.get_rvalue (addr_of_a, NULL), NULL);
7582
7583 region_model model1 (model0);
7584 ASSERT_EQ (model0, model1);
7585
7586 /* They should be mergeable, and the result should be the same. */
7587 region_model merged;
7588 ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
7589 ASSERT_EQ (model0, merged);
7590 }
7591
7592 /* Pointers: non-NULL and non-NULL: ptr to a global. */
7593 {
7594 region_model merged;
7595 /* p == &y in both input models. */
7596 svalue *merged_p_sval;
7597 assert_region_models_merge (p, addr_of_y, addr_of_y, &merged,
7598 &merged_p_sval);
7599
7600 /* We should get p == &y in the merged model. */
7601 ASSERT_EQ (merged_p_sval->get_kind (), SK_REGION);
7602 region_svalue *merged_p_ptr = merged_p_sval->dyn_cast_region_svalue ();
7603 region_id merged_p_star_rid = merged_p_ptr->get_pointee ();
7604 ASSERT_EQ (merged_p_star_rid, merged.get_lvalue (y, NULL));
7605 }
7606
7607 /* Pointers: non-NULL ptrs to different globals: should be unknown. */
7608 {
7609 region_model merged;
7610 /* x == &y vs x == &z in the input models. */
7611 svalue *merged_x_sval;
7612 assert_region_models_merge (x, addr_of_y, addr_of_z, &merged,
7613 &merged_x_sval);
7614
7615 /* We should get x == unknown in the merged model. */
7616 ASSERT_EQ (merged_x_sval->get_kind (), SK_UNKNOWN);
7617 }
7618
7619 /* Pointers: non-NULL and non-NULL: ptr to a heap region. */
7620 {
7621 test_region_model_context ctxt;
7622 region_model model0;
7623 region_id new_rid = model0.add_new_malloc_region ();
7624 svalue_id ptr_sid
7625 = model0.get_or_create_ptr_svalue (ptr_type_node, new_rid);
7626 model0.set_value (model0.get_lvalue (p, &ctxt),
7627 ptr_sid, &ctxt);
7628 model0.canonicalize (&ctxt);
7629
7630 region_model model1 (model0);
7631
7632 ASSERT_EQ (model0, model1);
7633
7634 region_model merged;
7635 ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
7636
7637 merged.canonicalize (&ctxt);
7638
7639 /* The merged model ought to be identical (after canonicalization,
7640 at least). */
7641 ASSERT_EQ (model0, merged);
7642 }
7643
7644 /* Two regions sharing the same unknown svalue should continue sharing
7645 an unknown svalue after self-merger. */
7646 {
7647 test_region_model_context ctxt;
7648 region_model model0;
7649 svalue_id sid
7650 = model0.set_to_new_unknown_value (model0.get_lvalue (x, &ctxt),
7651 integer_type_node, &ctxt);
7652 model0.set_value (model0.get_lvalue (y, &ctxt), sid, &ctxt);
7653 region_model model1 (model0);
7654
7655 /* They should be mergeable, and the result should be the same. */
7656 region_model merged;
7657 ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
7658 ASSERT_EQ (model0, merged);
7659
7660 /* In particular, we should have x == y. */
7661 ASSERT_EQ (merged.eval_condition (x, EQ_EXPR, y, &ctxt),
7662 tristate (tristate::TS_TRUE));
7663 }
7664
7665#if 0
7666 {
7667 region_model model0;
7668 region_model model1;
7669 test_region_model_context ctxt;
7670 model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
7671 model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
7672 ASSERT_TRUE (model0.can_merge_with_p (model1));
7673 }
7674
7675 {
7676 region_model model0;
7677 region_model model1;
7678 test_region_model_context ctxt;
7679 model0.add_constraint (x, EQ_EXPR, int_42, &ctxt);
7680 model1.add_constraint (x, NE_EXPR, int_42, &ctxt);
7681 model1.add_constraint (x, EQ_EXPR, int_113, &ctxt);
7682 ASSERT_TRUE (model0.can_merge_with_p (model1));
7683 }
7684#endif
7685
7686 // TODO: what can't we merge? need at least one such test
7687
7688 /* TODO: various things
7689 - heap regions
7690 - value merging:
7691 - every combination, but in particular
7692 - pairs of regions
7693 */
7694
7695 /* Views. */
7696 {
7697 test_region_model_context ctxt;
7698 region_model model0;
7699
7700 region_id x_rid = model0.get_lvalue (x, &ctxt);
7701 region_id x_as_ptr = model0.get_or_create_view (x_rid, ptr_type_node);
7702 model0.set_value (x_as_ptr, model0.get_rvalue (addr_of_y, &ctxt), &ctxt);
7703
7704 region_model model1 (model0);
7705 ASSERT_EQ (model1, model0);
7706
7707 /* They should be mergeable, and the result should be the same. */
7708 region_model merged;
7709 ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
7710 }
7711}
7712
7713/* Verify that constraints are correctly merged when merging region_model
7714 instances. */
7715
7716static void
7717test_constraint_merging ()
7718{
7719 tree int_0 = build_int_cst (integer_type_node, 0);
7720 tree int_5 = build_int_cst (integer_type_node, 5);
7721 tree x = build_global_decl ("x", integer_type_node);
7722 tree y = build_global_decl ("y", integer_type_node);
7723 tree z = build_global_decl ("z", integer_type_node);
7724 tree n = build_global_decl ("n", integer_type_node);
7725
7726 test_region_model_context ctxt;
7727
7728 /* model0: 0 <= (x == y) < n. */
7729 region_model model0;
7730 model0.set_to_new_unknown_value (model0.get_lvalue (x, &ctxt),
7731 integer_type_node, &ctxt);
7732 model0.add_constraint (x, EQ_EXPR, y, &ctxt);
7733 model0.add_constraint (x, GE_EXPR, int_0, NULL);
7734 model0.add_constraint (x, LT_EXPR, n, NULL);
7735
7736 /* model1: z != 5 && (0 <= x < n). */
7737 region_model model1;
7738 model1.set_to_new_unknown_value (model1.get_lvalue (x, &ctxt),
7739 integer_type_node, &ctxt);
7740 model1.add_constraint (z, NE_EXPR, int_5, NULL);
7741 model1.add_constraint (x, GE_EXPR, int_0, NULL);
7742 model1.add_constraint (x, LT_EXPR, n, NULL);
7743
7744 /* They should be mergeable; the merged constraints should
7745 be: (0 <= x < n). */
7746 region_model merged;
7747 ASSERT_TRUE (model0.can_merge_with_p (model1, &merged));
7748
7749 ASSERT_EQ (merged.eval_condition (x, GE_EXPR, int_0, &ctxt),
7750 tristate (tristate::TS_TRUE));
7751 ASSERT_EQ (merged.eval_condition (x, LT_EXPR, n, &ctxt),
7752 tristate (tristate::TS_TRUE));
7753
7754 ASSERT_EQ (merged.eval_condition (z, NE_EXPR, int_5, &ctxt),
7755 tristate (tristate::TS_UNKNOWN));
7756 ASSERT_EQ (merged.eval_condition (x, LT_EXPR, y, &ctxt),
7757 tristate (tristate::TS_UNKNOWN));
7758}
7759
7760/* Run all of the selftests within this file. */
7761
7762void
7763analyzer_region_model_cc_tests ()
7764{
7765 test_dump ();
7766 test_unique_constants ();
7767 test_svalue_equality ();
7768 test_region_equality ();
7769 test_purging_by_criteria ();
7770 test_purge_unused_svalues ();
7771 test_assignment ();
7772 test_stack_frames ();
7773 test_get_representative_path_var ();
7774 test_canonicalization_1 ();
7775 test_canonicalization_2 ();
7776 test_canonicalization_3 ();
7777 test_state_merging ();
7778 test_constraint_merging ();
7779}
7780
7781} // namespace selftest
7782
7783#endif /* CHECKING_P */
7784
7785#endif /* #if ENABLE_ANALYZER */