analyzer: add heuristics for switch on enum type [PR105273]
[platform/upstream/gcc.git] / gcc / analyzer / supergraph.h
1 /* "Supergraph" classes that combine CFGs and callgraph into one digraph.
2    Copyright (C) 2019-2022 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_SUPERGRAPH_H
22 #define GCC_ANALYZER_SUPERGRAPH_H
23
24 #include "ordered-hash-map.h"
25 #include "cfg.h"
26 #include "basic-block.h"
27 #include "gimple.h"
28 #include "gimple-iterator.h"
29 #include "digraph.h"
30
31 using namespace ana;
32
33 namespace ana {
34
35 /* Forward decls, using indentation to show inheritance.  */
36
37 class supergraph;
38 class supernode;
39 class superedge;
40   class callgraph_superedge;
41     class call_superedge;
42     class return_superedge;
43   class cfg_superedge;
44     class switch_cfg_superedge;
45 class supercluster;
46 class dot_annotator;
47
48 class logger;
49
50 /* An enum for discriminating between superedge subclasses.  */
51
52 enum edge_kind
53 {
54   SUPEREDGE_CFG_EDGE,
55   SUPEREDGE_CALL,
56   SUPEREDGE_RETURN,
57   SUPEREDGE_INTRAPROCEDURAL_CALL
58 };
59
60 /* Flags for controlling the appearance of .dot dumps.  */
61
62 enum supergraph_dot_flags
63 {
64   SUPERGRAPH_DOT_SHOW_BBS = (1 << 0)
65 };
66
67 /* A traits struct describing the family of node, edge and digraph
68    classes for supergraphs.  */
69
70 struct supergraph_traits
71 {
72   typedef supernode node_t;
73   typedef superedge edge_t;
74   typedef supergraph graph_t;
75   struct dump_args_t
76   {
77     dump_args_t (enum supergraph_dot_flags flags,
78                  const dot_annotator *node_annotator)
79     : m_flags (flags),
80       m_node_annotator (node_annotator)
81     {}
82
83     enum supergraph_dot_flags m_flags;
84     const dot_annotator *m_node_annotator;
85   };
86   typedef supercluster cluster_t;
87 };
88
89 /* A class to manage the setting and restoring of statement uids.  */
90
91 class saved_uids
92 {
93 public:
94   void make_uid_unique (gimple *stmt);
95   void restore_uids () const;
96
97 private:
98   auto_vec<std::pair<gimple *, unsigned> > m_old_stmt_uids;
99 };
100
101 /* A "supergraph" is a directed graph formed by joining together all CFGs,
102    linking them via interprocedural call and return edges.
103
104    Basic blocks are split at callsites, so that a call statement occurs
105    twice: once at the end of a supernode, and a second instance at the
106    start of the next supernode (to handle the return).  */
107
108 class supergraph : public digraph<supergraph_traits>
109 {
110 public:
111   supergraph (logger *logger);
112   ~supergraph ();
113
114   supernode *get_node_for_function_entry (function *fun) const
115   {
116     return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (fun));
117   }
118
119   supernode *get_node_for_function_exit (function *fun) const
120   {
121     return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (fun));
122   }
123
124   supernode *get_node_for_block (basic_block bb) const
125   {
126     return *const_cast <bb_to_node_t &> (m_bb_to_initial_node).get (bb);
127   }
128
129   /* Get the supernode containing the second half of the gcall *
130      at an interprocedural call, within the caller.  */
131   supernode *get_caller_next_node (cgraph_edge *edge) const
132   {
133     return (*const_cast <cgraph_edge_to_node_t &>
134               (m_cgraph_edge_to_caller_next_node).get (edge));
135   }
136
137   call_superedge *get_edge_for_call (cgraph_edge *edge) const
138   {
139     return (*const_cast <cgraph_edge_to_call_superedge_t &>
140               (m_cgraph_edge_to_call_superedge).get (edge));
141   }
142
143   return_superedge *get_edge_for_return (cgraph_edge *edge) const
144   {
145     return (*const_cast <cgraph_edge_to_return_superedge_t &>
146               (m_cgraph_edge_to_return_superedge).get (edge));
147   }
148
149   superedge *get_intraprocedural_edge_for_call (cgraph_edge *edge) const
150   {
151     return (*const_cast <cgraph_edge_to_intraproc_superedge_t &>
152               (m_cgraph_edge_to_intraproc_superedge).get (edge));
153   }
154
155   cfg_superedge *get_edge_for_cfg_edge (edge e) const
156   {
157     return (*const_cast <cfg_edge_to_cfg_superedge_t &>
158               (m_cfg_edge_to_cfg_superedge).get (e));
159   }
160
161   supernode *get_supernode_for_stmt (const gimple *stmt) const
162   {
163     return (*const_cast <stmt_to_node_t &>(m_stmt_to_node_t).get
164             (const_cast <gimple *> (stmt)));
165   }
166
167   void dump_dot_to_pp (pretty_printer *pp, const dump_args_t &) const;
168   void dump_dot_to_file (FILE *fp, const dump_args_t &) const;
169   void dump_dot (const char *path, const dump_args_t &) const;
170
171   json::object *to_json () const;
172
173   int num_nodes () const { return m_nodes.length (); }
174   int num_edges () const { return m_edges.length (); }
175
176   supernode *get_node_by_index (int idx) const
177   {
178     return m_nodes[idx];
179   }
180
181   unsigned get_num_snodes (const function *fun) const
182   {
183     function_to_num_snodes_t &map
184       = const_cast <function_to_num_snodes_t &>(m_function_to_num_snodes);
185     return *map.get (fun);
186   }
187
188 private:
189   supernode *add_node (function *fun, basic_block bb, gcall *returning_call,
190                        gimple_seq phi_nodes);
191   cfg_superedge *add_cfg_edge (supernode *src, supernode *dest, ::edge e);
192   call_superedge *add_call_superedge (supernode *src, supernode *dest,
193                                       cgraph_edge *cedge);
194   return_superedge *add_return_superedge (supernode *src, supernode *dest,
195                                           cgraph_edge *cedge);
196
197   /* Data.  */
198
199   typedef ordered_hash_map<basic_block, supernode *> bb_to_node_t;
200   bb_to_node_t m_bb_to_initial_node;
201   bb_to_node_t m_bb_to_final_node;
202
203   typedef ordered_hash_map<cgraph_edge *, supernode *> cgraph_edge_to_node_t;
204   cgraph_edge_to_node_t m_cgraph_edge_to_caller_prev_node;
205   cgraph_edge_to_node_t m_cgraph_edge_to_caller_next_node;
206
207   typedef ordered_hash_map< ::edge, cfg_superedge *>
208     cfg_edge_to_cfg_superedge_t;
209   cfg_edge_to_cfg_superedge_t m_cfg_edge_to_cfg_superedge;
210
211   typedef ordered_hash_map<cgraph_edge *, call_superedge *>
212     cgraph_edge_to_call_superedge_t;
213   cgraph_edge_to_call_superedge_t m_cgraph_edge_to_call_superedge;
214
215   typedef ordered_hash_map<cgraph_edge *, return_superedge *>
216     cgraph_edge_to_return_superedge_t;
217   cgraph_edge_to_return_superedge_t m_cgraph_edge_to_return_superedge;
218
219   typedef ordered_hash_map<cgraph_edge *, superedge *>
220     cgraph_edge_to_intraproc_superedge_t;
221   cgraph_edge_to_intraproc_superedge_t m_cgraph_edge_to_intraproc_superedge;
222
223   typedef ordered_hash_map<gimple *, supernode *> stmt_to_node_t;
224   stmt_to_node_t m_stmt_to_node_t;
225
226   typedef hash_map<const function *, unsigned> function_to_num_snodes_t;
227   function_to_num_snodes_t m_function_to_num_snodes;
228
229   saved_uids m_stmt_uids;
230 };
231
232 /* A node within a supergraph.  */
233
234 class supernode : public dnode<supergraph_traits>
235 {
236  public:
237   supernode (function *fun, basic_block bb, gcall *returning_call,
238              gimple_seq phi_nodes, int index)
239   : m_fun (fun), m_bb (bb), m_returning_call (returning_call),
240     m_phi_nodes (phi_nodes), m_index (index)
241   {}
242
243   function *get_function () const { return m_fun; }
244
245   bool entry_p () const
246   {
247     return m_bb == ENTRY_BLOCK_PTR_FOR_FN (m_fun);
248   }
249
250   bool return_p () const
251   {
252     return m_bb == EXIT_BLOCK_PTR_FOR_FN (m_fun);
253   }
254
255   void dump_dot (graphviz_out *gv, const dump_args_t &args) const override;
256   void dump_dot_id (pretty_printer *pp) const;
257
258   json::object *to_json () const;
259
260   location_t get_start_location () const;
261   location_t get_end_location () const;
262
263   /* Returns iterator at the start of the list of phi nodes, if any.  */
264   gphi_iterator start_phis ()
265   {
266     gimple_seq *pseq = &m_phi_nodes;
267
268     /* Adapted from gsi_start_1. */
269     gphi_iterator i;
270
271     i.ptr = gimple_seq_first (*pseq);
272     i.seq = pseq;
273     i.bb = i.ptr ? gimple_bb (i.ptr) : NULL;
274
275     return i;
276   }
277
278   gcall *get_returning_call () const
279   {
280     return m_returning_call;
281   }
282
283   gimple *get_last_stmt () const
284   {
285     if (m_stmts.length () == 0)
286       return NULL;
287     return m_stmts[m_stmts.length () - 1];
288   }
289
290   gcall *get_final_call () const
291   {
292     gimple *stmt = get_last_stmt ();
293     if (stmt == NULL)
294       return NULL;
295     return dyn_cast<gcall *> (stmt);
296   }
297
298   unsigned int get_stmt_index (const gimple *stmt) const;
299
300   function * const m_fun; // alternatively could be stored as runs of indices within the supergraph
301   const basic_block m_bb;
302   gcall * const m_returning_call; // for handling the result of a returned call
303   gimple_seq m_phi_nodes; // ptr to that of the underlying BB, for the first supernode for the BB
304   auto_vec<gimple *> m_stmts;
305   const int m_index; /* unique within the supergraph as a whole.  */
306 };
307
308 /* An abstract base class encapsulating an edge within a supergraph.
309    Edges can be CFG edges, or calls/returns for callgraph edges.  */
310
311 class superedge : public dedge<supergraph_traits>
312 {
313  public:
314   virtual ~superedge () {}
315
316   void dump (pretty_printer *pp) const;
317   void dump () const;
318   void dump_dot (graphviz_out *gv, const dump_args_t &args)
319     const final override;
320
321   virtual void dump_label_to_pp (pretty_printer *pp,
322                                  bool user_facing) const = 0;
323
324   json::object *to_json () const;
325
326   enum edge_kind get_kind () const { return m_kind; }
327
328   virtual cfg_superedge *dyn_cast_cfg_superedge () { return NULL; }
329   virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return NULL; }
330   virtual const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const { return NULL; }
331   virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return NULL; }
332   virtual const callgraph_superedge *dyn_cast_callgraph_superedge () const { return NULL; }
333   virtual call_superedge *dyn_cast_call_superedge () { return NULL; }
334   virtual const call_superedge *dyn_cast_call_superedge () const { return NULL; }
335   virtual return_superedge *dyn_cast_return_superedge () { return NULL; }
336   virtual const return_superedge *dyn_cast_return_superedge () const { return NULL; }
337
338   ::edge get_any_cfg_edge () const;
339   cgraph_edge *get_any_callgraph_edge () const;
340
341   label_text get_description (bool user_facing) const;
342
343  protected:
344   superedge (supernode *src, supernode *dest, enum edge_kind kind)
345   : dedge<supergraph_traits> (src, dest),
346     m_kind (kind)
347   {}
348
349  public:
350   const enum edge_kind m_kind;
351 };
352
353 /* An ID representing an expression at a callsite:
354    either a parameter index, or the return value (or unknown).  */
355
356 class callsite_expr
357 {
358  public:
359   callsite_expr () : m_val (-1) {}
360
361   static callsite_expr from_zero_based_param (int idx)
362   {
363     return callsite_expr (idx + 1);
364   }
365
366   static callsite_expr from_return_value ()
367   {
368     return callsite_expr (0);
369   }
370
371   bool param_p () const
372   {
373     return m_val > 0;
374   }
375
376   bool return_value_p () const
377   {
378     return m_val == 0;
379   }
380
381  private:
382   callsite_expr (int val) : m_val (val) {}
383
384   int m_val; /* 1-based parm, 0 for return value, or -1 for "unknown".  */
385 };
386
387 /* A subclass of superedge with an associated callgraph edge (either a
388    call or a return).  */
389
390 class callgraph_superedge : public superedge
391 {
392  public:
393   callgraph_superedge (supernode *src, supernode *dst, enum edge_kind kind,
394                        cgraph_edge *cedge)
395   : superedge (src, dst, kind),
396     m_cedge (cedge)
397   {}
398
399   void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
400     final override;
401
402   callgraph_superedge *dyn_cast_callgraph_superedge () final override
403   {
404     return this;
405   }
406   const callgraph_superedge *dyn_cast_callgraph_superedge () const
407     final override
408   {
409     return this;
410   }
411
412   function *get_callee_function () const;
413   function *get_caller_function () const;
414   tree get_callee_decl () const;
415   tree get_caller_decl () const;
416   gcall *get_call_stmt () const;
417   tree get_arg_for_parm (tree parm, callsite_expr *out) const;
418   tree get_parm_for_arg (tree arg, callsite_expr *out) const;
419   tree map_expr_from_caller_to_callee (tree caller_expr,
420                                        callsite_expr *out) const;
421   tree map_expr_from_callee_to_caller (tree callee_expr,
422                                        callsite_expr *out) const;
423
424   cgraph_edge *const m_cedge;
425 };
426
427 } // namespace ana
428
429 template <>
430 template <>
431 inline bool
432 is_a_helper <const callgraph_superedge *>::test (const superedge *sedge)
433 {
434   return (sedge->get_kind () == SUPEREDGE_INTRAPROCEDURAL_CALL
435           || sedge->get_kind () == SUPEREDGE_CALL
436           || sedge->get_kind () == SUPEREDGE_RETURN);
437 }
438
439 namespace ana {
440
441 /* A subclass of superedge representing an interprocedural call.  */
442
443 class call_superedge : public callgraph_superedge
444 {
445  public:
446   call_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
447   : callgraph_superedge (src, dst, SUPEREDGE_CALL, cedge)
448   {}
449
450   call_superedge *dyn_cast_call_superedge () final override
451   {
452     return this;
453   }
454   const call_superedge *dyn_cast_call_superedge () const final override
455   {
456     return this;
457   }
458
459   return_superedge *get_edge_for_return (const supergraph &sg) const
460   {
461     return sg.get_edge_for_return (m_cedge);
462   }
463 };
464
465 } // namespace ana
466
467 template <>
468 template <>
469 inline bool
470 is_a_helper <const call_superedge *>::test (const superedge *sedge)
471 {
472   return sedge->get_kind () == SUPEREDGE_CALL;
473 }
474
475 namespace ana {
476
477 /* A subclass of superedge represesnting an interprocedural return.  */
478
479 class return_superedge : public callgraph_superedge
480 {
481  public:
482   return_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
483   : callgraph_superedge (src, dst, SUPEREDGE_RETURN, cedge)
484   {}
485
486   return_superedge *dyn_cast_return_superedge () final override { return this; }
487   const return_superedge *dyn_cast_return_superedge () const final override
488   {
489     return this;
490   }
491
492   call_superedge *get_edge_for_call (const supergraph &sg) const
493   {
494     return sg.get_edge_for_call (m_cedge);
495   }
496 };
497
498 } // namespace ana
499
500 template <>
501 template <>
502 inline bool
503 is_a_helper <const return_superedge *>::test (const superedge *sedge)
504 {
505   return sedge->get_kind () == SUPEREDGE_RETURN;
506 }
507
508 namespace ana {
509
510 /* A subclass of superedge that corresponds to a CFG edge.  */
511
512 class cfg_superedge : public superedge
513 {
514  public:
515   cfg_superedge (supernode *src, supernode *dst, ::edge e)
516   : superedge (src, dst, SUPEREDGE_CFG_EDGE),
517     m_cfg_edge (e)
518   {}
519
520   void dump_label_to_pp (pretty_printer *pp, bool user_facing) const override;
521   cfg_superedge *dyn_cast_cfg_superedge () final override { return this; }
522   const cfg_superedge *dyn_cast_cfg_superedge () const final override { return this; }
523
524   ::edge get_cfg_edge () const { return m_cfg_edge; }
525   int get_flags () const { return m_cfg_edge->flags; }
526   int true_value_p () const { return get_flags () & EDGE_TRUE_VALUE; }
527   int false_value_p () const { return get_flags () & EDGE_FALSE_VALUE; }
528   int back_edge_p () const { return get_flags () & EDGE_DFS_BACK; }
529
530   size_t get_phi_arg_idx () const;
531   tree get_phi_arg (const gphi *phi) const;
532
533  private:
534   const ::edge m_cfg_edge;
535 };
536
537 } // namespace ana
538
539 template <>
540 template <>
541 inline bool
542 is_a_helper <const cfg_superedge *>::test (const superedge *sedge)
543 {
544   return sedge->get_kind () == SUPEREDGE_CFG_EDGE;
545 }
546
547 namespace ana {
548
549 /* A subclass for edges from switch statements, retaining enough
550    information to identify the pertinent cases, and for adding labels
551    when rendering via graphviz.  */
552
553 class switch_cfg_superedge : public cfg_superedge {
554  public:
555   switch_cfg_superedge (supernode *src, supernode *dst, ::edge e);
556
557   const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const
558     final override
559   {
560     return this;
561   }
562
563   void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
564     final override;
565
566   gswitch *get_switch_stmt () const
567   {
568     return as_a <gswitch *> (m_src->get_last_stmt ());
569   }
570
571   const vec<tree> &get_case_labels () const { return m_case_labels; }
572
573   bool implicitly_created_default_p () const;
574
575 private:
576   auto_vec<tree> m_case_labels;
577 };
578
579 } // namespace ana
580
581 template <>
582 template <>
583 inline bool
584 is_a_helper <const switch_cfg_superedge *>::test (const superedge *sedge)
585 {
586   return sedge->dyn_cast_switch_cfg_superedge () != NULL;
587 }
588
589 namespace ana {
590
591 /* Base class for adding additional content to the .dot output
592    for a supergraph.  */
593
594 class dot_annotator
595 {
596  public:
597   virtual ~dot_annotator () {}
598   virtual bool add_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
599                                      const supernode &n ATTRIBUTE_UNUSED,
600                                      bool within_table ATTRIBUTE_UNUSED)
601     const
602   {
603     return false;
604   }
605   virtual void add_stmt_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
606                                      const gimple *stmt ATTRIBUTE_UNUSED,
607                                      bool within_row ATTRIBUTE_UNUSED)
608     const {}
609   virtual bool add_after_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
610                                            const supernode &n ATTRIBUTE_UNUSED)
611     const
612   {
613     return false;
614   }
615 };
616
617 extern cgraph_edge *supergraph_call_edge (function *fun, const gimple *stmt);
618 extern function *get_ultimate_function_for_cgraph_edge (cgraph_edge *edge);
619
620 } // namespace ana
621
622 #endif /* GCC_ANALYZER_SUPERGRAPH_H */