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