Branch data Line data Source code
1 : : /* Iterator for walking a chain of inlining locations.
2 : : Copyright (C) 2022-2024 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 : 73437 : inlining_iterator (location_t loc)
48 : 73437 : : m_abstract_origin (LOCATION_BLOCK (loc)),
49 : 73437 : m_callsite (UNKNOWN_LOCATION), m_fndecl (NULL),
50 : 73437 : m_next_abstract_origin (NULL)
51 : : {
52 : 73437 : prepare_iteration ();
53 : 73437 : }
54 : :
55 : 130408 : bool done_p () const { return m_abstract_origin == NULL; }
56 : :
57 : 57175 : void next ()
58 : : {
59 : 57175 : m_abstract_origin = m_next_abstract_origin;
60 : 57081 : prepare_iteration ();
61 : 57081 : }
62 : :
63 : 114007 : tree get_fndecl () const { return m_fndecl; }
64 : 108 : location_t get_callsite () const { return m_callsite; }
65 : : tree get_block () const { return m_abstract_origin; }
66 : :
67 : : private:
68 : 130612 : void prepare_iteration ()
69 : : {
70 : 130612 : if (done_p ())
71 : : return;
72 : 57207 : tree block = m_abstract_origin;
73 : 57207 : m_callsite = BLOCK_SOURCE_LOCATION (block);
74 : 57207 : m_fndecl = NULL;
75 : 57207 : block = BLOCK_SUPERCONTEXT (block);
76 : 114606 : while (block && TREE_CODE (block) == BLOCK
77 : 63895 : && BLOCK_ABSTRACT_ORIGIN (block))
78 : : {
79 : 1117 : tree ao = BLOCK_ABSTRACT_ORIGIN (block);
80 : 1117 : if (TREE_CODE (ao) == FUNCTION_DECL)
81 : : {
82 : 925 : m_fndecl = ao;
83 : 925 : break;
84 : : }
85 : 192 : else if (TREE_CODE (ao) != BLOCK)
86 : : break;
87 : :
88 : 192 : block = BLOCK_SUPERCONTEXT (block);
89 : : }
90 : 57207 : if (m_fndecl)
91 : 925 : m_next_abstract_origin = block;
92 : : else
93 : : {
94 : 64521 : while (block && TREE_CODE (block) == BLOCK)
95 : 8239 : block = BLOCK_SUPERCONTEXT (block);
96 : :
97 : 56282 : if (block && TREE_CODE (block) == FUNCTION_DECL)
98 : 56282 : m_fndecl = block;
99 : 56282 : 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 : 56910 : inlining_info (location_t loc)
124 : 56910 : {
125 : 56910 : inlining_iterator iter (loc);
126 : 56910 : m_inner_fndecl = iter.get_fndecl ();
127 : 56910 : int num_frames = 0;
128 : 100531 : while (!iter.done_p ())
129 : : {
130 : 43621 : m_outer_fndecl = iter.get_fndecl ();
131 : 43621 : num_frames++;
132 : 43621 : iter.next ();
133 : : }
134 : 56910 : if (num_frames > 1)
135 : 380 : m_extra_frames = num_frames - 1;
136 : : else
137 : 56530 : m_extra_frames = 0;
138 : 56910 : }
139 : :
140 : 56744 : tree get_inner_fndecl () const { return m_inner_fndecl; }
141 : 42961 : 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 */
|