1 | /* Classes for representing locations within the program. |
2 | Copyright (C) 2019-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_PROGRAM_POINT_H |
22 | #define GCC_ANALYZER_PROGRAM_POINT_H |
23 | |
24 | #include "pretty-print.h" |
25 | #include "analyzer/call-string.h" |
26 | |
27 | namespace ana { |
28 | |
29 | class exploded_graph; |
30 | |
31 | /* An enum for distinguishing the various kinds of program_point. */ |
32 | |
33 | enum point_kind { |
34 | /* A "fake" node which has edges to all entrypoints. */ |
35 | PK_ORIGIN, |
36 | |
37 | PK_BEFORE_SUPERNODE, |
38 | PK_BEFORE_STMT, |
39 | PK_AFTER_SUPERNODE, |
40 | |
41 | /* Special values used for hash_map: */ |
42 | PK_EMPTY, |
43 | PK_DELETED, |
44 | |
45 | NUM_POINT_KINDS |
46 | }; |
47 | |
48 | extern const char *point_kind_to_string (enum point_kind pk); |
49 | |
50 | class format |
51 | { |
52 | public: |
53 | format (bool newlines) : m_newlines (newlines) {} |
54 | |
55 | void spacer (pretty_printer *pp) const |
56 | { |
57 | if (m_newlines) |
58 | pp_newline (pp); |
59 | else |
60 | pp_space (pp); |
61 | } |
62 | |
63 | bool m_newlines; |
64 | }; |
65 | |
66 | /* A class for representing a location within the program, without |
67 | interprocedural information. |
68 | |
69 | This represents a fine-grained location within the supergraph (or |
70 | within one of its nodes). */ |
71 | |
72 | class function_point |
73 | { |
74 | public: |
75 | function_point (const supernode *supernode, |
76 | const superedge *from_edge, |
77 | unsigned stmt_idx, |
78 | enum point_kind kind); |
79 | |
80 | void print (pretty_printer *pp, const format &f) const; |
81 | void print_source_line (pretty_printer *pp) const; |
82 | void dump () const; |
83 | |
84 | hashval_t hash () const; |
85 | bool operator== (const function_point &other) const |
86 | { |
87 | return (m_supernode == other.m_supernode |
88 | && m_from_edge == other.m_from_edge |
89 | && m_stmt_idx == other.m_stmt_idx |
90 | && m_kind == other.m_kind); |
91 | } |
92 | |
93 | /* Accessors. */ |
94 | |
95 | const supernode *get_supernode () const { return m_supernode; } |
96 | function *get_function () const; |
97 | const gimple *get_stmt () const; |
98 | location_t get_location () const; |
99 | enum point_kind get_kind () const { return m_kind; } |
100 | const superedge *get_from_edge () const |
101 | { |
102 | return m_from_edge; |
103 | } |
104 | unsigned get_stmt_idx () const |
105 | { |
106 | gcc_assert (m_kind == PK_BEFORE_STMT); |
107 | return m_stmt_idx; |
108 | } |
109 | |
110 | bool final_stmt_p () const; |
111 | |
112 | /* Factory functions for making various kinds of program_point. */ |
113 | |
114 | static function_point from_function_entry (const supergraph &sg, |
115 | const function &fun); |
116 | |
117 | static function_point before_supernode (const supernode *supernode, |
118 | const superedge *from_edge); |
119 | |
120 | static function_point before_stmt (const supernode *supernode, |
121 | unsigned stmt_idx) |
122 | { |
123 | return function_point (supernode, NULL, stmt_idx, PK_BEFORE_STMT); |
124 | } |
125 | |
126 | static function_point after_supernode (const supernode *supernode) |
127 | { |
128 | return function_point (supernode, NULL, 0, PK_AFTER_SUPERNODE); |
129 | } |
130 | |
131 | /* Support for hash_map. */ |
132 | |
133 | static function_point empty () |
134 | { |
135 | return function_point (NULL, NULL, 0, PK_EMPTY); |
136 | } |
137 | static function_point deleted () |
138 | { |
139 | return function_point (NULL, NULL, 0, PK_DELETED); |
140 | } |
141 | |
142 | static int cmp_within_supernode_1 (const function_point &point_a, |
143 | const function_point &point_b); |
144 | static int cmp_within_supernode (const function_point &point_a, |
145 | const function_point &point_b); |
146 | static int cmp (const function_point &point_a, |
147 | const function_point &point_b); |
148 | static int cmp_ptr (const void *p1, const void *p2); |
149 | |
150 | /* For before_stmt, go to next stmt. */ |
151 | void next_stmt (); |
152 | |
153 | function_point get_next () const; |
154 | |
155 | private: |
156 | const supernode *m_supernode; |
157 | |
158 | /* For PK_BEFORE_SUPERNODE, and only for CFG edges. */ |
159 | const superedge *m_from_edge; |
160 | |
161 | /* Only for PK_BEFORE_STMT. */ |
162 | unsigned m_stmt_idx; |
163 | |
164 | enum point_kind m_kind; |
165 | }; |
166 | |
167 | /* A class for representing a location within the program, including |
168 | interprocedural information. |
169 | |
170 | This represents a fine-grained location within the supergraph (or |
171 | within one of its nodes), along with a call string giving the |
172 | interprocedural context. */ |
173 | |
174 | class program_point |
175 | { |
176 | public: |
177 | program_point (const function_point &fn_point, |
178 | const call_string &call_string) |
179 | : m_function_point (fn_point), |
180 | m_call_string (&call_string) |
181 | { |
182 | } |
183 | |
184 | void print (pretty_printer *pp, const format &f) const; |
185 | void dump () const; |
186 | |
187 | json::object *to_json () const; |
188 | |
189 | hashval_t hash () const; |
190 | bool operator== (const program_point &other) const |
191 | { |
192 | return (m_function_point == other.m_function_point |
193 | && m_call_string == other.m_call_string); |
194 | } |
195 | bool operator!= (const program_point &other) const |
196 | { |
197 | return !(*this == other); |
198 | } |
199 | |
200 | /* Accessors. */ |
201 | |
202 | const function_point &get_function_point () const { return m_function_point; } |
203 | const call_string &get_call_string () const { return *m_call_string; } |
204 | |
205 | const supernode *get_supernode () const |
206 | { |
207 | return m_function_point.get_supernode (); |
208 | } |
209 | function *get_function () const |
210 | { |
211 | return m_function_point.get_function (); |
212 | } |
213 | function *get_function_at_depth (unsigned depth) const; |
214 | tree get_fndecl () const |
215 | { |
216 | gcc_assert (get_kind () != PK_ORIGIN); |
217 | return get_function ()->decl; |
218 | } |
219 | const gimple *get_stmt () const |
220 | { |
221 | return m_function_point.get_stmt (); |
222 | } |
223 | location_t get_location () const |
224 | { |
225 | return m_function_point.get_location (); |
226 | } |
227 | enum point_kind get_kind () const |
228 | { |
229 | return m_function_point.get_kind (); |
230 | } |
231 | const superedge *get_from_edge () const |
232 | { |
233 | return m_function_point.get_from_edge (); |
234 | } |
235 | unsigned get_stmt_idx () const |
236 | { |
237 | return m_function_point.get_stmt_idx (); |
238 | } |
239 | |
240 | /* Get the number of frames we expect at this program point. |
241 | This will be one more than the length of the call_string |
242 | (which stores the parent callsites), apart from the origin |
243 | node, which doesn't have any frames. */ |
244 | int get_stack_depth () const |
245 | { |
246 | if (get_kind () == PK_ORIGIN) |
247 | return 0; |
248 | return get_call_string ().length () + 1; |
249 | } |
250 | |
251 | /* Factory functions for making various kinds of program_point. */ |
252 | static program_point origin (const region_model_manager &mgr); |
253 | static program_point from_function_entry (const region_model_manager &mgr, |
254 | const supergraph &sg, |
255 | const function &fun); |
256 | |
257 | static program_point before_supernode (const supernode *supernode, |
258 | const superedge *from_edge, |
259 | const call_string &call_string) |
260 | { |
261 | return program_point (function_point::before_supernode (supernode, |
262 | from_edge), |
263 | call_string); |
264 | } |
265 | |
266 | static program_point before_stmt (const supernode *supernode, |
267 | unsigned stmt_idx, |
268 | const call_string &call_string) |
269 | { |
270 | return program_point (function_point::before_stmt (supernode, stmt_idx), |
271 | call_string); |
272 | } |
273 | |
274 | static program_point after_supernode (const supernode *supernode, |
275 | const call_string &call_string) |
276 | { |
277 | return program_point (function_point::after_supernode (supernode), |
278 | call_string); |
279 | } |
280 | |
281 | /* Support for hash_map. */ |
282 | |
283 | static program_point empty () |
284 | { |
285 | return program_point (function_point::empty ()); |
286 | } |
287 | static program_point deleted () |
288 | { |
289 | return program_point (function_point::deleted ()); |
290 | } |
291 | |
292 | bool on_edge (exploded_graph &eg, const superedge *succ); |
293 | void push_to_call_stack (const supernode *caller, const supernode *callee); |
294 | void pop_from_call_stack (); |
295 | void validate () const; |
296 | |
297 | /* For before_stmt, go to next stmt. */ |
298 | void next_stmt () { m_function_point.next_stmt (); } |
299 | |
300 | program_point get_next () const; |
301 | |
302 | static bool effectively_intraprocedural_p (const program_point &point_a, |
303 | const program_point &point_b); |
304 | |
305 | private: |
306 | program_point (const function_point &fn_point) |
307 | : m_function_point (fn_point), |
308 | m_call_string (NULL) |
309 | { |
310 | } |
311 | |
312 | function_point m_function_point; |
313 | const call_string *m_call_string; |
314 | }; |
315 | |
316 | } // namespace ana |
317 | |
318 | #endif /* GCC_ANALYZER_PROGRAM_POINT_H */ |
319 | |