LCOV - code coverage report
Current view: top level - gcc - optinfo-emit-json.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 94.2 % 243 229
Test Date: 2026-05-30 15:37:04 Functions: 100.0 % 15 15
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Emit optimization information as JSON files.
       2              :    Copyright (C) 2018-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 under
       8              : the terms of the GNU General Public License as published by the Free
       9              : Software Foundation; either version 3, or (at your option) any later
      10              : version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15              : 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              : #include "config.h"
      22              : #include "system.h"
      23              : #include "coretypes.h"
      24              : 
      25              : #include "backend.h"
      26              : #include "tree.h"
      27              : #include "gimple.h"
      28              : #include "diagnostic-core.h"
      29              : 
      30              : #include "profile.h"
      31              : #include "output.h"
      32              : #include "tree-pass.h"
      33              : 
      34              : #include "optinfo.h"
      35              : #include "optinfo-emit-json.h"
      36              : #include "json.h"
      37              : #include "pretty-print.h"
      38              : #include "tree-pretty-print.h"
      39              : #include "gimple-pretty-print.h"
      40              : #include "cgraph.h"
      41              : 
      42              : #include "langhooks.h"
      43              : #include "version.h"
      44              : #include "context.h"
      45              : #include "pass_manager.h"
      46              : #include "selftest.h"
      47              : #include "dump-context.h"
      48              : #include <zlib.h>
      49              : 
      50              : /* optrecord_json_writer's ctor.  Populate the top-level parts of the
      51              :    in-memory JSON representation.  */
      52              : 
      53         1288 : optrecord_json_writer::optrecord_json_writer ()
      54         1288 : : m_root_tuple (nullptr), m_scopes ()
      55              : {
      56         1288 :   m_root_tuple = std::make_unique<json::array> ();
      57              : 
      58              :   /* Populate with metadata; compare with toplev.cc: print_version.  */
      59         1288 :   auto metadata = std::make_unique<json::object> ();
      60         1288 :   metadata->set_string ("format", "1");
      61         1288 :   auto generator = std::make_unique<json::object> ();
      62         1288 :   generator->set_string ("name", lang_hooks.name);
      63         1288 :   generator->set_string ("pkgversion", pkgversion_string);
      64         1288 :   generator->set_string ("version", version_string);
      65              :   /* TARGET_NAME is passed in by the Makefile.  */
      66         1288 :   generator->set_string ("target", TARGET_NAME);
      67         1288 :   metadata->set<json::object> ("generator", std::move (generator));
      68         1288 :   m_root_tuple->append<json::object> (std::move (metadata));
      69              : 
      70              :   /* TODO: capture command-line?
      71              :      see gen_producer_string in dwarf2out.cc (currently static).  */
      72              : 
      73              :   /* TODO: capture "any plugins?" flag (or the plugins themselves).  */
      74              : 
      75         1288 :   auto passes = std::make_unique<json::array> ();
      76              : 
      77              :   /* Call add_pass_list for all of the pass lists.  */
      78         1288 :   {
      79              : #define DEF_PASS_LIST(LIST) \
      80              :     add_pass_list (passes.get (), g->get_passes ()->LIST);
      81         1288 :     GCC_PASS_LISTS
      82              : #undef DEF_PASS_LIST
      83              :   }
      84         1288 :   m_root_tuple->append<json::array> (std::move (passes));
      85              : 
      86         1288 :   auto records = std::make_unique<json::array> ();
      87         1288 :   m_scopes.safe_push (records.get ());
      88         1288 :   m_root_tuple->append (std::move (records));
      89         1288 : }
      90              : 
      91              : /* Choose an appropriate filename, and write the saved records to it.  */
      92              : 
      93              : void
      94           41 : optrecord_json_writer::write () const
      95              : {
      96           41 :   pretty_printer pp;
      97           41 :   m_root_tuple->print (&pp, false);
      98              : 
      99           41 :   bool emitted_error = false;
     100           41 :   char *filename = concat (dump_base_name, ".opt-record.json.gz", nullptr);
     101           41 :   gzFile outfile = gzopen (filename, "w");
     102           41 :   if (outfile == nullptr)
     103              :     {
     104            0 :       error_at (UNKNOWN_LOCATION, "cannot open file %qs for writing optimization records",
     105              :                 filename); // FIXME: more info?
     106            0 :       goto cleanup;
     107              :     }
     108              : 
     109           41 :   if (gzputs (outfile, pp_formatted_text (&pp)) <= 0)
     110              :     {
     111            0 :       int tmp;
     112            0 :       error_at (UNKNOWN_LOCATION, "error writing optimization records to %qs: %s",
     113              :                 filename, gzerror (outfile, &tmp));
     114            0 :       emitted_error = true;
     115              :     }
     116              : 
     117           41 :  cleanup:
     118           41 :   if (outfile)
     119           41 :     if (gzclose (outfile) != Z_OK)
     120            0 :       if (!emitted_error)
     121            0 :         error_at (UNKNOWN_LOCATION, "error closing optimization records %qs",
     122              :                   filename);
     123              : 
     124           41 :   free (filename);
     125           41 : }
     126              : 
     127              : /* Add a record for OPTINFO to the queue of records to be written.  */
     128              : 
     129              : void
     130        44714 : optrecord_json_writer::add_record (const optinfo &optinfo)
     131              : {
     132        44714 :   auto obj = optinfo_to_json (optinfo);
     133        44714 :   auto borrowed_obj = obj.get ();
     134              : 
     135        44714 :   add_record (std::move (obj));
     136              : 
     137              :   /* Potentially push the scope.  */
     138        44714 :   if (optinfo.get_kind () == optinfo::kind::scope)
     139              :     {
     140         3958 :       auto children = std::make_unique<json::array> ();
     141         3958 :       m_scopes.safe_push (children.get ());
     142         3958 :       borrowed_obj->set<json::array> ("children", std::move (children));
     143         3958 :     }
     144        44714 : }
     145              : 
     146              : /* Private methods of optrecord_json_writer.  */
     147              : 
     148              : /* Add record OBJ to the innermost scope.  */
     149              : 
     150              : void
     151        44714 : optrecord_json_writer::add_record (std::unique_ptr<json::object> obj)
     152              : {
     153              :   /* Add to innermost scope.  */
     154        44714 :   gcc_assert (m_scopes.length () > 0);
     155        44714 :   m_scopes[m_scopes.length () - 1]->append<json::object> (std::move (obj));
     156        44714 : }
     157              : 
     158              : /* Pop the innermost scope.  */
     159              : 
     160              : void
     161         3958 : optrecord_json_writer::pop_scope ()
     162              : {
     163         3958 :   m_scopes.pop ();
     164              : 
     165              :   /* We should never pop the top-level records array.  */
     166         3958 :   gcc_assert (m_scopes.length () > 0);
     167         3958 : }
     168              : 
     169              : /* Create a JSON object representing LOC.  */
     170              : 
     171              : std::unique_ptr<json::object>
     172        44718 : optrecord_json_writer::impl_location_to_json (dump_impl_location_t loc)
     173              : {
     174        44718 :   auto obj = std::make_unique<json::object> ();
     175        44718 :   obj->set_string ("file", loc.m_file);
     176        44718 :   obj->set_integer ("line", loc.m_line);
     177        44718 :   if (loc.m_function)
     178        44718 :     obj->set_string ("function", loc.m_function);
     179        44718 :   return obj;
     180              : }
     181              : 
     182              : /* Create a JSON object representing LOC.  */
     183              : 
     184              : std::unique_ptr<json::object>
     185        36722 : optrecord_json_writer::location_to_json (location_t loc)
     186              : {
     187        36722 :   gcc_assert (LOCATION_LOCUS (loc) != UNKNOWN_LOCATION);
     188        36722 :   expanded_location exploc = expand_location (loc);
     189        36722 :   auto obj = std::make_unique<json::object> ();
     190        36722 :   obj->set_string ("file", exploc.file);
     191        36722 :   obj->set_integer ("line", exploc.line);
     192        36722 :   obj->set_integer ("column", exploc.column);
     193        36722 :   return obj;
     194              : }
     195              : 
     196              : /* Create a JSON object representing COUNT.  */
     197              : 
     198              : std::unique_ptr<json::object>
     199        44658 : optrecord_json_writer::profile_count_to_json (profile_count count)
     200              : {
     201        44658 :   auto obj = std::make_unique<json::object> ();
     202        44658 :   obj->set_integer ("value", count.to_gcov_type ());
     203        44658 :   obj->set_string ("quality", profile_quality_as_string (count.quality ()));
     204        44658 :   return obj;
     205              : }
     206              : 
     207              : /* Get a string for use when referring to PASS in the saved optimization
     208              :    records.  */
     209              : 
     210              : std::unique_ptr<json::string>
     211       549658 : optrecord_json_writer::get_id_value_for_pass (const opt_pass &pass)
     212              : {
     213       549658 :   pretty_printer pp;
     214              :   /* this is host-dependent, but will be consistent for a given host.  */
     215       549658 :   pp_pointer (&pp, static_cast<const void *> (&pass));
     216       549658 :   return std::make_unique<json::string> (pp_formatted_text (&pp));
     217       549658 : }
     218              : 
     219              : /* Create a JSON object representing PASS.  */
     220              : 
     221              : std::unique_ptr<json::object>
     222       507472 : optrecord_json_writer::pass_to_json (const opt_pass &pass)
     223              : {
     224       507472 :   auto obj = std::make_unique<json::object> ();
     225       507472 :   const char *type = nullptr;
     226       507472 :   switch (pass.type)
     227              :     {
     228            0 :     default:
     229            0 :       gcc_unreachable ();
     230              :     case GIMPLE_PASS:
     231              :       type = "gimple";
     232              :       break;
     233       136528 :     case RTL_PASS:
     234       136528 :       type = "rtl";
     235       136528 :       break;
     236        28336 :     case SIMPLE_IPA_PASS:
     237        28336 :       type = "simple_ipa";
     238        28336 :       break;
     239        24472 :     case IPA_PASS:
     240        24472 :       type = "ipa";
     241        24472 :       break;
     242              :     }
     243       507472 :   obj->set<json::string> ("id", get_id_value_for_pass (pass));
     244       507472 :   obj->set_string ("type", type);
     245       507472 :   obj->set_string ("name", pass.name);
     246              :   /* Represent the optgroup flags as an array.  */
     247       507472 :   {
     248       507472 :     auto optgroups = std::make_unique<json::array> ();
     249      3552304 :     for (const kv_pair<optgroup_flags_t> *optgroup = optgroup_options;
     250      3552304 :          optgroup->name != nullptr; optgroup++)
     251      3044832 :       if (optgroup->value != OPTGROUP_ALL
     252      2537360 :           && (pass.optinfo_flags & optgroup->value))
     253        91448 :         optgroups->append_string (optgroup->name);
     254       507472 :     obj->set<json::array> ("optgroups", std::move (optgroups));
     255       507472 :   }
     256       507472 :   obj->set_integer ("num", pass.static_pass_number);
     257       507472 :   return obj;
     258              : }
     259              : 
     260              : /* Create a JSON array for LOC representing the chain of inlining
     261              :    locations.
     262              :    Compare with lhd_print_error_function and cp_print_error_function.  */
     263              : 
     264              : std::unique_ptr<json::array>
     265        29588 : optrecord_json_writer::inlining_chain_to_json (location_t loc)
     266              : {
     267        29588 :   auto array = std::make_unique<json::array> ();
     268              : 
     269        29588 :   tree abstract_origin = LOCATION_BLOCK (loc);
     270              : 
     271        58005 :   while (abstract_origin)
     272              :     {
     273        28417 :       location_t *locus;
     274        28417 :       tree block = abstract_origin;
     275              : 
     276        28417 :       locus = &BLOCK_SOURCE_LOCATION (block);
     277        28417 :       tree fndecl = nullptr;
     278        28417 :       block = BLOCK_SUPERCONTEXT (block);
     279        58275 :       while (block && TREE_CODE (block) == BLOCK
     280        43499 :              && BLOCK_ABSTRACT_ORIGIN (block))
     281              :         {
     282         2945 :           tree ao = BLOCK_ABSTRACT_ORIGIN (block);
     283         2945 :           if (TREE_CODE (ao) == FUNCTION_DECL)
     284              :             {
     285              :               fndecl = ao;
     286              :               break;
     287              :             }
     288         1441 :           else if (TREE_CODE (ao) != BLOCK)
     289              :             break;
     290              : 
     291         1441 :           block = BLOCK_SUPERCONTEXT (block);
     292              :         }
     293        28417 :       if (fndecl)
     294              :         abstract_origin = block;
     295              :       else
     296              :         {
     297        50262 :           while (block && TREE_CODE (block) == BLOCK)
     298        23349 :             block = BLOCK_SUPERCONTEXT (block);
     299              : 
     300        26913 :           if (block && TREE_CODE (block) == FUNCTION_DECL)
     301              :             fndecl = block;
     302              :           abstract_origin = nullptr;
     303              :         }
     304              :       if (fndecl)
     305              :         {
     306        28417 :           auto obj = std::make_unique<json::object> ();
     307        28417 :           const char *printable_name
     308        28417 :             = lang_hooks.decl_printable_name (fndecl, 2);
     309        28417 :           obj->set_string ("fndecl", printable_name);
     310        28417 :           if (LOCATION_LOCUS (*locus) != UNKNOWN_LOCATION)
     311         1504 :             obj->set<json::object> ("site", location_to_json (*locus));
     312        28417 :           array->append<json::object> (std::move (obj));
     313        28417 :         }
     314              :     }
     315              : 
     316        29588 :   return array;
     317              : }
     318              : 
     319              : /* Create a JSON object representing OPTINFO.  */
     320              : 
     321              : std::unique_ptr<json::object>
     322        44718 : optrecord_json_writer::optinfo_to_json (const optinfo &optinfo)
     323              : {
     324        44718 :   auto obj = std::make_unique<json::object> ();
     325              : 
     326        44718 :   obj->set<json::object>
     327        44718 :     ("impl_location",
     328        44718 :      impl_location_to_json (optinfo.get_impl_location ()));
     329              : 
     330        44718 :   const char *kind_str = optinfo::kind_to_string (optinfo.get_kind ());
     331        44718 :   obj->set_string ("kind", kind_str);
     332        44718 :   auto message = std::make_unique<json::array> ();
     333       152903 :   for (unsigned i = 0; i < optinfo.num_items (); i++)
     334              :     {
     335       108185 :       const optinfo_item *item = optinfo.get_item (i);
     336       108185 :       switch (item->get_kind ())
     337              :         {
     338            0 :         default:
     339            0 :           gcc_unreachable ();
     340        78455 :         case optinfo_item::kind::text:
     341        78455 :           {
     342        78455 :             message->append_string (item->get_text ());
     343              :           }
     344        78455 :           break;
     345        10451 :         case optinfo_item::kind::tree:
     346        10451 :           {
     347        10451 :             auto json_item = std::make_unique<json::object> ();
     348        10451 :             json_item->set_string ("expr", item->get_text ());
     349              : 
     350              :             /* Capture any location for the node.  */
     351        10451 :             if (LOCATION_LOCUS (item->get_location ()) != UNKNOWN_LOCATION)
     352            0 :               json_item->set<json::object>
     353            0 :                 ("location",
     354            0 :                  location_to_json (item->get_location ()));
     355              : 
     356        10451 :             message->append<json::object> (std::move (json_item));
     357        10451 :           }
     358        10451 :           break;
     359        19017 :         case optinfo_item::kind::gimple:
     360        19017 :           {
     361        19017 :             auto json_item = std::make_unique<json::object> ();
     362        19017 :             json_item->set_string ("stmt", item->get_text ());
     363              : 
     364              :             /* Capture any location for the stmt.  */
     365        19017 :             if (LOCATION_LOCUS (item->get_location ()) != UNKNOWN_LOCATION)
     366         6068 :               json_item->set<json::object>
     367         6068 :                 ("location",
     368         6068 :                  location_to_json (item->get_location ()));
     369              : 
     370        19017 :             message->append<json::object> (std::move (json_item));
     371        19017 :           }
     372        19017 :           break;
     373          262 :         case optinfo_item::kind::symtab_node:
     374          262 :           {
     375          262 :             auto json_item = std::make_unique<json::object> ();
     376          262 :             json_item->set_string ("symtab_node", item->get_text ());
     377              : 
     378              :             /* Capture any location for the node.  */
     379          262 :             if (LOCATION_LOCUS (item->get_location ()) != UNKNOWN_LOCATION)
     380          262 :               json_item->set<json::object>
     381          262 :                 ("location",
     382          262 :                  location_to_json (item->get_location ()));
     383          262 :             message->append<json::object> (std::move (json_item));
     384          262 :           }
     385          262 :           break;
     386              :         }
     387              :    }
     388        44718 :   obj->set<json::array> ("message", std::move (message));
     389              : 
     390        44718 :   if (auto pass = optinfo.get_pass ())
     391        42186 :     obj->set<json::string> ("pass",
     392        42186 :                             get_id_value_for_pass (*pass));
     393              : 
     394        44718 :   profile_count count = optinfo.get_count ();
     395        44718 :   if (count.initialized_p ())
     396        44658 :     obj->set<json::object> ("count", profile_count_to_json (count));
     397              : 
     398              :   /* Record any location, handling the case where of an UNKNOWN_LOCATION
     399              :      within an inlined block.  */
     400        44718 :   location_t loc = optinfo.get_location_t ();
     401        44718 :   if (get_pure_location (line_table, loc) != UNKNOWN_LOCATION)
     402              :     {
     403              :       // TOOD: record the location (just caret for now)
     404              :       // TODO: start/finish also?
     405        28888 :       obj->set<json::object> ("location", location_to_json (loc));
     406              :     }
     407              : 
     408        44718 :   if (current_function_decl)
     409              :     {
     410        42104 :       const char *fnname
     411        42104 :         = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
     412        42104 :       obj->set_string ("function", fnname);
     413              :     }
     414              : 
     415        44718 :   if (loc != UNKNOWN_LOCATION)
     416        29588 :     obj->set<json::array> ("inlining_chain", inlining_chain_to_json (loc));
     417              : 
     418        89436 :   return obj;
     419        44718 : }
     420              : 
     421              : /* Add a json description of PASS and its siblings to ARR, recursing into
     422              :    child passes (adding their descriptions within a "children" array).  */
     423              : 
     424              : void
     425        33488 : optrecord_json_writer::add_pass_list (json::array *arr,
     426              :                                       const opt_pass *pass)
     427              : {
     428        33488 :   gcc_assert (pass);
     429       507472 :   do
     430              :     {
     431       507472 :       auto pass_obj = pass_to_json (*pass);
     432       507472 :       if (pass->sub)
     433              :         {
     434        27048 :           auto child_arr = std::make_unique<json::array> ();
     435        27048 :           add_pass_list (child_arr.get (), pass->sub);
     436        27048 :           pass_obj->set ("children", std::move (child_arr));
     437        27048 :         }
     438       507472 :       arr->append (std::move (pass_obj));
     439       507472 :       pass = pass->next;
     440       507472 :     }
     441       507472 :   while (pass);
     442        33488 : }
     443              : 
     444              : #if CHECKING_P
     445              : 
     446              : namespace selftest {
     447              : 
     448              : /* Verify that we can build a JSON optimization record from dump_*
     449              :    calls.  */
     450              : 
     451              : static void
     452            4 : test_building_json_from_dump_calls ()
     453              : {
     454            4 :   temp_dump_context tmp (true, true, MSG_NOTE);
     455            4 :   dump_user_location_t loc;
     456            4 :   dump_printf_loc (MSG_NOTE, loc, "test of tree: ");
     457            4 :   dump_generic_expr (MSG_NOTE, TDF_SLIM, integer_zero_node);
     458            4 :   optinfo *info = tmp.get_pending_optinfo ();
     459            4 :   ASSERT_TRUE (info != nullptr);
     460            4 :   ASSERT_EQ (info->num_items (), 2);
     461              : 
     462            4 :   optrecord_json_writer writer;
     463            4 :   auto json_obj = writer.optinfo_to_json (*info);
     464            4 :   ASSERT_TRUE (json_obj != nullptr);
     465              : 
     466              :   /* Verify that the json is sane.  */
     467            4 :   pretty_printer pp;
     468            4 :   json_obj->print (&pp, false);
     469            4 :   const char *json_str = pp_formatted_text (&pp);
     470            4 :   ASSERT_STR_CONTAINS (json_str, "impl_location");
     471            4 :   ASSERT_STR_CONTAINS (json_str, "\"kind\": \"note\"");
     472            4 :   ASSERT_STR_CONTAINS (json_str,
     473              :                        "\"message\": [\"test of tree: \", {\"expr\": \"0\"}]");
     474            8 : }
     475              : 
     476              : /* Run all of the selftests within this file.  */
     477              : 
     478              : void
     479            4 : optinfo_emit_json_cc_tests ()
     480              : {
     481            4 :   test_building_json_from_dump_calls ();
     482            4 : }
     483              : 
     484              : } // namespace selftest
     485              : 
     486              : #endif /* CHECKING_P */
        

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.