Branch data Line data Source code
1 : : /* rtegraph.cc graph and nodes used by m2rte.
2 : :
3 : : Copyright (C) 2019-2024 Free Software Foundation, Inc.
4 : : Contributed by Gaius Mulley <gaius@glam.ac.uk>.
5 : :
6 : : This file is part of GNU Modula-2.
7 : :
8 : : GNU Modula-2 is free software; you can redistribute it and/or modify
9 : : it under the terms of the GNU General Public License as published by
10 : : the Free Software Foundation; either version 3, or (at your option)
11 : : any later version.
12 : :
13 : : GNU Modula-2 is distributed in the hope that it will be useful, but
14 : : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : General Public License for more details.
17 : :
18 : : You should have received a copy of the GNU General Public License
19 : : along with GNU Modula-2; see the file COPYING3. If not see
20 : : <http://www.gnu.org/licenses/>. */
21 : :
22 : : #include "gcc-consolidation.h"
23 : :
24 : : #include "../gm2-lang.h"
25 : : #include "../m2-tree.h"
26 : :
27 : : #include "langhooks-def.h" /* FIXME: for lhd_set_decl_assembler_name. */
28 : : #include "tree-pass.h" /* FIXME: only for PROP_gimple_any. */
29 : : #include "toplev.h"
30 : : #include "debug.h"
31 : :
32 : : #include "opts.h"
33 : : #include "mpfr.h"
34 : :
35 : : #undef DEBUGGING
36 : :
37 : : struct GTY (()) rtenode
38 : : {
39 : : bool constructor_reachable; /* Is this guarenteed to be reachable by a constructor? */
40 : : bool export_reachable; /* Is this reachable via exported functions? */
41 : : bool exception_routine; /* Is this an exception routine? */
42 : : bool constructor_final; /* Have we walked this rtenode during constructor testing? */
43 : : bool export_final; /* Walked this rtenode during exported testing? */
44 : : bool is_call; /* Is this a function call? */
45 : : gimple *grtenode;
46 : : tree func;
47 : : rtenode *reachable_src; /* If this is reachable which src function will call us? */
48 : :
49 : : vec<rtenode *, va_gc> *function_call;
50 : : vec<rtenode *, va_gc> *rts_call;
51 : : void dump (void);
52 : : void dump_vec (const char *title, vec<rtenode *, va_gc> *list);
53 : :
54 : : void propagate_constructor_reachable (rtenode *);
55 : : void propagate_export_reachable (rtenode *);
56 : : void error_message (void);
57 : : void warning_message (void);
58 : : void note_message (void);
59 : : const char *get_func_name (void);
60 : : const char *create_message (const char *with_name, const char *without_name);
61 : : };
62 : :
63 : :
64 : : typedef vec<rtenode *, va_gc> rtevec;
65 : :
66 : : static GTY (()) rtevec *allnodes;
67 : : static GTY (()) rtevec *candidates;
68 : : static GTY (()) rtevec *externs;
69 : : static GTY (()) rtevec *constructors;
70 : :
71 : :
72 : : static void determine_reachable (void);
73 : : static void issue_messages (void);
74 : : void rtegraph_dump (void);
75 : :
76 : :
77 : : static GTY (()) rtenode *rtegraph_current_function = NULL;
78 : :
79 : :
80 : : /* rtegraph_get_func returns the function associated with the rtenode. */
81 : :
82 : : tree
83 : 428 : rtegraph_get_func (rtenode *n)
84 : : {
85 : 428 : return n->func;
86 : : }
87 : :
88 : : /* rtegraph_set_current_function assigns rtegraph_current_function with func. */
89 : :
90 : : void
91 : 428 : rtegraph_set_current_function (rtenode *func)
92 : : {
93 : 428 : rtegraph_current_function = func;
94 : 428 : }
95 : :
96 : : /* rtegraph_include_rtscall mark func as an exception routine and remember
97 : : that it is called from rtegraph_current_function in the rts_call array. */
98 : :
99 : 102 : void rtegraph_include_rtscall (rtenode *func)
100 : : {
101 : : /* This is a runtime exception, mark it as such. */
102 : 102 : func->exception_routine = true;
103 : : /* And remember it. */
104 : 102 : vec_safe_push (rtegraph_current_function->rts_call, func);
105 : 102 : }
106 : :
107 : :
108 : : /* rtegraph_include_rtscall remember that rtegraph_current_function calls
109 : : func. */
110 : :
111 : 230 : void rtegraph_include_function_call (rtenode *func)
112 : : {
113 : 230 : vec_safe_push (rtegraph_current_function->function_call, func);
114 : 230 : }
115 : :
116 : :
117 : : /* rtegraph_discover performs the main work, called by m2rte.cc analyse_graph.
118 : : It determines which function calls a reachable and then issues any warning
119 : : message if a reachable function is a call to a runtime exception handler. */
120 : :
121 : 102 : void rtegraph_discover (void)
122 : : {
123 : 102 : determine_reachable ();
124 : : #if defined (DEBUGGING)
125 : : rtegraph_dump ();
126 : : #endif
127 : 102 : issue_messages ();
128 : 102 : }
129 : :
130 : : /* rtegraph_candidates_include include node n in the array of candidates. */
131 : :
132 : 102 : void rtegraph_candidates_include (rtenode *n)
133 : : {
134 : 102 : unsigned int len = vec_safe_length (candidates);
135 : :
136 : 102 : for (unsigned int i = 0; i < len; i++)
137 : 0 : if ((*candidates)[i] == n)
138 : : return;
139 : 102 : vec_safe_push (candidates, n);
140 : : }
141 : :
142 : : /* rtegraph_allnodes_include include node n in the array of allnodes. */
143 : :
144 : 0 : void rtegraph_allnodes_include (rtenode *n)
145 : : {
146 : 0 : unsigned int len = vec_safe_length (allnodes);
147 : :
148 : 0 : for (unsigned int i = 0; i < len; i++)
149 : 0 : if ((*allnodes)[i] == n)
150 : : return;
151 : 0 : vec_safe_push (allnodes, n);
152 : : }
153 : :
154 : : /* rtegraph_externs_include include node n in the array of externs. */
155 : :
156 : 326 : void rtegraph_externs_include (rtenode *n)
157 : : {
158 : 326 : unsigned int len = vec_safe_length (externs);
159 : :
160 : 692 : for (unsigned int i = 0; i < len; i++)
161 : 366 : if ((*externs)[i] == n)
162 : : return;
163 : 326 : vec_safe_push (externs, n);
164 : : }
165 : :
166 : : /* rtegraph_constructors_include include node n in the array of constructors. */
167 : :
168 : 102 : void rtegraph_constructors_include (rtenode *n)
169 : : {
170 : 102 : unsigned int len = vec_safe_length (constructors);
171 : :
172 : 102 : for (unsigned int i = 0; i < len; i++)
173 : 0 : if ((*constructors)[i] == n)
174 : : return;
175 : 102 : vec_safe_push (constructors, n);
176 : : }
177 : :
178 : : /* determine_reachable mark modules constructors as reachable and
179 : : also mark the exported functions as also reachable. */
180 : :
181 : 102 : void determine_reachable (void)
182 : : {
183 : 102 : unsigned int len = vec_safe_length (constructors);
184 : 204 : for (unsigned int i = 0; i < len; i++)
185 : 102 : (*constructors)[i]->propagate_constructor_reachable ((*constructors)[i]);
186 : 102 : len = vec_safe_length (externs);
187 : 428 : for (unsigned int i = 0; i < len; i++)
188 : 326 : (*externs)[i]->propagate_export_reachable ((*externs)[i]);
189 : 102 : }
190 : :
191 : : /* issue_messages for every candidate which is constructor reachable issue
192 : : an error. For each candidate which is reachable via an external call
193 : : issue a warning, for any other candidate (of a local procedure) issue
194 : : a note. */
195 : :
196 : 102 : void issue_messages (void)
197 : : {
198 : 102 : unsigned int len = vec_safe_length (candidates);
199 : 204 : for (unsigned int i = 0; i < len; i++)
200 : : {
201 : 102 : if ((*candidates)[i]->constructor_reachable)
202 : 82 : (*candidates)[i]->error_message ();
203 : 20 : else if ((*candidates)[i]->export_reachable)
204 : 20 : (*candidates)[i]->warning_message ();
205 : : else
206 : 0 : (*candidates)[i]->note_message ();
207 : : }
208 : 102 : }
209 : :
210 : :
211 : : #if defined (DEBUGGING)
212 : : /* rtegraph_dump_vec display the contents of a vector array. */
213 : :
214 : : void
215 : : rtegraph_dump_vec (const char *title, vec<rtenode *, va_gc> *list)
216 : : {
217 : : unsigned int len = vec_safe_length (list);
218 : : printf ("%s (length = %d)\n", title, len);
219 : : for (unsigned int i = 0; i < len; i++)
220 : : {
221 : : printf ("[%d]: rtenode %p ", i, (*list)[i]);
222 : : (*list)[i]->dump ();
223 : : }
224 : : printf ("end\n");
225 : : }
226 : :
227 : : /* rtegraph_dump display the contents of each vector array. */
228 : :
229 : : void rtegraph_dump (void)
230 : : {
231 : : rtegraph_dump_vec ("allnodes", allnodes);
232 : : rtegraph_dump_vec ("candidates", candidates);
233 : : rtegraph_dump_vec ("externs", externs);
234 : : rtegraph_dump_vec ("constructors", constructors);
235 : : }
236 : : #endif
237 : :
238 : : /* rtegraph_init_rtenode create and return a new rtenode. */
239 : :
240 : : rtenode *
241 : 760 : rtegraph_init_rtenode (gimple *g, tree fndecl, bool is_func_call)
242 : : {
243 : 760 : rtenode *n = ggc_alloc<rtenode> ();
244 : :
245 : 760 : n->constructor_reachable = false;
246 : 760 : n->export_reachable = false;
247 : 760 : n->constructor_final = false;
248 : 760 : n->export_final = false;
249 : 760 : n->is_call = is_func_call;
250 : 760 : n->grtenode = g;
251 : 760 : n->func = fndecl;
252 : 760 : n->reachable_src = NULL;
253 : :
254 : 760 : vec_alloc (n->function_call, 0);
255 : : // n->function_call = ggc_alloc<rtevec> ();
256 : 760 : gcc_assert (vec_safe_length (n->function_call) == 0);
257 : 760 : vec_alloc (n->rts_call, 0);
258 : : // n->rts_call = ggc_alloc<rtevec> ();
259 : 760 : gcc_assert (vec_safe_length (n->rts_call) == 0);
260 : 760 : return n;
261 : : }
262 : :
263 : : /* rtegraph_lookup attempts to lookup a rtenode associated with a fndecl
264 : : which is a function call from node g. */
265 : :
266 : : rtenode *
267 : 760 : rtegraph_lookup (gimple *g, tree fndecl, bool is_call)
268 : : {
269 : 760 : unsigned int len = vec_safe_length (allnodes);
270 : 3228 : for (unsigned int i = 0; i < len; i++)
271 : 2468 : if ((*allnodes)[i]->grtenode == g
272 : 692 : && (*allnodes)[i]->func == fndecl
273 : 2468 : && (*allnodes)[i]->is_call == is_call)
274 : : return (*allnodes)[i];
275 : 760 : rtenode *n = rtegraph_init_rtenode (g, fndecl, is_call);
276 : 760 : vec_safe_push (allnodes, n);
277 : : #if defined (DEBUGGING)
278 : : rtegraph_dump ();
279 : : #endif
280 : 760 : return n;
281 : : }
282 : :
283 : : /* rte_error_at - wraps up an error message. */
284 : :
285 : : static void
286 : 102 : rte_error_at (location_t location, diagnostic_t kind, const char *message, ...)
287 : : {
288 : 102 : diagnostic_info diagnostic;
289 : 102 : va_list ap;
290 : 102 : rich_location richloc (line_table, location);
291 : :
292 : 102 : va_start (ap, message);
293 : 102 : diagnostic_set_info (&diagnostic, message, &ap, &richloc, kind);
294 : 102 : diagnostic_report_diagnostic (global_dc, &diagnostic);
295 : 102 : va_end (ap);
296 : 102 : }
297 : :
298 : : /* access_int return true if the tree t contains a constant integer, if so then
299 : : its value is assigned to *value. */
300 : :
301 : : static bool
302 : 204 : access_int (tree t, int *value)
303 : : {
304 : 204 : enum tree_code code = TREE_CODE (t);
305 : :
306 : 204 : if (code == SSA_NAME)
307 : 0 : return access_int (SSA_NAME_VAR (t), value);
308 : 204 : if (code == INTEGER_CST)
309 : : {
310 : 204 : *value = TREE_INT_CST_LOW (t);
311 : 204 : return true;
312 : : }
313 : 0 : if ((code == VAR_DECL || code == PARM_DECL)
314 : 0 : && DECL_HAS_VALUE_EXPR_P (t))
315 : 0 : return access_int (DECL_VALUE_EXPR (t), value);
316 : : return false;
317 : : }
318 : :
319 : : /* access_string return true if the tree t contains a constant string, if so then
320 : : its value is assigned to *value. */
321 : :
322 : : static bool
323 : 306 : access_string (tree t, const char **value)
324 : : {
325 : 306 : if (TREE_CODE (t) == ADDR_EXPR)
326 : : {
327 : 306 : if (TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST)
328 : : {
329 : 306 : *value = TREE_STRING_POINTER (TREE_OPERAND (t, 0));
330 : 306 : return true;
331 : : }
332 : : }
333 : : return false;
334 : : }
335 : :
336 : : /* generate an error using the parameters of the M2RTS exception handler to
337 : : locate the source code. We dont use location, as the error_at function will
338 : : give the function context which might be misleading if this is inlined. */
339 : :
340 : : static void
341 : 102 : generate_report (gimple *stmt, const char *report, diagnostic_t kind)
342 : : {
343 : 102 : if (gimple_call_num_args (stmt) == 5)
344 : : {
345 : 102 : tree s0 = gimple_call_arg (stmt, 0);
346 : 102 : tree i1 = gimple_call_arg (stmt, 1);
347 : 102 : tree i2 = gimple_call_arg (stmt, 2);
348 : 102 : tree s1 = gimple_call_arg (stmt, 3);
349 : 102 : tree s2 = gimple_call_arg (stmt, 4);
350 : 102 : const char *file;
351 : 102 : int line;
352 : 102 : int col;
353 : 102 : const char *scope;
354 : 102 : const char *message;
355 : :
356 : 102 : if (access_string (s0, &file)
357 : 102 : && access_int (i1, &line)
358 : 102 : && access_int (i2, &col)
359 : 102 : && access_string (s1, &scope)
360 : 204 : && access_string (s2, &message))
361 : : {
362 : : /* Continue to use scope as this will survive any
363 : : optimization transforms. */
364 : 102 : location_t location = gimple_location (stmt);
365 : 102 : rte_error_at (location, kind, "In %s\n%s, %s",
366 : : scope, report, message);
367 : : }
368 : : }
369 : 102 : }
370 : :
371 : : /* get_func_name returns the name of the function associated with rtenode. */
372 : :
373 : 20 : const char *rtenode::get_func_name (void)
374 : : {
375 : 20 : if (func != NULL && (DECL_NAME (func) != NULL))
376 : 20 : return IDENTIFIER_POINTER (DECL_NAME (func));
377 : : return NULL;
378 : : }
379 : :
380 : : /* create_message if the current rtenode has a named function associated with it then
381 : : create a new message using with_name and the function name, otherwise
382 : : return without_name. */
383 : :
384 : 20 : const char *rtenode::create_message (const char *with_name, const char *without_name)
385 : : {
386 : 20 : const char *name = get_func_name ();
387 : 20 : if (name == NULL)
388 : : return without_name;
389 : :
390 : 20 : int len = strlen (with_name) + 1 + strlen (name);
391 : 20 : char *message = XNEWVEC (char, len);
392 : 20 : snprintf (message, len, with_name, name);
393 : 20 : return message;
394 : : }
395 : :
396 : : /* error_message issue an DK_ERROR from grtenode. */
397 : :
398 : 82 : void rtenode::error_message (void)
399 : : {
400 : 82 : if (grtenode != NULL)
401 : 82 : generate_report (grtenode, "runtime error will occur", DK_ERROR);
402 : 82 : }
403 : :
404 : : /* warning_message issue an DK_WARNING from grtenode. */
405 : :
406 : 20 : void rtenode::warning_message (void)
407 : : {
408 : 20 : const char *message = reachable_src->create_message
409 : 20 : ("runtime error will occur if an exported procedure is called from %s",
410 : : "runtime error will occur if an exported procedure is called");
411 : 20 : if (grtenode != NULL)
412 : 20 : generate_report (grtenode, message, DK_WARNING);
413 : 20 : }
414 : :
415 : : /* note_message issue an DK_NOTE from grtenode. */
416 : :
417 : 0 : void rtenode::note_message (void)
418 : : {
419 : 0 : if (grtenode != NULL)
420 : 0 : generate_report (grtenode, "runtime will occur if this procedure is called", DK_NOTE);
421 : 0 : }
422 : :
423 : : /* dump_vec display contents of vector array list. */
424 : : #if defined (DEBUGGING)
425 : : void
426 : : rtenode::dump_vec (const char *title, vec<rtenode *, va_gc> *list)
427 : : {
428 : : printf (" %s (length = %d)\n", title, vec_safe_length (list));
429 : : for (unsigned int i = 0; i < vec_safe_length (list); i++)
430 : : printf (" [%d]: rtenode %p\n", i, (*list)[i]);
431 : : }
432 : : #endif
433 : :
434 : : /* dump display all vector arrays associated with rtenode. */
435 : :
436 : : void
437 : 0 : rtenode::dump (void)
438 : : {
439 : : #if defined (DEBUGGING)
440 : : printf ("rtenode::dump:");
441 : : if (func != NULL && (DECL_NAME (func) != NULL))
442 : : {
443 : : const char *n = IDENTIFIER_POINTER (DECL_NAME (func));
444 : : printf ("%s", n);
445 : : }
446 : : if (constructor_reachable)
447 : : printf (", constructor_reachable");
448 : : if (export_reachable)
449 : : printf (", export_reachable");
450 : : if (constructor_final)
451 : : printf (", constructor_final");
452 : : if (export_final)
453 : : printf (", export_final");
454 : : if (is_call)
455 : : printf (", is_call");
456 : : else
457 : : printf (", decl");
458 : : printf (", grtenode %p, func = %p\n", grtenode, func);
459 : : dump_vec ("function_call", function_call);
460 : : dump_vec ("rts_call", rts_call);
461 : : #endif
462 : 0 : }
463 : :
464 : : /* propagate_constructor_reachable for every function which is reachable from
465 : : rtenode call the callee rtenode and mark it as reachable from a
466 : : constructor. */
467 : :
468 : 188 : void rtenode::propagate_constructor_reachable (rtenode *src)
469 : : {
470 : 188 : if (constructor_final)
471 : : return;
472 : 188 : constructor_final = true;
473 : 188 : constructor_reachable = true;
474 : 188 : reachable_src = src;
475 : 200 : for (unsigned int i = 0; i < vec_safe_length (function_call); i++)
476 : 4 : (*function_call)[i]->propagate_constructor_reachable (src);
477 : 270 : for (unsigned int i = 0; i < vec_safe_length (rts_call); i++)
478 : 82 : (*rts_call)[i]->propagate_constructor_reachable (src);
479 : : }
480 : :
481 : : /* propagate_export_reachable for every function which is reachable
482 : : from rtenode call the callee rtenode and mark it as reachable from
483 : : an exported function. */
484 : :
485 : 534 : void rtenode::propagate_export_reachable (rtenode *src)
486 : : {
487 : 534 : if (export_final)
488 : : return;
489 : 534 : export_final = true;
490 : 534 : export_reachable = true;
491 : 534 : reachable_src = src;
492 : 852 : for (unsigned int i = 0; i < vec_safe_length (function_call); i++)
493 : 106 : (*function_call)[i]->propagate_export_reachable (src);
494 : 636 : for (unsigned int i = 0; i < vec_safe_length (rts_call); i++)
495 : 102 : (*rts_call)[i]->propagate_export_reachable (src);
496 : : }
497 : :
498 : : /* rtegraph_init initialize the data structures (vec arrays) in this
499 : : file. */
500 : :
501 : 106 : void rtegraph_init (void)
502 : : {
503 : 106 : vec_alloc (allnodes, 0);
504 : 106 : gcc_assert (vec_safe_length (allnodes) == 0);
505 : 106 : vec_alloc (candidates, 0);
506 : 106 : gcc_assert (vec_safe_length (candidates) == 0);
507 : 106 : vec_alloc (externs, 0);
508 : 106 : gcc_assert (vec_safe_length (externs) == 0);
509 : 106 : vec_alloc (constructors, 0);
510 : 106 : gcc_assert (vec_safe_length (constructors) == 0);
511 : : #if defined (DEBUGGING)
512 : : rtegraph_dump ();
513 : : #endif
514 : 106 : }
515 : :
516 : : /* rtegraph_finish deallocate all vec arrays in this file. */
517 : :
518 : 102 : void rtegraph_finish (void)
519 : : {
520 : 102 : rtegraph_current_function = NULL;
521 : 102 : vec_free (allnodes);
522 : 102 : vec_free (candidates);
523 : 102 : vec_free (externs);
524 : 102 : vec_free (constructors);
525 : 102 : }
526 : :
527 : : #include "gt-m2-rtegraph.h"
|