LCOV - code coverage report
Current view: top level - gcc/m2/gm2-gcc - rtegraph.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 90.1 % 182 164
Test Date: 2026-02-28 14:20:25 Functions: 88.9 % 27 24
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* rtegraph.cc graph and nodes used by m2rte.
       2              : 
       3              : Copyright (C) 2019-2026 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          433 : rtegraph_get_func (rtenode *n)
      84              : {
      85          433 :   return n->func;
      86              : }
      87              : 
      88              : /* rtegraph_set_current_function assigns rtegraph_current_function with func.  */
      89              : 
      90              : void
      91          433 : rtegraph_set_current_function (rtenode *func)
      92              : {
      93          433 :   rtegraph_current_function = func;
      94          433 : }
      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          103 : void rtegraph_include_rtscall (rtenode *func)
     100              : {
     101              :   /* This is a runtime exception, mark it as such.  */
     102          103 :   func->exception_routine = true;
     103              :   /* And remember it.  */
     104          103 :   vec_safe_push (rtegraph_current_function->rts_call, func);
     105          103 : }
     106              : 
     107              : 
     108              : /* rtegraph_include_rtscall remember that rtegraph_current_function calls
     109              :    func.  */
     110              : 
     111          233 : void rtegraph_include_function_call (rtenode *func)
     112              : {
     113          233 :   vec_safe_push (rtegraph_current_function->function_call, func);
     114          233 : }
     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          103 : void rtegraph_discover (void)
     122              : {
     123          103 :   determine_reachable ();
     124              : #if defined (DEBUGGING)
     125              :   rtegraph_dump ();
     126              : #endif
     127          103 :   issue_messages ();
     128          103 : }
     129              : 
     130              : /* rtegraph_candidates_include include node n in the array of candidates.  */
     131              : 
     132          103 : void rtegraph_candidates_include (rtenode *n)
     133              : {
     134          103 :   unsigned int len = vec_safe_length (candidates);
     135              : 
     136          103 :   for (unsigned int i = 0; i < len; i++)
     137            0 :     if ((*candidates)[i] == n)
     138              :       return;
     139          103 :   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          330 : void rtegraph_externs_include (rtenode *n)
     157              : {
     158          330 :   unsigned int len = vec_safe_length (externs);
     159              : 
     160          702 :   for (unsigned int i = 0; i < len; i++)
     161          372 :     if ((*externs)[i] == n)
     162              :       return;
     163          330 :   vec_safe_push (externs, n);
     164              : }
     165              : 
     166              : /* rtegraph_constructors_include include node n in the array of constructors.  */
     167              : 
     168          103 : void rtegraph_constructors_include (rtenode *n)
     169              : {
     170          103 :   unsigned int len = vec_safe_length (constructors);
     171              : 
     172          103 :   for (unsigned int i = 0; i < len; i++)
     173            0 :     if ((*constructors)[i] == n)
     174              :       return;
     175          103 :   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          103 : void determine_reachable (void)
     182              : {
     183          103 :   unsigned int len = vec_safe_length (constructors);
     184          206 :   for (unsigned int i = 0; i < len; i++)
     185          103 :     (*constructors)[i]->propagate_constructor_reachable ((*constructors)[i]);
     186          103 :   len = vec_safe_length (externs);
     187          433 :   for (unsigned int i = 0; i < len; i++)
     188          330 :     (*externs)[i]->propagate_export_reachable ((*externs)[i]);
     189          103 : }
     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          103 : void issue_messages (void)
     197              : {
     198          103 :   unsigned int len = vec_safe_length (candidates);
     199          206 :   for (unsigned int i = 0; i < len; i++)
     200              :     {
     201          103 :       if ((*candidates)[i]->constructor_reachable)
     202           83 :         (*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          103 : }
     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          769 : rtegraph_init_rtenode (gimple *g, tree fndecl, bool is_func_call)
     242              : {
     243          769 :   rtenode *n = ggc_alloc<rtenode> ();
     244              : 
     245          769 :   n->constructor_reachable = false;
     246          769 :   n->export_reachable = false;
     247          769 :   n->constructor_final = false;
     248          769 :   n->export_final = false;
     249          769 :   n->is_call = is_func_call;
     250          769 :   n->grtenode = g;
     251          769 :   n->func = fndecl;
     252          769 :   n->reachable_src = NULL;
     253              : 
     254          769 :   vec_alloc (n->function_call, 0);
     255              :   // n->function_call = ggc_alloc<rtevec> ();
     256          769 :   gcc_assert (vec_safe_length (n->function_call) == 0);
     257          769 :   vec_alloc (n->rts_call, 0);
     258              :   // n->rts_call = ggc_alloc<rtevec> ();
     259          769 :   gcc_assert (vec_safe_length (n->rts_call) == 0);
     260          769 :   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          769 : rtegraph_lookup (gimple *g, tree fndecl, bool is_call)
     268              : {
     269          769 :   unsigned int len = vec_safe_length (allnodes);
     270         3273 :   for (unsigned int i = 0; i < len; i++)
     271         2504 :     if ((*allnodes)[i]->grtenode == g
     272          702 :         && (*allnodes)[i]->func == fndecl
     273         2504 :         && (*allnodes)[i]->is_call == is_call)
     274              :       return (*allnodes)[i];
     275          769 :   rtenode *n = rtegraph_init_rtenode (g, fndecl, is_call);
     276          769 :   vec_safe_push (allnodes, n);
     277              : #if defined (DEBUGGING)
     278              :   rtegraph_dump ();
     279              : #endif
     280          769 :   return n;
     281              : }
     282              : 
     283              : /* rte_error_at - wraps up an error message.  */
     284              : 
     285              : static void
     286          103 : rte_error_at (location_t location, diagnostics::kind kind,
     287              :               const char *message, ...)
     288              : {
     289          103 :   diagnostics::diagnostic_info diagnostic;
     290          103 :   va_list ap;
     291          103 :   rich_location richloc (line_table, location);
     292              : 
     293          103 :   va_start (ap, message);
     294          103 :   diagnostic_set_info (&diagnostic, message, &ap, &richloc, kind);
     295          103 :   diagnostic_report_diagnostic (global_dc, &diagnostic);
     296          103 :   va_end (ap);
     297          103 : }
     298              : 
     299              : /* access_int return true if the tree t contains a constant integer, if so then
     300              :    its value is assigned to *value.  */
     301              : 
     302              : static bool
     303          206 : access_int (tree t, int *value)
     304              : {
     305          206 :   enum tree_code code = TREE_CODE (t);
     306              : 
     307          206 :   if (code == SSA_NAME)
     308            0 :     return access_int (SSA_NAME_VAR (t), value);
     309          206 :   if (code == INTEGER_CST)
     310              :     {
     311          206 :       *value = TREE_INT_CST_LOW (t);
     312          206 :       return true;
     313              :     }
     314            0 :   if ((code == VAR_DECL || code == PARM_DECL)
     315            0 :       && DECL_HAS_VALUE_EXPR_P (t))
     316            0 :     return access_int (DECL_VALUE_EXPR (t), value);
     317              :   return false;
     318              : }
     319              : 
     320              : /* access_string return true if the tree t contains a constant string, if so then
     321              :    its value is assigned to *value.  */
     322              : 
     323              : static bool
     324          309 : access_string (tree t, const char **value)
     325              : {
     326          309 :   if (TREE_CODE (t) == ADDR_EXPR)
     327              :     {
     328          309 :       if (TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST)
     329              :         {
     330          309 :           *value = TREE_STRING_POINTER (TREE_OPERAND (t, 0));
     331          309 :           return true;
     332              :         }
     333              :     }
     334              :   return false;
     335              : }
     336              : 
     337              : /* generate an error using the parameters of the M2RTS exception handler to
     338              :    locate the source code.  We dont use location, as the error_at function will
     339              :    give the function context which might be misleading if this is inlined.  */
     340              : 
     341              : static void
     342          103 : generate_report (gimple *stmt, const char *report, diagnostics::kind kind)
     343              : {
     344          103 :   if (gimple_call_num_args (stmt) == 5)
     345              :     {
     346          103 :       tree s0 = gimple_call_arg (stmt, 0);
     347          103 :       tree i1 = gimple_call_arg (stmt, 1);
     348          103 :       tree i2 = gimple_call_arg (stmt, 2);
     349          103 :       tree s1 = gimple_call_arg (stmt, 3);
     350          103 :       tree s2 = gimple_call_arg (stmt, 4);
     351          103 :       const char *file;
     352          103 :       int line;
     353          103 :       int col;
     354          103 :       const char *scope;
     355          103 :       const char *message;
     356              : 
     357          103 :       if (access_string (s0, &file)
     358          103 :           && access_int (i1, &line)
     359          103 :           && access_int (i2, &col)
     360          103 :           && access_string (s1, &scope)
     361          206 :           && access_string (s2, &message))
     362              :         {
     363              :           /* Continue to use scope as this will survive any
     364              :              optimization transforms.  */
     365          103 :           location_t location = gimple_location (stmt);
     366          103 :           rte_error_at (location, kind, "In %s\n%s, %s",
     367              :                         scope, report, message);
     368              :         }
     369              :     }
     370          103 : }
     371              : 
     372              : /* get_func_name returns the name of the function associated with rtenode.  */
     373              : 
     374           20 : const char *rtenode::get_func_name (void)
     375              : {
     376           20 :   if (func != NULL && (DECL_NAME (func) != NULL))
     377           20 :     return IDENTIFIER_POINTER (DECL_NAME (func));
     378              :   return NULL;
     379              : }
     380              : 
     381              : /* create_message if the current rtenode has a named function associated with it then
     382              :    create a new message using with_name and the function name, otherwise
     383              :    return without_name.  */
     384              : 
     385           20 : const char *rtenode::create_message (const char *with_name, const char *without_name)
     386              : {
     387           20 :   const char *name = get_func_name ();
     388           20 :   if (name == NULL)
     389              :     return without_name;
     390              : 
     391           20 :   int len = strlen (with_name) + 1 + strlen (name);
     392           20 :   char *message = XNEWVEC (char, len);
     393           20 :   snprintf (message, len, with_name, name);
     394           20 :   return message;
     395              : }
     396              : 
     397              : /* error_message issue an diagnostics::kind::error from grtenode.  */
     398              : 
     399           83 : void rtenode::error_message (void)
     400              : {
     401           83 :   if (grtenode != NULL)
     402           83 :     generate_report (grtenode, "runtime error will occur",
     403              :                      diagnostics::kind::error);
     404           83 : }
     405              : 
     406              : /* warning_message issue an diagnostics::kind::warning from grtenode.  */
     407              : 
     408           20 : void rtenode::warning_message (void)
     409              : {
     410           20 :   const char *message = reachable_src->create_message
     411           20 :     ("runtime error will occur if an exported procedure is called from %s",
     412              :      "runtime error will occur if an exported procedure is called");
     413           20 :   if (grtenode != NULL)
     414           20 :     generate_report (grtenode, message, diagnostics::kind::warning);
     415           20 : }
     416              : 
     417              : /* note_message issue an diagnostics::kind::note from grtenode.  */
     418              : 
     419            0 : void rtenode::note_message (void)
     420              : {
     421            0 :   if (grtenode != NULL)
     422            0 :     generate_report (grtenode, "runtime will occur if this procedure is called",
     423              :                      diagnostics::kind::note);
     424            0 : }
     425              : 
     426              : /* dump_vec display contents of vector array list.  */
     427              : #if defined (DEBUGGING)
     428              : void
     429              : rtenode::dump_vec (const char *title, vec<rtenode *, va_gc> *list)
     430              : {
     431              :   printf ("  %s (length = %d)\n", title, vec_safe_length (list));
     432              :   for (unsigned int i = 0; i < vec_safe_length (list); i++)
     433              :     printf ("   [%d]: rtenode %p\n", i, (*list)[i]);
     434              : }
     435              : #endif
     436              : 
     437              : /* dump display all vector arrays associated with rtenode.  */
     438              : 
     439              : void
     440            0 : rtenode::dump (void)
     441              : {
     442              : #if defined (DEBUGGING)
     443              :   printf ("rtenode::dump:");
     444              :   if (func != NULL && (DECL_NAME (func) != NULL))
     445              :     {
     446              :       const char *n = IDENTIFIER_POINTER (DECL_NAME (func));
     447              :       printf ("%s", n);
     448              :     }
     449              :   if (constructor_reachable)
     450              :     printf (", constructor_reachable");
     451              :   if (export_reachable)
     452              :     printf (", export_reachable");
     453              :   if (constructor_final)
     454              :     printf (", constructor_final");
     455              :   if (export_final)
     456              :     printf (", export_final");
     457              :   if (is_call)
     458              :     printf (", is_call");
     459              :   else
     460              :     printf (", decl");
     461              :   printf (", grtenode %p, func = %p\n", grtenode, func);
     462              :   dump_vec ("function_call", function_call);
     463              :   dump_vec ("rts_call", rts_call);
     464              : #endif
     465            0 : }
     466              : 
     467              : /* propagate_constructor_reachable for every function which is reachable from
     468              :    rtenode call the callee rtenode and mark it as reachable from a
     469              :    constructor.  */
     470              : 
     471          190 : void rtenode::propagate_constructor_reachable (rtenode *src)
     472              : {
     473          190 :   if (constructor_final)
     474              :     return;
     475          190 :   constructor_final = true;
     476          190 :   constructor_reachable = true;
     477          190 :   reachable_src = src;
     478          202 :   for (unsigned int i = 0; i < vec_safe_length (function_call); i++)
     479            4 :     (*function_call)[i]->propagate_constructor_reachable (src);
     480          273 :   for (unsigned int i = 0; i < vec_safe_length (rts_call); i++)
     481           83 :     (*rts_call)[i]->propagate_constructor_reachable (src);
     482              : }
     483              : 
     484              : /* propagate_export_reachable for every function which is reachable
     485              :    from rtenode call the callee rtenode and mark it as reachable from
     486              :    an exported function.  */
     487              : 
     488          541 : void rtenode::propagate_export_reachable (rtenode *src)
     489              : {
     490          541 :   if (export_final)
     491              :     return;
     492          541 :   export_final = true;
     493          541 :   export_reachable = true;
     494          541 :   reachable_src = src;
     495          865 :   for (unsigned int i = 0; i < vec_safe_length (function_call); i++)
     496          108 :     (*function_call)[i]->propagate_export_reachable (src);
     497          644 :   for (unsigned int i = 0; i < vec_safe_length (rts_call); i++)
     498          103 :     (*rts_call)[i]->propagate_export_reachable (src);
     499              : }
     500              : 
     501              : /* rtegraph_init initialize the data structures (vec arrays) in this
     502              :    file.  */
     503              : 
     504          107 : void rtegraph_init (void)
     505              : {
     506          107 :   vec_alloc (allnodes, 0);
     507          107 :   gcc_assert (vec_safe_length (allnodes) == 0);
     508          107 :   vec_alloc (candidates, 0);
     509          107 :   gcc_assert (vec_safe_length (candidates) == 0);
     510          107 :   vec_alloc (externs, 0);
     511          107 :   gcc_assert (vec_safe_length (externs) == 0);
     512          107 :   vec_alloc (constructors, 0);
     513          107 :   gcc_assert (vec_safe_length (constructors) == 0);
     514              : #if defined (DEBUGGING)
     515              :   rtegraph_dump ();
     516              : #endif
     517          107 : }
     518              : 
     519              : /* rtegraph_finish deallocate all vec arrays in this file.  */
     520              : 
     521          103 : void rtegraph_finish (void)
     522              : {
     523          103 :   rtegraph_current_function = NULL;
     524          103 :   vec_free (allnodes);
     525          103 :   vec_free (candidates);
     526          103 :   vec_free (externs);
     527          103 :   vec_free (constructors);
     528          103 : }
     529              : 
     530              : #include "gt-m2-rtegraph.h"
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.