xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/analyzer/exploded-graph.h (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1 /* Classes for managing a directed graph of <point, state> pairs.
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 #ifndef GCC_ANALYZER_EXPLODED_GRAPH_H
22 #define GCC_ANALYZER_EXPLODED_GRAPH_H
23 
24 namespace ana {
25 
26 /* Concrete implementation of region_model_context, wiring it up to the
27    rest of the analysis engine.  */
28 
29 class impl_region_model_context : public region_model_context
30 {
31  public:
32   impl_region_model_context (exploded_graph &eg,
33 			     const exploded_node *enode_for_diag,
34 
35 			     /* TODO: should we be getting the ECs from the
36 				old state, rather than the new?  */
37 			     const program_state *old_state,
38 			     program_state *new_state,
39 			     state_change *change,
40 
41 			     const gimple *stmt,
42 			     stmt_finder *stmt_finder = NULL);
43 
44   impl_region_model_context (program_state *state,
45 			     state_change *change,
46 			     const extrinsic_state &ext_state,
47 			     logger *logger = NULL);
48 
49   void warn (pending_diagnostic *d) FINAL OVERRIDE;
50 
51   void remap_svalue_ids (const svalue_id_map &map) FINAL OVERRIDE;
52 
53   int on_svalue_purge (svalue_id first_unused_sid,
54 		       const svalue_id_map &map) FINAL OVERRIDE;
55 
get_logger()56   logger *get_logger () FINAL OVERRIDE
57   {
58     return m_logger.get_logger ();
59   }
60 
61   void on_state_leak (const state_machine &sm,
62 		      int sm_idx,
63 		      svalue_id sid,
64 		      svalue_id first_unused_sid,
65 		      const svalue_id_map &map,
66 		      state_machine::state_t state);
67 
68   void on_inherited_svalue (svalue_id parent_sid,
69 			    svalue_id child_sid) FINAL OVERRIDE;
70 
71   void on_cast (svalue_id src_sid,
72 		svalue_id dst_sid) FINAL OVERRIDE;
73 
74   void on_condition (tree lhs, enum tree_code op, tree rhs) FINAL OVERRIDE;
75 
76   void on_unknown_change (svalue_id sid ATTRIBUTE_UNUSED) FINAL OVERRIDE;
77 
78   void on_phi (const gphi *phi, tree rhs) FINAL OVERRIDE;
79 
80   void on_unexpected_tree_code (tree t,
81 				const dump_location_t &loc) FINAL OVERRIDE;
82 
83   exploded_graph *m_eg;
84   log_user m_logger;
85   const exploded_node *m_enode_for_diag;
86   const program_state *m_old_state;
87   program_state *m_new_state;
88   state_change *m_change;
89   const gimple *m_stmt;
90   stmt_finder *m_stmt_finder;
91   const extrinsic_state &m_ext_state;
92 };
93 
94 /* A <program_point, program_state> pair, used internally by
95    exploded_node as its immutable data, and as a key for identifying
96    exploded_nodes we've already seen in the graph.  */
97 
98 class point_and_state
99 {
100 public:
point_and_state(const program_point & point,const program_state & state)101   point_and_state (const program_point &point,
102 		   const program_state &state)
103   : m_point (point),
104     m_state (state),
105     m_hash (m_point.hash () ^ m_state.hash ())
106   {
107     /* We shouldn't be building point_and_states and thus exploded_nodes
108        for states that aren't valid.  */
109     gcc_assert (state.m_valid);
110   }
111 
hash()112   hashval_t hash () const
113   {
114     return m_hash;
115   }
116   bool operator== (const point_and_state &other) const
117   {
118     return m_point == other.m_point && m_state == other.m_state;
119   }
120 
get_point()121   const program_point &get_point () const { return m_point; }
get_state()122   const program_state &get_state () const { return m_state; }
123 
set_state(const program_state & state)124   void set_state (const program_state &state)
125   {
126     m_state = state;
127     m_hash = m_point.hash () ^ m_state.hash ();
128   }
129 
130   void validate (const extrinsic_state &ext_state) const;
131 
132 private:
133   program_point m_point;
134   program_state m_state;
135   hashval_t m_hash;
136 };
137 
138 /* A traits class for exploded graphs and their nodes and edges.  */
139 
140 struct eg_traits
141 {
142   typedef exploded_node node_t;
143   typedef exploded_edge edge_t;
144   typedef exploded_graph graph_t;
145   struct dump_args_t
146   {
dump_args_teg_traits::dump_args_t147     dump_args_t (const exploded_graph &eg) : m_eg (eg) {}
148     const exploded_graph &m_eg;
149   };
150   typedef exploded_cluster cluster_t;
151 };
152 
153 /* An exploded_node is a unique, immutable <point, state> pair within the
154    exploded_graph.
155    Each exploded_node has a unique index within the graph
156    (for ease of debugging).  */
157 
158 class exploded_node : public dnode<eg_traits>
159 {
160  public:
161   /* Has this enode had exploded_graph::process_node called on it?
162      This allows us to distinguish enodes that were merged during
163      worklist-handling, and thus never had process_node called on them
164      (in favor of processing the merged node).  */
165   enum status
166   {
167     /* Node is in the worklist.  */
168     STATUS_WORKLIST,
169 
170     /* Node has had exploded_graph::process_node called on it.  */
171     STATUS_PROCESSED,
172 
173     /* Node was left unprocessed due to merger; it won't have had
174        exploded_graph::process_node called on it.  */
175     STATUS_MERGER
176   };
177 
178   exploded_node (const point_and_state &ps, int index);
179 
hash()180   hashval_t hash () const { return m_ps.hash (); }
181 
182   const char * get_dot_fillcolor () const;
183   void dump_dot (graphviz_out *gv, const dump_args_t &args)
184     const FINAL OVERRIDE;
185   void dump_dot_id (pretty_printer *pp) const;
186 
187   void dump_to_pp (pretty_printer *pp, const extrinsic_state &ext_state) const;
188   void dump (FILE *fp, const extrinsic_state &ext_state) const;
189   void dump (const extrinsic_state &ext_state) const;
190 
191   /* The result of on_stmt.  */
192   struct on_stmt_flags
193   {
on_stmt_flagson_stmt_flags194     on_stmt_flags (bool sm_changes)
195     : m_sm_changes (sm_changes),
196       m_terminate_path (false)
197     {}
198 
terminate_pathon_stmt_flags199     static on_stmt_flags terminate_path ()
200     {
201       return on_stmt_flags (true, true);
202     }
203 
state_changeon_stmt_flags204     static on_stmt_flags state_change (bool any_sm_changes)
205     {
206       return on_stmt_flags (any_sm_changes, false);
207     }
208 
209     /* Did any sm-changes occur handling the stmt.  */
210     bool m_sm_changes : 1;
211 
212     /* Should we stop analyzing this path (on_stmt may have already
213        added nodes/edges, e.g. when handling longjmp).  */
214     bool m_terminate_path : 1;
215 
216   private:
on_stmt_flagson_stmt_flags217     on_stmt_flags (bool sm_changes,
218 		   bool terminate_path)
219     : m_sm_changes (sm_changes),
220       m_terminate_path (terminate_path)
221     {}
222   };
223 
224   on_stmt_flags on_stmt (exploded_graph &eg,
225 			 const supernode *snode,
226 			 const gimple *stmt,
227 			 program_state *state,
228 			 state_change *change) const;
229   bool on_edge (exploded_graph &eg,
230 		const superedge *succ,
231 		program_point *next_point,
232 		program_state *next_state,
233 		state_change *change) const;
234   void on_longjmp (exploded_graph &eg,
235 		   const gcall *call,
236 		   program_state *new_state,
237 		   region_model_context *ctxt) const;
238 
239   void detect_leaks (exploded_graph &eg) const;
240 
get_point()241   const program_point &get_point () const { return m_ps.get_point (); }
get_supernode()242   const supernode *get_supernode () const
243   {
244     return get_point ().get_supernode ();
245   }
get_function()246   function *get_function () const
247   {
248     return get_point ().get_function ();
249   }
get_stack_depth()250   int get_stack_depth () const
251   {
252     return get_point ().get_stack_depth ();
253   }
get_stmt()254   const gimple *get_stmt () const { return get_point ().get_stmt (); }
255 
get_state()256   const program_state &get_state () const { return m_ps.get_state (); }
257 
get_ps_key()258   const point_and_state *get_ps_key () const { return &m_ps; }
get_point_key()259   const program_point *get_point_key () const { return &m_ps.get_point (); }
260 
261   void dump_succs_and_preds (FILE *outf) const;
262 
get_status()263   enum status get_status () const { return m_status; }
set_status(enum status status)264   void set_status (enum status status)
265   {
266     gcc_assert (m_status == STATUS_WORKLIST);
267     m_status = status;
268   }
269 
270 private:
271   DISABLE_COPY_AND_ASSIGN (exploded_node);
272 
273   /* The <program_point, program_state> pair.  This is const, as it
274      is immutable once the exploded_node has been created.  */
275   const point_and_state m_ps;
276 
277   enum status m_status;
278 
279 public:
280   /* The index of this exploded_node.  */
281   const int m_index;
282 };
283 
284 /* An edge within the exploded graph.
285    Some exploded_edges have an underlying superedge; others don't.  */
286 
287 class exploded_edge : public dedge<eg_traits>
288 {
289  public:
290   /* Abstract base class for associating custom data with an
291      exploded_edge, for handling non-standard edges such as
292      rewinding from a longjmp, signal handlers, etc.  */
293   class custom_info_t
294   {
295   public:
~custom_info_t()296     virtual ~custom_info_t () {}
297 
298     /* Hook for making .dot label more readable .  */
299     virtual void print (pretty_printer *pp) = 0;
300 
301     /* Hook for updating MODEL within exploded_path::feasible_p.  */
302     virtual void update_model (region_model *model,
303 			       const exploded_edge &eedge) = 0;
304 
305     virtual void add_events_to_path (checker_path *emission_path,
306 				     const exploded_edge &eedge) = 0;
307   };
308 
309   exploded_edge (exploded_node *src, exploded_node *dest,
310 		 const extrinsic_state &ext_state,
311 		 const superedge *sedge,
312 		 const state_change &change,
313 		 custom_info_t *custom_info);
314   ~exploded_edge ();
315   void dump_dot (graphviz_out *gv, const dump_args_t &args)
316     const FINAL OVERRIDE;
317 
318   //private:
319   const superedge *const m_sedge;
320 
321   const state_change m_change;
322 
323   /* NULL for most edges; will be non-NULL for special cases
324      such as an unwind from a longjmp to a setjmp, or when
325      a signal is delivered to a signal-handler.
326 
327      Owned by this class.  */
328   custom_info_t *m_custom_info;
329 
330 private:
331   DISABLE_COPY_AND_ASSIGN (exploded_edge);
332 };
333 
334 /* Extra data for an exploded_edge that represents a rewind from a
335    longjmp to a setjmp (or from a siglongjmp to a sigsetjmp).  */
336 
337 class rewind_info_t : public exploded_edge::custom_info_t
338 {
339 public:
rewind_info_t(const setjmp_record & setjmp_record,const gcall * longjmp_call)340   rewind_info_t (const setjmp_record &setjmp_record,
341 		 const gcall *longjmp_call)
342   : m_setjmp_record (setjmp_record),
343     m_longjmp_call (longjmp_call)
344   {}
345 
print(pretty_printer * pp)346   void print (pretty_printer *pp) FINAL OVERRIDE
347   {
348     pp_string (pp, "rewind");
349   }
350 
351   void update_model (region_model *model,
352 		     const exploded_edge &eedge) FINAL OVERRIDE;
353 
354   void add_events_to_path (checker_path *emission_path,
355 			   const exploded_edge &eedge) FINAL OVERRIDE;
356 
get_setjmp_point()357   const program_point &get_setjmp_point () const
358   {
359     const program_point &origin_point = get_enode_origin ()->get_point ();
360 
361     /* "origin_point" ought to be before the call to "setjmp".  */
362     gcc_assert (origin_point.get_kind () == PK_BEFORE_STMT);
363 
364     /* TODO: assert that it's the final stmt in its supernode.  */
365 
366     return origin_point;
367   }
368 
get_setjmp_call()369   const gcall *get_setjmp_call () const
370   {
371     return m_setjmp_record.m_setjmp_call;
372   }
373 
get_longjmp_call()374   const gcall *get_longjmp_call () const
375   {
376     return m_longjmp_call;
377   }
378 
get_enode_origin()379   const exploded_node *get_enode_origin () const
380   {
381     return m_setjmp_record.m_enode;
382   }
383 
384 private:
385   setjmp_record m_setjmp_record;
386   const gcall *m_longjmp_call;
387 };
388 
389 /* Statistics about aspects of an exploded_graph.  */
390 
391 struct stats
392 {
393   stats (int num_supernodes);
394   void log (logger *logger) const;
395   void dump (FILE *out) const;
396 
397   int get_total_enodes () const;
398 
399   int m_num_nodes[NUM_POINT_KINDS];
400   int m_node_reuse_count;
401   int m_node_reuse_after_merge_count;
402   int m_num_supernodes;
403 };
404 
405 /* Traits class for ensuring uniqueness of point_and_state data within
406    an exploded_graph.  */
407 
408 struct eg_hash_map_traits
409 {
410   typedef const point_and_state *key_type;
411   typedef exploded_node *value_type;
412   typedef exploded_node *compare_type;
413 
hasheg_hash_map_traits414   static inline hashval_t hash (const key_type &k)
415   {
416     gcc_assert (k != NULL);
417     gcc_assert (k != reinterpret_cast<key_type> (1));
418     return k->hash ();
419   }
equal_keyseg_hash_map_traits420   static inline bool equal_keys (const key_type &k1, const key_type &k2)
421   {
422     gcc_assert (k1 != NULL);
423     gcc_assert (k2 != NULL);
424     gcc_assert (k1 != reinterpret_cast<key_type> (1));
425     gcc_assert (k2 != reinterpret_cast<key_type> (1));
426     if (k1 && k2)
427       return *k1 == *k2;
428     else
429       /* Otherwise they must both be non-NULL.  */
430       return k1 == k2;
431   }
432   template <typename T>
removeeg_hash_map_traits433   static inline void remove (T &)
434   {
435     /* empty; the nodes are handled elsewhere.  */
436   }
437   template <typename T>
mark_deletedeg_hash_map_traits438   static inline void mark_deleted (T &entry)
439   {
440     entry.m_key = reinterpret_cast<key_type> (1);
441   }
442   template <typename T>
mark_emptyeg_hash_map_traits443   static inline void mark_empty (T &entry)
444   {
445     entry.m_key = NULL;
446   }
447   template <typename T>
is_deletedeg_hash_map_traits448   static inline bool is_deleted (const T &entry)
449   {
450     return entry.m_key == reinterpret_cast<key_type> (1);
451   }
452   template <typename T>
is_emptyeg_hash_map_traits453   static inline bool is_empty (const T &entry)
454   {
455     return entry.m_key == NULL;
456   }
457   static const bool empty_zero_p = false;
458 };
459 
460 /* Per-program_point data for an exploded_graph.  */
461 
462 struct per_program_point_data
463 {
per_program_point_dataper_program_point_data464   per_program_point_data (const program_point &key)
465   : m_key (key), m_excess_enodes (0)
466   {}
467 
468   const program_point m_key;
469   auto_vec<exploded_node *> m_enodes;
470   /* The number of attempts to create an enode for this point
471      after exceeding --param=analyzer-max-enodes-per-program-point.  */
472   int m_excess_enodes;
473 };
474 
475 /* Traits class for storing per-program_point data within
476    an exploded_graph.  */
477 
478 struct eg_point_hash_map_traits
479 {
480   typedef const program_point *key_type;
481   typedef per_program_point_data *value_type;
482   typedef per_program_point_data *compare_type;
483 
hasheg_point_hash_map_traits484   static inline hashval_t hash (const key_type &k)
485   {
486     gcc_assert (k != NULL);
487     gcc_assert (k != reinterpret_cast<key_type> (1));
488     return k->hash ();
489   }
equal_keyseg_point_hash_map_traits490   static inline bool equal_keys (const key_type &k1, const key_type &k2)
491   {
492     gcc_assert (k1 != NULL);
493     gcc_assert (k2 != NULL);
494     gcc_assert (k1 != reinterpret_cast<key_type> (1));
495     gcc_assert (k2 != reinterpret_cast<key_type> (1));
496     if (k1 && k2)
497       return *k1 == *k2;
498     else
499       /* Otherwise they must both be non-NULL.  */
500       return k1 == k2;
501   }
502   template <typename T>
removeeg_point_hash_map_traits503   static inline void remove (T &)
504   {
505     /* empty; the nodes are handled elsewhere.  */
506   }
507   template <typename T>
mark_deletedeg_point_hash_map_traits508   static inline void mark_deleted (T &entry)
509   {
510     entry.m_key = reinterpret_cast<key_type> (1);
511   }
512   template <typename T>
mark_emptyeg_point_hash_map_traits513   static inline void mark_empty (T &entry)
514   {
515     entry.m_key = NULL;
516   }
517   template <typename T>
is_deletedeg_point_hash_map_traits518   static inline bool is_deleted (const T &entry)
519   {
520     return entry.m_key == reinterpret_cast<key_type> (1);
521   }
522   template <typename T>
is_emptyeg_point_hash_map_traits523   static inline bool is_empty (const T &entry)
524   {
525     return entry.m_key == NULL;
526   }
527   static const bool empty_zero_p = false;
528 };
529 
530 /* Data about a particular call_string within an exploded_graph.  */
531 
532 struct per_call_string_data
533 {
per_call_string_dataper_call_string_data534   per_call_string_data (const call_string &key, int num_supernodes)
535   : m_key (key), m_stats (num_supernodes)
536   {}
537 
538   const call_string m_key;
539   stats m_stats;
540 };
541 
542 /* Traits class for storing per-call_string data within
543    an exploded_graph.  */
544 
545 struct eg_call_string_hash_map_traits
546 {
547   typedef const call_string *key_type;
548   typedef per_call_string_data *value_type;
549   typedef per_call_string_data *compare_type;
550 
hasheg_call_string_hash_map_traits551   static inline hashval_t hash (const key_type &k)
552   {
553     gcc_assert (k != NULL);
554     gcc_assert (k != reinterpret_cast<key_type> (1));
555     return k->hash ();
556   }
equal_keyseg_call_string_hash_map_traits557   static inline bool equal_keys (const key_type &k1, const key_type &k2)
558   {
559     gcc_assert (k1 != NULL);
560     gcc_assert (k2 != NULL);
561     gcc_assert (k1 != reinterpret_cast<key_type> (1));
562     gcc_assert (k2 != reinterpret_cast<key_type> (1));
563     if (k1 && k2)
564       return *k1 == *k2;
565     else
566       /* Otherwise they must both be non-NULL.  */
567       return k1 == k2;
568   }
569   template <typename T>
removeeg_call_string_hash_map_traits570   static inline void remove (T &)
571   {
572     /* empty; the nodes are handled elsewhere.  */
573   }
574   template <typename T>
mark_deletedeg_call_string_hash_map_traits575   static inline void mark_deleted (T &entry)
576   {
577     entry.m_key = reinterpret_cast<key_type> (1);
578   }
579   template <typename T>
mark_emptyeg_call_string_hash_map_traits580   static inline void mark_empty (T &entry)
581   {
582     entry.m_key = NULL;
583   }
584   template <typename T>
is_deletedeg_call_string_hash_map_traits585   static inline bool is_deleted (const T &entry)
586   {
587     return entry.m_key == reinterpret_cast<key_type> (1);
588   }
589   template <typename T>
is_emptyeg_call_string_hash_map_traits590   static inline bool is_empty (const T &entry)
591   {
592     return entry.m_key == NULL;
593   }
594   static const bool empty_zero_p = false;
595 };
596 
597 /* Data about a particular function within an exploded_graph.  */
598 
599 struct per_function_data
600 {
per_function_dataper_function_data601   per_function_data () {}
602 
add_call_summaryper_function_data603   void add_call_summary (exploded_node *node)
604   {
605     m_summaries.safe_push (node);
606   }
607 
608   auto_vec<exploded_node *> m_summaries;
609 };
610 
611 
612 /* The strongly connected components of a supergraph.
613    In particular, this allows us to compute a partial ordering
614    of supernodes.  */
615 
616 class strongly_connected_components
617 {
618 public:
619   strongly_connected_components (const supergraph &sg, logger *logger);
620 
get_scc_id(int node_index)621   int get_scc_id (int node_index) const
622   {
623     return m_per_node[node_index].m_lowlink;
624   }
625 
626   void dump () const;
627 
628 private:
629   struct per_node_data
630   {
per_node_dataper_node_data631     per_node_data ()
632       : m_index (-1), m_lowlink (-1), m_on_stack (false)
633     {}
634 
635     int m_index;
636     int m_lowlink;
637     bool m_on_stack;
638   };
639 
640   void strong_connect (unsigned index);
641 
642   const supergraph &m_sg;
643   auto_vec<unsigned> m_stack;
644   auto_vec<per_node_data> m_per_node;
645 };
646 
647 /* The worklist of exploded_node instances that have been added to
648    an exploded_graph, but that haven't yet been processed to find
649    their successors (or warnings).
650 
651    The enodes are stored in a priority queue, ordered by a topological
652    sort of the SCCs in the supergraph, so that enodes for the same
653    program_point should appear at the front of the queue together.
654    This allows for state-merging at CFG join-points, so that
655    sufficiently-similar enodes can be merged into one.  */
656 
657 class worklist
658 {
659 public:
660   worklist (const exploded_graph &eg, const analysis_plan &plan);
661   unsigned length () const;
662   exploded_node *take_next ();
663   exploded_node *peek_next ();
664   void add_node (exploded_node *enode);
665 
666 private:
667   class key_t
668   {
669   public:
key_t(const worklist & w,exploded_node * enode)670     key_t (const worklist &w, exploded_node *enode)
671     : m_worklist (w), m_enode (enode)
672     {}
673 
674     bool operator< (const key_t &other) const
675     {
676       return cmp (*this, other) < 0;
677     }
678 
679     bool operator== (const key_t &other) const
680     {
681       return cmp (*this, other) == 0;
682     }
683 
684     bool operator> (const key_t &other) const
685     {
686       return !(*this == other || *this < other);
687     }
688 
689   private:
690     static int cmp (const key_t &ka, const key_t &kb);
691 
get_scc_id(const exploded_node * enode)692     int get_scc_id (const exploded_node *enode) const
693     {
694       const supernode *snode = enode->get_supernode ();
695       if (snode == NULL)
696 	return 0;
697       return m_worklist.m_scc.get_scc_id (snode->m_index);
698     }
699 
700     const worklist &m_worklist;
701     exploded_node *m_enode;
702   };
703 
704   /* The order is important here: m_scc needs to stick around
705      until after m_queue has finished being cleaned up (the dtor
706      calls the ordering fns).  */
707   strongly_connected_components m_scc;
708   const analysis_plan &m_plan;
709 
710   /* Priority queue, backed by a fibonacci_heap.  */
711   typedef fibonacci_heap<key_t, exploded_node> queue_t;
712   queue_t m_queue;
713 };
714 
715 /* An exploded_graph is a directed graph of unique <point, state> pairs.
716    It also has a worklist of nodes that are waiting for their successors
717    to be added to the graph.  */
718 
719 class exploded_graph : public digraph<eg_traits>
720 {
721 public:
722   typedef hash_map <const call_string *, per_call_string_data *,
723 		    eg_call_string_hash_map_traits> call_string_data_map_t;
724 
725   exploded_graph (const supergraph &sg, logger *logger,
726 		  const extrinsic_state &ext_state,
727 		  const state_purge_map *purge_map,
728 		  const analysis_plan &plan,
729 		  int verbosity);
730   ~exploded_graph ();
731 
get_logger()732   logger *get_logger () const { return m_logger.get_logger (); }
733 
get_supergraph()734   const supergraph &get_supergraph () const { return m_sg; }
get_ext_state()735   const extrinsic_state &get_ext_state () const { return m_ext_state; }
get_purge_map()736   const state_purge_map *get_purge_map () const { return m_purge_map; }
get_analysis_plan()737   const analysis_plan &get_analysis_plan () const { return m_plan; }
738 
get_origin()739   exploded_node *get_origin () const { return m_origin; }
740 
741   exploded_node *add_function_entry (function *fun);
742 
743   void build_initial_worklist ();
744   void process_worklist ();
745   void process_node (exploded_node *node);
746 
747   exploded_node *get_or_create_node (const program_point &point,
748 				     const program_state &state,
749 				     state_change *change);
750   exploded_edge *add_edge (exploded_node *src, exploded_node *dest,
751 			   const superedge *sedge,
752 			   const state_change &change,
753 			   exploded_edge::custom_info_t *custom = NULL);
754 
755   per_program_point_data *
756   get_or_create_per_program_point_data (const program_point &);
757 
758   per_call_string_data *
759   get_or_create_per_call_string_data (const call_string &);
760 
761   per_function_data *
762   get_or_create_per_function_data (function *);
763   per_function_data *get_per_function_data (function *) const;
764 
765   void save_diagnostic (const state_machine &sm,
766 			const exploded_node *enode,
767 			const supernode *node, const gimple *stmt,
768 			stmt_finder *finder,
769 			tree var, state_machine::state_t state,
770 			pending_diagnostic *d);
771 
get_diagnostic_manager()772   diagnostic_manager &get_diagnostic_manager ()
773   {
774     return m_diagnostic_manager;
775   }
get_diagnostic_manager()776   const diagnostic_manager &get_diagnostic_manager () const
777   {
778     return m_diagnostic_manager;
779   }
780 
get_global_stats()781   stats *get_global_stats () { return &m_global_stats; }
782   stats *get_or_create_function_stats (function *fn);
783   void log_stats () const;
784   void dump_stats (FILE *) const;
785   void dump_states_for_supernode (FILE *, const supernode *snode) const;
786   void dump_exploded_nodes () const;
787 
get_per_call_string_data()788   const call_string_data_map_t *get_per_call_string_data () const
789   { return &m_per_call_string_data; }
790 
791 private:
792   void print_bar_charts (pretty_printer *pp) const;
793 
794   DISABLE_COPY_AND_ASSIGN (exploded_graph);
795 
796   const supergraph &m_sg;
797 
798   log_user m_logger;
799 
800   /* Map from point/state to exploded node.
801      To avoid duplication we store point_and_state
802      *pointers* as keys, rather than point_and_state, using the
803      instance from within the exploded_node, with a custom hasher.  */
804   typedef hash_map <const point_and_state *, exploded_node *,
805 		    eg_hash_map_traits> map_t;
806   map_t m_point_and_state_to_node;
807 
808   /* Map from program_point to per-program_point data.  */
809   typedef hash_map <const program_point *, per_program_point_data *,
810 		    eg_point_hash_map_traits> point_map_t;
811   point_map_t m_per_point_data;
812 
813   worklist m_worklist;
814 
815   exploded_node *m_origin;
816 
817   const extrinsic_state &m_ext_state;
818 
819   const state_purge_map *const m_purge_map;
820 
821   const analysis_plan &m_plan;
822 
823   typedef hash_map<function *, per_function_data *> per_function_data_t;
824   per_function_data_t m_per_function_data;
825 
826   diagnostic_manager m_diagnostic_manager;
827 
828   /* Stats.  */
829   stats m_global_stats;
830   typedef ordered_hash_map<function *, stats *> function_stat_map_t;
831   function_stat_map_t m_per_function_stats;
832   stats m_functionless_stats;
833 
834   call_string_data_map_t m_per_call_string_data;
835 
836   auto_vec<int> m_PK_AFTER_SUPERNODE_per_snode;
837 };
838 
839 /* A path within an exploded_graph: a sequence of edges.  */
840 
841 class exploded_path
842 {
843 public:
exploded_path()844   exploded_path () : m_edges () {}
845   exploded_path (const exploded_path &other);
846   exploded_path & operator= (const exploded_path &other);
847 
length()848   unsigned length () const { return m_edges.length (); }
849 
850   bool find_stmt_backwards (const gimple *search_stmt,
851 			    int *out_idx) const;
852 
853   exploded_node *get_final_enode () const;
854 
855   void dump_to_pp (pretty_printer *pp) const;
856   void dump (FILE *fp) const;
857   void dump () const;
858 
859   bool feasible_p (logger *logger, feasibility_problem **out) const;
860 
861   auto_vec<const exploded_edge *> m_edges;
862 };
863 
864 /* A reason why a particular exploded_path is infeasible.  */
865 
866 class feasibility_problem
867 {
868 public:
feasibility_problem(unsigned eedge_idx,const region_model & model,const exploded_edge & eedge,const gimple * last_stmt)869   feasibility_problem (unsigned eedge_idx,
870 		       const region_model &model,
871 		       const exploded_edge &eedge,
872 		       const gimple *last_stmt)
873   : m_eedge_idx (eedge_idx), m_model (model), m_eedge (eedge),
874     m_last_stmt (last_stmt)
875   {}
876 
877   unsigned m_eedge_idx;
878   region_model m_model;
879   const exploded_edge &m_eedge;
880   const gimple *m_last_stmt;
881 };
882 
883 /* Finding the shortest exploded_path within an exploded_graph.  */
884 
885 typedef shortest_paths<eg_traits, exploded_path> shortest_exploded_paths;
886 
887 /* Abstract base class for use when passing NULL as the stmt for
888    a possible warning, allowing the choice of stmt to be deferred
889    until after we have an emission path (and know we're emitting a
890    warning).  */
891 
892 class stmt_finder
893 {
894 public:
~stmt_finder()895   virtual ~stmt_finder () {}
896   virtual stmt_finder *clone () const = 0;
897   virtual const gimple *find_stmt (const exploded_path &epath) = 0;
898 };
899 
900 // TODO: split the above up?
901 
902 } // namespace ana
903 
904 #endif /* GCC_ANALYZER_EXPLODED_GRAPH_H */
905