c++: only cache constexpr calls that are constant exprs
[official-gcc.git] / gcc / analyzer / program-point.cc
blobf2d6490f0c04407775d488a0e7752e3f35738f8c
1 /* Classes for representing locations within the program.
2 Copyright (C) 2019-2023 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #define INCLUDE_MEMORY
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tree.h"
26 #include "gimple-pretty-print.h"
27 #include "gcc-rich-location.h"
28 #include "ordered-hash-map.h"
29 #include "options.h"
30 #include "cgraph.h"
31 #include "function.h"
32 #include "cfg.h"
33 #include "basic-block.h"
34 #include "gimple.h"
35 #include "gimple-iterator.h"
36 #include "digraph.h"
37 #include "analyzer/analyzer.h"
38 #include "analyzer/analyzer-logging.h"
39 #include "analyzer/call-string.h"
40 #include "analyzer/supergraph.h"
41 #include "analyzer/program-point.h"
42 #include "sbitmap.h"
43 #include "bitmap.h"
44 #include "selftest.h"
45 #include "analyzer/store.h"
46 #include "analyzer/region-model.h"
47 #include "analyzer/sm.h"
48 #include "analyzer/program-state.h"
49 #include "diagnostic-event-id.h"
50 #include "analyzer/pending-diagnostic.h"
51 #include "analyzer/diagnostic-manager.h"
52 #include "shortest-paths.h"
53 #include "analyzer/exploded-graph.h"
54 #include "analyzer/analysis-plan.h"
55 #include "analyzer/inlining-iterator.h"
57 #if ENABLE_ANALYZER
59 namespace ana {
61 /* Get a string for PK. */
63 const char *
64 point_kind_to_string (enum point_kind pk)
66 switch (pk)
68 default:
69 gcc_unreachable ();
70 case PK_ORIGIN:
71 return "PK_ORIGIN";
72 case PK_BEFORE_SUPERNODE:
73 return "PK_BEFORE_SUPERNODE";
74 case PK_BEFORE_STMT:
75 return "PK_BEFORE_STMT";
76 case PK_AFTER_SUPERNODE:
77 return "PK_AFTER_SUPERNODE";
78 case PK_EMPTY:
79 return "PK_EMPTY";
80 case PK_DELETED:
81 return "PK_DELETED";
85 /* class function_point. */
87 function_point::function_point (const supernode *supernode,
88 const superedge *from_edge,
89 unsigned stmt_idx,
90 enum point_kind kind)
91 : m_supernode (supernode), m_from_edge (from_edge),
92 m_stmt_idx (stmt_idx), m_kind (kind)
94 if (from_edge)
96 gcc_checking_assert (m_kind == PK_BEFORE_SUPERNODE);
97 gcc_checking_assert (from_edge->get_kind () == SUPEREDGE_CFG_EDGE);
99 if (stmt_idx)
100 gcc_checking_assert (m_kind == PK_BEFORE_STMT);
103 /* Print this function_point to PP. */
105 void
106 function_point::print (pretty_printer *pp, const format &f) const
108 switch (get_kind ())
110 default:
111 gcc_unreachable ();
113 case PK_ORIGIN:
114 pp_printf (pp, "origin");
115 if (f.m_newlines)
116 pp_newline (pp);
117 break;
119 case PK_BEFORE_SUPERNODE:
121 if (m_from_edge)
123 if (basic_block bb = m_from_edge->m_src->m_bb)
124 pp_printf (pp, "before SN: %i (from SN: %i (bb: %i))",
125 m_supernode->m_index, m_from_edge->m_src->m_index,
126 bb->index);
127 else
128 pp_printf (pp, "before SN: %i (from SN: %i)",
129 m_supernode->m_index, m_from_edge->m_src->m_index);
131 else
132 pp_printf (pp, "before SN: %i (NULL from-edge)",
133 m_supernode->m_index);
134 f.spacer (pp);
135 for (gphi_iterator gpi
136 = const_cast<supernode *>(get_supernode ())->start_phis ();
137 !gsi_end_p (gpi); gsi_next (&gpi))
139 const gphi *phi = gpi.phi ();
140 pp_gimple_stmt_1 (pp, phi, 0, (dump_flags_t)0);
143 break;
145 case PK_BEFORE_STMT:
146 pp_printf (pp, "before (SN: %i stmt: %i): ", m_supernode->m_index,
147 m_stmt_idx);
148 f.spacer (pp);
149 pp_gimple_stmt_1 (pp, get_stmt (), 0, (dump_flags_t)0);
150 if (f.m_newlines)
152 pp_newline (pp);
153 print_source_line (pp);
155 break;
157 case PK_AFTER_SUPERNODE:
158 pp_printf (pp, "after SN: %i", m_supernode->m_index);
159 if (f.m_newlines)
160 pp_newline (pp);
161 break;
165 /* Generate a hash value for this function_point. */
167 hashval_t
168 function_point::hash () const
170 inchash::hash hstate;
171 if (m_supernode)
172 hstate.add_int (m_supernode->m_index);
173 hstate.add_ptr (m_from_edge);
174 hstate.add_int (m_stmt_idx);
175 hstate.add_int (m_kind);
176 return hstate.end ();
179 /* Get the function at this point, if any. */
181 function *
182 function_point::get_function () const
184 if (m_supernode)
185 return m_supernode->m_fun;
186 else
187 return NULL;
190 /* Get the gimple stmt for this function_point, if any. */
192 const gimple *
193 function_point::get_stmt () const
195 if (m_kind == PK_BEFORE_STMT)
196 return m_supernode->m_stmts[m_stmt_idx];
197 else if (m_kind == PK_AFTER_SUPERNODE)
198 return m_supernode->get_last_stmt ();
199 else
200 return NULL;
203 /* Get a location for this function_point, if any. */
205 location_t
206 function_point::get_location () const
208 const gimple *stmt = get_stmt ();
209 if (stmt)
210 return stmt->location;
211 if (m_kind == PK_BEFORE_SUPERNODE)
212 return m_supernode->get_start_location ();
213 else if (m_kind == PK_AFTER_SUPERNODE)
214 return m_supernode->get_end_location ();
215 else
216 return UNKNOWN_LOCATION;
219 /* Return true if this function_point is a before_stmt for
220 the final stmt in its supernode. */
222 bool
223 function_point::final_stmt_p () const
225 if (m_kind != PK_BEFORE_STMT)
226 return false;
227 return m_stmt_idx == get_supernode ()->m_stmts.length () - 1;
230 /* Create a function_point representing the entrypoint of function FUN. */
232 function_point
233 function_point::from_function_entry (const supergraph &sg, function *fun)
235 return before_supernode (sg.get_node_for_function_entry (fun), NULL);
238 /* Create a function_point representing entering supernode SUPERNODE,
239 having reached it via FROM_EDGE (which could be NULL). */
241 function_point
242 function_point::before_supernode (const supernode *supernode,
243 const superedge *from_edge)
245 if (from_edge && from_edge->get_kind () != SUPEREDGE_CFG_EDGE)
246 from_edge = NULL;
247 return function_point (supernode, from_edge, 0, PK_BEFORE_SUPERNODE);
250 /* A subclass of diagnostic_context for use by
251 program_point::print_source_line. */
253 class debug_diagnostic_context : public diagnostic_context
255 public:
256 debug_diagnostic_context ()
258 diagnostic_initialize (this, 0);
259 show_line_numbers_p = true;
260 show_caret = true;
262 ~debug_diagnostic_context ()
264 diagnostic_finish (this);
268 /* Print the source line (if any) for this function_point to PP. */
270 void
271 function_point::print_source_line (pretty_printer *pp) const
273 const gimple *stmt = get_stmt ();
274 if (!stmt)
275 return;
276 // TODO: monospace font
277 debug_diagnostic_context tmp_dc;
278 gcc_rich_location richloc (stmt->location);
279 diagnostic_show_locus (&tmp_dc, &richloc, DK_ERROR);
280 pp_string (pp, pp_formatted_text (tmp_dc.printer));
283 /* class program_point. */
285 /* Print this program_point to PP. */
287 void
288 program_point::print (pretty_printer *pp, const format &f) const
290 pp_string (pp, "callstring: ");
291 m_call_string->print (pp);
292 f.spacer (pp);
294 m_function_point.print (pp, f);
297 /* Dump this point to stderr. */
299 DEBUG_FUNCTION void
300 program_point::dump () const
302 pretty_printer pp;
303 pp_show_color (&pp) = pp_show_color (global_dc->printer);
304 pp.buffer->stream = stderr;
305 print (&pp, format (true));
306 pp_flush (&pp);
309 /* Return a new json::object of the form
310 {"kind" : str,
311 "snode_idx" : int (optional), the index of the supernode,
312 "from_edge_snode_idx" : int (only for kind=='PK_BEFORE_SUPERNODE'),
313 "stmt_idx": int (only for kind=='PK_BEFORE_STMT',
314 "call_string": object for the call_string}. */
316 json::object *
317 program_point::to_json () const
319 json::object *point_obj = new json::object ();
321 point_obj->set ("kind",
322 new json::string (point_kind_to_string (get_kind ())));
324 if (get_supernode ())
325 point_obj->set ("snode_idx",
326 new json::integer_number (get_supernode ()->m_index));
328 switch (get_kind ())
330 default: break;
331 case PK_BEFORE_SUPERNODE:
332 if (const superedge *sedge = get_from_edge ())
333 point_obj->set ("from_edge_snode_idx",
334 new json::integer_number (sedge->m_src->m_index));
335 break;
336 case PK_BEFORE_STMT:
337 point_obj->set ("stmt_idx", new json::integer_number (get_stmt_idx ()));
338 break;
341 point_obj->set ("call_string", m_call_string->to_json ());
343 return point_obj;
346 /* Update the callstack to represent a call from caller to callee.
348 Generally used to push a custom call to a perticular program point
349 where we don't have a superedge representing the call. */
350 void
351 program_point::push_to_call_stack (const supernode *caller,
352 const supernode *callee)
354 m_call_string = m_call_string->push_call (callee, caller);
357 /* Pop the topmost call from the current callstack. */
358 void
359 program_point::pop_from_call_stack ()
361 m_call_string = m_call_string->get_parent ();
362 gcc_assert (m_call_string);
365 /* Generate a hash value for this program_point. */
367 hashval_t
368 program_point::hash () const
370 inchash::hash hstate;
371 hstate.merge_hash (m_function_point.hash ());
372 hstate.add_ptr (m_call_string);
373 return hstate.end ();
376 /* Get the function * at DEPTH within the call stack. */
378 function *
379 program_point::get_function_at_depth (unsigned depth) const
381 gcc_assert (depth <= m_call_string->length ());
382 if (depth == m_call_string->length ())
383 return m_function_point.get_function ();
384 else
385 return get_call_string ()[depth].get_caller_function ();
388 /* Assert that this object is sane. */
390 void
391 program_point::validate () const
393 /* Skip this in a release build. */
394 #if !CHECKING_P
395 return;
396 #endif
398 m_call_string->validate ();
399 /* The "callee" of the final entry in the callstring should be the
400 function of the m_function_point. */
401 if (m_call_string->length () > 0)
402 gcc_assert
403 ((*m_call_string)[m_call_string->length () - 1].get_callee_function ()
404 == get_function ());
407 /* Check to see if SUCC is a valid edge to take (ensuring that we have
408 interprocedurally valid paths in the exploded graph, and enforcing
409 recursion limits).
411 Update the call string if SUCC is a call or a return.
413 Return true if SUCC can be taken, or false otherwise.
415 This is the "point" half of exploded_node::on_edge. */
417 bool
418 program_point::on_edge (exploded_graph &eg,
419 const superedge *succ)
421 logger * const logger = eg.get_logger ();
422 LOG_FUNC (logger);
423 switch (succ->m_kind)
425 case SUPEREDGE_CFG_EDGE:
427 const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (succ);
429 /* Reject abnormal edges; we special-case setjmp/longjmp. */
430 if (cfg_sedge->get_flags () & EDGE_ABNORMAL)
431 return false;
433 break;
435 case SUPEREDGE_CALL:
437 const call_superedge *call_sedge = as_a <const call_superedge *> (succ);
439 if (eg.get_analysis_plan ().use_summary_p (call_sedge->m_cedge))
441 if (logger)
442 logger->log ("rejecting call edge: using summary instead");
443 return false;
446 /* Add the callsite to the call string. */
447 m_call_string = m_call_string->push_call (eg.get_supergraph (),
448 call_sedge);
450 /* Impose a maximum recursion depth and don't analyze paths
451 that exceed it further.
452 This is something of a blunt workaround, but it only
453 applies to recursion (and mutual recursion), not to
454 general call stacks. */
455 if (m_call_string->calc_recursion_depth ()
456 > param_analyzer_max_recursion_depth)
458 if (logger)
459 logger->log ("rejecting call edge: recursion limit exceeded");
460 // TODO: issue a sorry for this?
461 return false;
464 break;
466 case SUPEREDGE_RETURN:
468 /* Require that we return to the call site in the call string. */
469 if (m_call_string->empty_p ())
471 if (logger)
472 logger->log ("rejecting return edge: empty call string");
473 return false;
475 const call_string::element_t &top_of_stack
476 = m_call_string->get_top_of_stack ();
477 m_call_string = m_call_string->get_parent ();
478 call_string::element_t current_call_string_element (succ->m_dest,
479 succ->m_src);
480 if (top_of_stack != current_call_string_element)
482 if (logger)
483 logger->log ("rejecting return edge: return to wrong callsite");
484 return false;
487 break;
489 case SUPEREDGE_INTRAPROCEDURAL_CALL:
491 const callgraph_superedge *cg_sedge
492 = as_a <const callgraph_superedge *> (succ);
493 /* Consider turning this edge into a use of an
494 interprocedural summary. */
495 if (eg.get_analysis_plan ().use_summary_p (cg_sedge->m_cedge))
497 if (logger)
498 logger->log ("using function summary for %qE in %qE",
499 cg_sedge->get_callee_decl (),
500 cg_sedge->get_caller_decl ());
501 return true;
503 else
505 /* Otherwise, we ignore these edges */
506 if (logger)
507 logger->log ("rejecting interprocedural edge");
508 return false;
513 return true;
516 /* Comparator for program points within the same supernode,
517 for implementing worklist::key_t comparison operators.
518 Return negative if POINT_A is before POINT_B
519 Return positive if POINT_A is after POINT_B
520 Return 0 if they are equal. */
523 function_point::cmp_within_supernode_1 (const function_point &point_a,
524 const function_point &point_b)
526 gcc_assert (point_a.get_supernode () == point_b.get_supernode ());
528 switch (point_a.m_kind)
530 default:
531 gcc_unreachable ();
532 case PK_BEFORE_SUPERNODE:
533 switch (point_b.m_kind)
535 default:
536 gcc_unreachable ();
537 case PK_BEFORE_SUPERNODE:
539 int a_src_idx = -1;
540 int b_src_idx = -1;
541 if (point_a.m_from_edge)
542 a_src_idx = point_a.m_from_edge->m_src->m_index;
543 if (point_b.m_from_edge)
544 b_src_idx = point_b.m_from_edge->m_src->m_index;
545 return a_src_idx - b_src_idx;
547 break;
549 case PK_BEFORE_STMT:
550 case PK_AFTER_SUPERNODE:
551 return -1;
553 break;
554 case PK_BEFORE_STMT:
555 switch (point_b.m_kind)
557 default:
558 gcc_unreachable ();
559 case PK_BEFORE_SUPERNODE:
560 return 1;
562 case PK_BEFORE_STMT:
563 return point_a.m_stmt_idx - point_b.m_stmt_idx;
565 case PK_AFTER_SUPERNODE:
566 return -1;
568 break;
569 case PK_AFTER_SUPERNODE:
570 switch (point_b.m_kind)
572 default:
573 gcc_unreachable ();
574 case PK_BEFORE_SUPERNODE:
575 case PK_BEFORE_STMT:
576 return 1;
578 case PK_AFTER_SUPERNODE:
579 return 0;
581 break;
585 /* Comparator for program points within the same supernode,
586 for implementing worklist::key_t comparison operators.
587 Return negative if POINT_A is before POINT_B
588 Return positive if POINT_A is after POINT_B
589 Return 0 if they are equal. */
592 function_point::cmp_within_supernode (const function_point &point_a,
593 const function_point &point_b)
595 int result = cmp_within_supernode_1 (point_a, point_b);
597 /* Check that the ordering is symmetric */
598 #if CHECKING_P
599 int reversed = cmp_within_supernode_1 (point_b, point_a);
600 gcc_assert (reversed == -result);
601 #endif
603 return result;
606 /* Comparator for imposing an order on function_points. */
609 function_point::cmp (const function_point &point_a,
610 const function_point &point_b)
612 int idx_a = point_a.m_supernode ? point_a.m_supernode->m_index : -1;
613 int idx_b = point_b.m_supernode ? point_b.m_supernode->m_index : -1;
614 if (int cmp_idx = idx_a - idx_b)
615 return cmp_idx;
616 gcc_assert (point_a.m_supernode == point_b.m_supernode);
617 if (point_a.m_supernode)
618 return cmp_within_supernode (point_a, point_b);
619 else
620 return 0;
623 /* Comparator for use by vec<function_point>::qsort. */
626 function_point::cmp_ptr (const void *p1, const void *p2)
628 const function_point *fp1 = (const function_point *)p1;
629 const function_point *fp2 = (const function_point *)p2;
630 return cmp (*fp1, *fp2);
633 /* For PK_BEFORE_STMT, go to next stmt (or to PK_AFTER_SUPERNODE). */
635 void
636 function_point::next_stmt ()
638 gcc_assert (m_kind == PK_BEFORE_STMT);
639 if (++m_stmt_idx == m_supernode->m_stmts.length ())
641 m_kind = PK_AFTER_SUPERNODE;
642 m_stmt_idx = 0;
646 /* For those function points for which there is a uniquely-defined
647 successor, return it. */
649 function_point
650 function_point::get_next () const
652 switch (get_kind ())
654 default:
655 gcc_unreachable ();
656 case PK_ORIGIN:
657 case PK_AFTER_SUPERNODE:
658 gcc_unreachable (); /* Not uniquely defined. */
659 case PK_BEFORE_SUPERNODE:
660 if (get_supernode ()->m_stmts.length () > 0)
661 return before_stmt (get_supernode (), 0);
662 else
663 return after_supernode (get_supernode ());
664 case PK_BEFORE_STMT:
666 unsigned next_idx = get_stmt_idx () + 1;
667 if (next_idx < get_supernode ()->m_stmts.length ())
668 return before_stmt (get_supernode (), next_idx);
669 else
670 return after_supernode (get_supernode ());
675 /* class program_point. */
677 program_point
678 program_point::origin (const region_model_manager &mgr)
680 return program_point (function_point (NULL, NULL,
681 0, PK_ORIGIN),
682 mgr.get_empty_call_string ());
685 program_point
686 program_point::from_function_entry (const region_model_manager &mgr,
687 const supergraph &sg,
688 function *fun)
690 return program_point (function_point::from_function_entry (sg, fun),
691 mgr.get_empty_call_string ());
694 /* For those program points for which there is a uniquely-defined
695 successor, return it. */
697 program_point
698 program_point::get_next () const
700 switch (m_function_point.get_kind ())
702 default:
703 gcc_unreachable ();
704 case PK_ORIGIN:
705 case PK_AFTER_SUPERNODE:
706 gcc_unreachable (); /* Not uniquely defined. */
707 case PK_BEFORE_SUPERNODE:
708 if (get_supernode ()->m_stmts.length () > 0)
709 return before_stmt (get_supernode (), 0, get_call_string ());
710 else
711 return after_supernode (get_supernode (), get_call_string ());
712 case PK_BEFORE_STMT:
714 unsigned next_idx = get_stmt_idx () + 1;
715 if (next_idx < get_supernode ()->m_stmts.length ())
716 return before_stmt (get_supernode (), next_idx, get_call_string ());
717 else
718 return after_supernode (get_supernode (), get_call_string ());
723 /* Return true iff POINT_A and POINT_B share the same function and
724 call_string, both directly, and when attempting to undo inlining
725 information. */
727 bool
728 program_point::effectively_intraprocedural_p (const program_point &point_a,
729 const program_point &point_b)
731 /* First, compare without considering inlining info. */
732 if (point_a.get_function ()
733 != point_b.get_function ())
734 return false;
735 if (&point_a.get_call_string ()
736 != &point_b.get_call_string ())
737 return false;
739 /* Consider inlining info; they must have originally come from
740 the same function and have been inlined in the same way. */
741 location_t loc_a = point_a.get_location ();
742 location_t loc_b = point_b.get_location ();
743 inlining_iterator iter_a (loc_a);
744 inlining_iterator iter_b (loc_b);
745 while (!(iter_a.done_p () || iter_b.done_p ()))
747 if (iter_a.done_p () || iter_b.done_p ())
748 return false;
750 if (iter_a.get_fndecl () != iter_b.get_fndecl ())
751 return false;
752 if (iter_a.get_callsite () != iter_b.get_callsite ())
753 return false;
754 if (iter_a.get_block () != iter_b.get_block ())
755 return false;
757 iter_a.next ();
758 iter_b.next ();
761 return true;
764 #if CHECKING_P
766 namespace selftest {
768 /* Verify that function_point::operator== works as expected. */
770 static void
771 test_function_point_equality ()
773 const supernode *snode = NULL;
775 function_point a = function_point (snode, NULL, 0,
776 PK_BEFORE_SUPERNODE);
777 function_point b = function_point::before_supernode (snode, NULL);
778 ASSERT_EQ (a, b);
781 /* Verify that function_point::cmp_within_supernode works as expected. */
783 static void
784 test_function_point_ordering ()
786 const supernode *snode = NULL;
788 /* Populate an array with various points within the same
789 snode, in order. */
790 auto_vec<function_point> points;
791 points.safe_push (function_point::before_supernode (snode, NULL));
792 points.safe_push (function_point::before_stmt (snode, 0));
793 points.safe_push (function_point::before_stmt (snode, 1));
794 points.safe_push (function_point::after_supernode (snode));
796 /* Check all pairs. */
797 unsigned i;
798 function_point *point_a;
799 FOR_EACH_VEC_ELT (points, i, point_a)
801 unsigned j;
802 function_point *point_b;
803 FOR_EACH_VEC_ELT (points, j, point_b)
805 int cmp = function_point::cmp_within_supernode (*point_a, *point_b);
806 if (i == j)
807 ASSERT_EQ (cmp, 0);
808 if (i < j)
809 ASSERT_TRUE (cmp < 0);
810 if (i > j)
811 ASSERT_TRUE (cmp > 0);
816 /* Verify that program_point::operator== works as expected. */
818 static void
819 test_program_point_equality ()
821 region_model_manager mgr;
823 const supernode *snode = NULL;
825 const call_string &cs = mgr.get_empty_call_string ();
827 program_point a = program_point::before_supernode (snode, NULL,
828 cs);
830 program_point b = program_point::before_supernode (snode, NULL,
831 cs);
833 ASSERT_EQ (a, b);
834 // TODO: verify with non-empty callstrings, with different edges
837 /* Run all of the selftests within this file. */
839 void
840 analyzer_program_point_cc_tests ()
842 test_function_point_equality ();
843 test_function_point_ordering ();
844 test_program_point_equality ();
847 } // namespace selftest
849 #endif /* CHECKING_P */
851 } // namespace ana
853 #endif /* #if ENABLE_ANALYZER */