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