Line data Source code
1 : /* Iterator for walking a chain of inlining locations.
2 : Copyright (C) 2022-2026 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_INLINING_ITERATOR_H
22 : #define GCC_ANALYZER_INLINING_ITERATOR_H
23 :
24 : /* Iterator for walking a chain of inlining locations.
25 :
26 : The fndecls and locations will be traversed from innermost to outermost.
27 : For example, given:
28 :
29 : inline void inner (void)
30 : {
31 : ...LOCATION HERE...
32 : }
33 : void outer (void)
34 : {
35 : inner (); <-- CALLSITE
36 : }
37 :
38 : then the fndecl will be "inner" on the initial iteration, and "outer" on
39 : the second (final) iteration.
40 :
41 : Compare with lhd_print_error_function, cp_print_error_function,
42 : and optrecord_json_writer::inlining_chain_to_json. */
43 :
44 : class inlining_iterator
45 : {
46 : public:
47 53461 : inlining_iterator (location_t loc)
48 53461 : : m_abstract_origin (LOCATION_BLOCK (loc)),
49 53461 : m_callsite (UNKNOWN_LOCATION), m_fndecl (NULL_TREE),
50 53461 : m_next_abstract_origin (NULL)
51 : {
52 53461 : prepare_iteration ();
53 53461 : }
54 :
55 96791 : bool done_p () const { return m_abstract_origin == NULL; }
56 :
57 43534 : void next ()
58 : {
59 43534 : m_abstract_origin = m_next_abstract_origin;
60 43440 : prepare_iteration ();
61 43440 : }
62 :
63 80157 : tree get_fndecl () const { return m_fndecl; }
64 114 : location_t get_callsite () const { return m_callsite; }
65 : tree get_block () const { return m_abstract_origin; }
66 :
67 : private:
68 96995 : void prepare_iteration ()
69 : {
70 96995 : if (done_p ())
71 : return;
72 43566 : tree block = m_abstract_origin;
73 43566 : m_callsite = BLOCK_SOURCE_LOCATION (block);
74 43566 : m_fndecl = NULL_TREE;
75 43566 : block = BLOCK_SUPERCONTEXT (block);
76 87305 : while (block && TREE_CODE (block) == BLOCK
77 49694 : && BLOCK_ABSTRACT_ORIGIN (block))
78 : {
79 707 : tree ao = BLOCK_ABSTRACT_ORIGIN (block);
80 707 : if (TREE_CODE (ao) == FUNCTION_DECL)
81 : {
82 534 : m_fndecl = ao;
83 534 : break;
84 : }
85 173 : else if (TREE_CODE (ao) != BLOCK)
86 : break;
87 :
88 173 : block = BLOCK_SUPERCONTEXT (block);
89 : }
90 43566 : if (m_fndecl)
91 534 : m_next_abstract_origin = block;
92 : else
93 : {
94 51368 : while (block && TREE_CODE (block) == BLOCK)
95 8336 : block = BLOCK_SUPERCONTEXT (block);
96 :
97 43032 : if (block && TREE_CODE (block) == FUNCTION_DECL)
98 43032 : m_fndecl = block;
99 43032 : m_next_abstract_origin = NULL;
100 : }
101 : }
102 :
103 : tree m_abstract_origin;
104 : location_t m_callsite;
105 : tree m_fndecl;
106 : tree m_next_abstract_origin;
107 : };
108 :
109 : /* A class for fixing up fndecls and stack depths in checker_event, based
110 : on inlining records.
111 :
112 : The early inliner runs before the analyzer, which can lead to confusing
113 : output.
114 :
115 : Tne base fndecl and depth within a checker_event are from call strings
116 : in program_points, which reflect the call strings after inlining.
117 : This class lets us offset the depth and fix up the reported fndecl and
118 : stack depth to better reflect the user's original code. */
119 :
120 : class inlining_info
121 : {
122 : public:
123 36701 : inlining_info (location_t loc)
124 36701 : {
125 36701 : inlining_iterator iter (loc);
126 36701 : m_inner_fndecl = iter.get_fndecl ();
127 36701 : int num_frames = 0;
128 66595 : while (!iter.done_p ())
129 : {
130 29894 : m_outer_fndecl = iter.get_fndecl ();
131 29894 : num_frames++;
132 29894 : iter.next ();
133 : }
134 36701 : if (num_frames > 1)
135 175 : m_extra_frames = num_frames - 1;
136 : else
137 36526 : m_extra_frames = 0;
138 36701 : }
139 :
140 36554 : tree get_inner_fndecl () const { return m_inner_fndecl; }
141 29598 : int get_extra_frames () const { return m_extra_frames; }
142 :
143 : private:
144 : tree m_outer_fndecl;
145 : tree m_inner_fndecl;
146 : int m_extra_frames;
147 : };
148 :
149 : #endif /* GCC_ANALYZER_INLINING_ITERATOR_H */
|