diff mbox series

JSON dumping for GENERIC trees

Message ID 20240912014951.3636803-1-tcpreimesberger@gmail.com
State New
Headers show
Series JSON dumping for GENERIC trees | expand

Commit Message

Thor Preimesberger Sept. 12, 2024, 1:49 a.m. UTC
From: Thor C Preimesberger <tcpreimesberger@gmail.com>

This patch allows the compiler to dump GENERIC trees as JSON objects.

The dump flag -fdump-tree-original-json dumps each fndecl node in the 
C frontend's gimplifier as a JSON object and traverses related nodes 
in an analagous manner as to raw-dumping.

Some JSON parsers expect for there to be a single JSON value per file -
the following shell command makes the output conformant:

  tr -d '\n ' < out.json | sed -e 's/\]\[/,/g' | sed -e 's/}{/},{/g'
 
There is also a debug function that simply prints a node as formatted JSON to
stdout.

The information in the dumped JSON is meant to be an amalgation of 
tree-pretty-print.cc's dump_generic_node and print-tree.cc's debug_tree.

Bootstrapped and tested on x86_64-pc-linux-gnu without issue.

ChangeLog:
	* gcc/Makefile.in: Link tree-emit-json.o to c-gimplify.o
	* gcc/c-family/c-gimplify.cc (c_genericize): Hook for
	-fdump-tree-original-json
	* gcc/dumpfile.cc: Include tree-emit-json.h to expose
	node_emit_json and debug_tree_json. Also new headers needed for
	json.h being implicitly exposed
	* gcc/dumpfile.h (dump_flag): New dump flag TDF_JSON
	* gcc/tree-emit-json.cc: Logic for converting a tree to JSON
	and dumping.
	* gcc/tree-emit-json.h: Ditto

Signed-off-by: Thor C Preimesberger <tcpreimesberger@gmail.com>

---
 gcc/Makefile.in            |    2 +
 gcc/c-family/c-gimplify.cc |   30 +-
 gcc/cp/dump.cc             |    1 +
 gcc/dumpfile.cc            |    3 +
 gcc/dumpfile.h             |    6 +
 gcc/tree-emit-json.cc      | 3155 ++++++++++++++++++++++++++++++++++++
 gcc/tree-emit-json.h       |   82 +
 7 files changed, 3268 insertions(+), 11 deletions(-)
 create mode 100644 gcc/tree-emit-json.cc
 create mode 100644 gcc/tree-emit-json.h

Comments

Andrew Pinski Sept. 12, 2024, 2:04 a.m. UTC | #1
On Wed, Sep 11, 2024 at 6:51 PM <tcpreimesberger@gmail.com> wrote:
>
> From: Thor C Preimesberger <tcpreimesberger@gmail.com>
>
> This patch allows the compiler to dump GENERIC trees as JSON objects.
>
> The dump flag -fdump-tree-original-json dumps each fndecl node in the
> C frontend's gimplifier as a JSON object and traverses related nodes
> in an analagous manner as to raw-dumping.
>
> Some JSON parsers expect for there to be a single JSON value per file -
> the following shell command makes the output conformant:
>
>   tr -d '\n ' < out.json | sed -e 's/\]\[/,/g' | sed -e 's/}{/},{/g'
>
> There is also a debug function that simply prints a node as formatted JSON to
> stdout.
>
> The information in the dumped JSON is meant to be an amalgation of
> tree-pretty-print.cc's dump_generic_node and print-tree.cc's debug_tree.

I don't think this is a good idea and there is no obvious use case.
GIMPLE yes but not GENERIC.
Can you explain what the use case is for dumping generic as json. Also
you only hooked up the C and C++ family set of front-ends. Why not
hook up Fortran, Ada, Rust and go too? Why have it done in the
gimplifier?

Thanks,
Andrew

>
> Bootstrapped and tested on x86_64-pc-linux-gnu without issue.
>
> ChangeLog:
>         * gcc/Makefile.in: Link tree-emit-json.o to c-gimplify.o
>         * gcc/c-family/c-gimplify.cc (c_genericize): Hook for
>         -fdump-tree-original-json
>         * gcc/dumpfile.cc: Include tree-emit-json.h to expose
>         node_emit_json and debug_tree_json. Also new headers needed for
>         json.h being implicitly exposed
>         * gcc/dumpfile.h (dump_flag): New dump flag TDF_JSON
>         * gcc/tree-emit-json.cc: Logic for converting a tree to JSON
 >         and dumping.
>         * gcc/tree-emit-json.h: Ditto

A few comments about the changelog entry here.
it should be something like:
gcc/ChangeLog:
         * Makefile.in: ...

gcc/c-family/ChangeLog:
          * c-gimplify.cc ...

Also there is no testcase or indication on how you tested it.


>
> Signed-off-by: Thor C Preimesberger <tcpreimesberger@gmail.com>
>
> ---
>  gcc/Makefile.in            |    2 +
>  gcc/c-family/c-gimplify.cc |   30 +-
>  gcc/cp/dump.cc             |    1 +
>  gcc/dumpfile.cc            |    3 +
>  gcc/dumpfile.h             |    6 +
>  gcc/tree-emit-json.cc      | 3155 ++++++++++++++++++++++++++++++++++++
>  gcc/tree-emit-json.h       |   82 +
>  7 files changed, 3268 insertions(+), 11 deletions(-)
>  create mode 100644 gcc/tree-emit-json.cc
>  create mode 100644 gcc/tree-emit-json.h
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 68fda1a7591..b65cc7f0ad5 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1042,6 +1042,7 @@ OPTS_H = $(INPUT_H) $(VEC_H) opts.h $(OBSTACK_H)
>  SYMTAB_H = $(srcdir)/../libcpp/include/symtab.h $(OBSTACK_H)
>  CPP_INTERNAL_H = $(srcdir)/../libcpp/internal.h
>  TREE_DUMP_H = tree-dump.h $(SPLAY_TREE_H) $(DUMPFILE_H)
> +TREE_EMIT_JSON_H = tree-emit-json.h $(SPLAY_TREE_H) $(DUMPFILE_H) json.h
>  TREE_PASS_H = tree-pass.h $(TIMEVAR_H) $(DUMPFILE_H)
>  TREE_SSA_H = tree-ssa.h tree-ssa-operands.h \
>                 $(BITMAP_H) sbitmap.h $(BASIC_BLOCK_H) $(GIMPLE_H) \
> @@ -1709,6 +1710,7 @@ OBJS = \
>         tree-diagnostic.o \
>         tree-diagnostic-client-data-hooks.o \
>         tree-dump.o \
> +       tree-emit-json.o \
>         tree-eh.o \
>         tree-emutls.o \
>         tree-if-conv.o \
> diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc
> index 3e29766e092..8b0c80f4f75 100644
> --- a/gcc/c-family/c-gimplify.cc
> +++ b/gcc/c-family/c-gimplify.cc
> @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
>  <http://www.gnu.org/licenses/>.  */
>
>  #include "config.h"
> +#define INCLUDE_MEMORY
>  #include "system.h"
>  #include "coretypes.h"
>  #include "tm.h"
> @@ -43,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "context.h"
>  #include "tree-pass.h"
>  #include "internal-fn.h"
> +#include "tree-emit-json.h"
>
>  /*  The gimplification pass converts the language-dependent trees
>      (ld-trees) emitted by the parser into language-independent trees
> @@ -629,20 +631,26 @@ c_genericize (tree fndecl)
>    local_dump_flags = dfi->pflags;
>    if (dump_orig)
>      {
> -      fprintf (dump_orig, "\n;; Function %s",
> -              lang_hooks.decl_printable_name (fndecl, 2));
> -      fprintf (dump_orig, " (%s)\n",
> -              (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null"
> -               : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))));
> -      fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original));
> -      fprintf (dump_orig, "\n");
> -
> -      if (local_dump_flags & TDF_RAW)
> -       dump_node (DECL_SAVED_TREE (fndecl),
> +      if (local_dump_flags & TDF_JSON)
> +       dump_node_json (DECL_SAVED_TREE (fndecl),
>                    TDF_SLIM | local_dump_flags, dump_orig);
>        else
> -       print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl));
> +      {
> +       fprintf (dump_orig, "\n;; Function %s",
> +                lang_hooks.decl_printable_name (fndecl, 2));
> +       fprintf (dump_orig, " (%s)\n",
> +               (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null"
> +                : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))));
> +       fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original));
> +       fprintf (dump_orig, "\n");
> +       if (local_dump_flags & TDF_RAW)
> +         dump_node (DECL_SAVED_TREE (fndecl),
> +                    TDF_SLIM | local_dump_flags, dump_orig);
> +       else
> +         print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl));
> +
>        fprintf (dump_orig, "\n");
> +      }
>      }
>
>    /* Dump all nested functions now.  */
> diff --git a/gcc/cp/dump.cc b/gcc/cp/dump.cc
> index aafb62ffaa0..b1083de5f46 100644
> --- a/gcc/cp/dump.cc
> +++ b/gcc/cp/dump.cc
> @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "system.h"
>  #include "coretypes.h"
>  #include "cp-tree.h"
> +#define INCLUDE_MEMORY
>  #include "tree-dump.h"
>
>  /* Dump a representation of the accessibility information associated
> diff --git a/gcc/dumpfile.cc b/gcc/dumpfile.cc
> index 074da7df216..44d9451cf7c 100644
> --- a/gcc/dumpfile.cc
> +++ b/gcc/dumpfile.cc
> @@ -43,6 +43,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "spellcheck.h"
>  #include "make-unique.h"
>  #include "pretty-print-format-impl.h"
> +#include "tree-emit-json.h"
> +#include "tree-emit-json.h"
>
>  /* If non-NULL, return one past-the-end of the matching SUBPART of
>     the WHOLE string.  */
> @@ -148,6 +150,7 @@ static const kv_pair<dump_flags_t> dump_options[] =
>    {"missed", MSG_MISSED_OPTIMIZATION},
>    {"note", MSG_NOTE},
>    {"optall", MSG_ALL_KINDS},
> +  {"json", TDF_JSON},
>    {"all", dump_flags_t (TDF_ALL_VALUES
>                         & ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_GRAPH
>                             | TDF_STMTADDR | TDF_RHS_ONLY | TDF_NOUID
> diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
> index 877d444ce00..a116df5096f 100644
> --- a/gcc/dumpfile.h
> +++ b/gcc/dumpfile.h
> @@ -202,6 +202,9 @@ enum dump_flag : uint32_t
>
>    /* For error.  */
>    TDF_ERROR = ((uint32_t)1 << 30),
> +
> +  /* Tree JSON dumping */
> +  TDF_JSON = ((uint32_t)1 << 31),
>  };
>
>  /* Dump flags type.  */
> @@ -652,6 +655,9 @@ extern bool enable_rtl_dump_file (void);
>  /* In tree-dump.cc  */
>  extern void dump_node (const_tree, dump_flags_t, FILE *);
>
> +/* In tree-emit-json.cc */
> +extern void dump_node_json(const_tree, dump_flags_t, FILE *);
> +
>  /* In cfghooks.cc  */
>  extern void dump_bb (FILE *, basic_block, int, dump_flags_t);
>
> diff --git a/gcc/tree-emit-json.cc b/gcc/tree-emit-json.cc
> new file mode 100644
> index 00000000000..e6de2029265
> --- /dev/null
> +++ b/gcc/tree-emit-json.cc
> @@ -0,0 +1,3180 @@
> +/* Dumping functionality for GENERIC Trees as JSON. Both for
> +   the dump -fdump-tree-original-json and a new debug
> +   function.
> +   Copyright (C) 2024 Thor Preimesberger <tcpreimesberger@gmail.com>
> +   Adapted from tree-pretty-print.cc, tree-dump.cc, and
> +   print-tree.cc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#define INCLUDE_STRING
> +#define INCLUDE_MEMORY
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tree.h"
> +#include "tree-pretty-print.h"
> +#include "tree-emit-json.h"
> +#include "langhooks.h"
> +#include "tree-iterator.h"
> +#include "dumpfile.h"
> +#include "json.h"
> +#include "tm.h"
> +#include "wide-int-print.h"
> +#include "real.h" //for real printing
> +#include "poly-int.h"
> +#include "gomp-constants.h"
> +#include "internal-fn.h"
> +#include "cgraph.h"
> +#include "predict.h"
> +#include "fold-const.h"
> +#include "vec.h"
> +
> +static unsigned int queue (dump_info_p, const_tree);
> +static void dequeue_and_dump (dump_info_p);
> +static json::array* function_decl_emit_json (tree);
> +static void identifier_node_add_json (tree, json::object*);
> +static void decl_node_add_json (tree, json::object*);
> +static void function_name_add_json (tree, json::object*);
> +static void omp_iterator_add_json (tree, json::object*);
> +static void omp_clause_add_json(tree, json::object*);
> +static void omp_atomic_memory_order_add_json (json::object*,
> +                                              enum omp_memory_order);
> +static json::object* omp_atomic_memory_order_emit_json(omp_memory_order mo);
> +static json::object* omp_clause_emit_json (tree);
> +static json::array* loc_emit_json(expanded_location);
> +
> +/* Add T to the end of the queue of nodes to dump.  Returns the index
> +   assigned to T.  */
> +
> +static unsigned int
> +queue (dump_info_p di, const_tree t)
> +{
> +  dump_queue_p dq;
> +  dump_node_info_p dni;
> +  unsigned int index;
> +
> +  /* Assign the next available index to T.  */
> +  index = ++di->index;
> +
> +  /* Obtain a new queue node.  */
> +  if (di->free_list)
> +    {
> +      dq = di->free_list;
> +      di->free_list = dq->next;
> +    }
> +  else
> +    dq = XNEW (struct dump_queue);
> +
> +  /* Create a new entry in the splay-tree.  */
> +  dni = XNEW (struct dump_node_info);
> +  dni->index = index;
> +  dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
> +                               (splay_tree_value) dni);
> +
> +  /* Add it to the end of the queue.  */
> +  dq->next = 0;
> +  if (!di->queue_end)
> +    di->queue = dq;
> +  else
> +    di->queue_end->next = dq;
> +  di->queue_end = dq;
> +
> +  /* Return the index.  */
> +  return index;
> +}
> +
> +void
> +address_add_json (const void* t, json::object* dummy, char* address_buffer)
> +{
> +  sprintf(address_buffer, HOST_PTR_PRINTF, t);
> +  dummy->set_string("addr", address_buffer);
> +}
> +
> +/* Return args of a function declaration */
> +
> +json::array*
> +function_decl_emit_json (tree t)
> +{
> +  bool wrote_arg = false;
> +  tree arg;
> +  json::array* arg_holder;
> +  json::object* arg_json;
> +
> +  arg_json = new json::object ();
> +  arg_holder = new json::array ();
> +
> +  arg = TYPE_ARG_TYPES (t);
> +
> +  while (arg && arg != void_list_node && arg != error_mark_node)
> +    {
> +      wrote_arg = true;
> +      arg_json = node_emit_json(TREE_VALUE (arg));
> +      arg_holder->append(arg_json);
> +      arg = TREE_CHAIN (arg);
> +    }
> +
> +  if (arg == void_list_node && !wrote_arg)
> +{
> +      arg_json->set_bool("void_list_node", true);
> +      arg_holder->append(arg_json);
> +    }
> +
> +  return arg_holder;
> +}
> +
> +/* Adds Identifier information to JSON object */
> +
> +void
> +identifier_node_add_json (tree t, json::object* dummy)
> +  {
> +    const char* buff = IDENTIFIER_POINTER (t);
> +    dummy->set_string("id_to_locale", identifier_to_locale(buff));
> +    buff = IDENTIFIER_POINTER (t);
> +    dummy->set_string("id_point", buff);
> +  }
> +
> +void
> +decl_node_add_json (tree t, json::object* dummy)
> +{
> +  tree name = DECL_NAME (t);
> +
> +  if (name)
> +      {
> +        if (HAS_DECL_ASSEMBLER_NAME_P(t)
> +            && DECL_ASSEMBLER_NAME_SET_P(t))
> +          identifier_node_add_json(DECL_ASSEMBLER_NAME_RAW(t), dummy);
> +        else if (DECL_NAMELESS(t)
> +                 && DECL_IGNORED_P(t))
> +          name = NULL_TREE;
> +        else
> +          identifier_node_add_json(name, dummy);
> +      }
> +    if (name == NULL_TREE)
> +      {
> +        if (TREE_CODE (t) == LABEL_DECL && LABEL_DECL_UID (t) != -1)
> +          {
> +            dummy->set_integer("Label_UID", LABEL_DECL_UID(t));
> +          }
> +        else if (TREE_CODE (t) == DEBUG_EXPR_DECL)
> +          {
> +            dummy->set_integer("Debug_UID", DEBUG_TEMP_UID (t));
> +          }
> +        else
> +          {
> +            const char* c = TREE_CODE (t) == CONST_DECL ? "Const_UID"
> +                                                        : "Decl_UID";
> +            dummy->set_integer(c, DECL_UID(t));
> +          }
> +      }
> +    if (DECL_PT_UID (t) != DECL_UID (t))
> +      {
> +        dummy->set_integer("ptDecl", DECL_PT_UID(t));
> +      }
> +}
> +
> +/* Function call */
> +
> +void
> +function_name_add_json (tree t, json::object* dummy)
> +{
> +  if (CONVERT_EXPR_P (t))
> +    t = TREE_OPERAND (t, 0);
> +  if (DECL_NAME (t))
> +    {
> +      dummy->set_string("decl_name", lang_hooks.decl_printable_name (t, 1));
> +      dummy->set_integer("uid", DECL_UID(t));
> +    }
> +  else
> +    decl_node_add_json(t, dummy);
> +}
> +
> +/* Adds the name of a call. Enter iff t is CALL_EXPR_FN */
> +
> +void
> +call_name_add_json (tree t, json::object* dummy)
> +{
> +  tree op0 = t;
> +
> +  if (TREE_CODE (op0) == NON_LVALUE_EXPR)
> +    op0 = TREE_OPERAND (op0, 0);
> +  again:
> +    switch (TREE_CODE (op0))
> +      {
> +      case VAR_DECL:
> +      case PARM_DECL:
> +      case FUNCTION_DECL:
> +        function_name_add_json (op0, dummy);
> +        break;
> +
> +      case ADDR_EXPR:
> +      case INDIRECT_REF:
> +      CASE_CONVERT:
> +        op0 = TREE_OPERAND (op0, 0);
> +        goto again;
> +
> +      case COND_EXPR:
> +        {
> +          json::object *_x;
> +          _x = new json::object ();
> +          _x->set("if", node_emit_json(TREE_OPERAND(op0, 0)));
> +          _x->set("then", node_emit_json(TREE_OPERAND(op0, 1)));
> +          _x->set("else", node_emit_json(TREE_OPERAND(op0, 2)));
> +          dummy->set("call_name", _x);
> +        }
> +        break;
> +
> +      case ARRAY_REF:
> +        if (VAR_P (TREE_OPERAND (op0, 0)))
> +       function_name_add_json (TREE_OPERAND (op0, 0), dummy);
> +        else
> +       dummy->set("call_name", node_emit_json (op0));
> +        break;
> +
> +      case MEM_REF:
> +        if (integer_zerop (TREE_OPERAND (op0, 1)))
> +       {
> +         op0 = TREE_OPERAND (op0, 0);
> +         goto again;
> +       }
> +        /* Fallthrough  */
> +      case COMPONENT_REF:
> +      case SSA_NAME:
> +      case OBJ_TYPE_REF:
> +        dummy->set("call_name", node_emit_json (op0));
> +        break;
> +      default:
> +        break;
> +    }
> +}
> +
> +/* OMP helper. */
> +void
> +omp_iterator_add_json(tree iter, json::object* dummy)
> +{
> +  json::array* iter_holder;
> +  iter_holder = new json::array ();
> +
> +  for (tree it = iter; it; it = TREE_CHAIN (it))
> +    {
> +      for (int i = 0; i < 4; i++)
> +        {
> +          if (TREE_VEC_ELT (it, 0) != NULL_TREE)
> +            iter_holder->append (node_emit_json (TREE_VEC_ELT (it, 0)));
> +        }
> +    }
> +  dummy->set("omp_iter", iter_holder);
> +}
> +/* Omp helper. */
> +void
> +omp_clause_add_json(tree clause, json::object* dummy)
> +{
> +  char buffer[100] = {'\0'};
> +  const char* name;
> +  const char* modifier = NULL;
> +  switch (OMP_CLAUSE_CODE (clause))
> +    {
> +    case OMP_CLAUSE_PRIVATE:
> +      name = "private";
> +      goto print_remap;
> +    case OMP_CLAUSE_SHARED:
> +      name = "shared";
> +      goto print_remap;
> +    case OMP_CLAUSE_FIRSTPRIVATE:
> +      name = "firstprivate";
> +      goto print_remap;
> +    case OMP_CLAUSE_LASTPRIVATE:
> +      name = "lastprivate";
> +      if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (clause))
> +       modifier = "conditional:";
> +      goto print_remap;
> +    case OMP_CLAUSE_COPYIN:
> +      name = "copyin";
> +      goto print_remap;
> +    case OMP_CLAUSE_COPYPRIVATE:
> +      name = "copyprivate";
> +      goto print_remap;
> +    case OMP_CLAUSE_UNIFORM:
> +      name = "uniform";
> +      goto print_remap;
> +    case OMP_CLAUSE_USE_DEVICE_PTR:
> +      name = "use_device_ptr";
> +      if (OMP_CLAUSE_USE_DEVICE_PTR_IF_PRESENT (clause))
> +       modifier = "if_present:";
> +      goto print_remap;
> +    case OMP_CLAUSE_USE_DEVICE_ADDR:
> +      name = "use_device_addr";
> +      goto print_remap;
> +    case OMP_CLAUSE_HAS_DEVICE_ADDR:
> +      name = "has_device_addr";
> +      goto print_remap;
> +    case OMP_CLAUSE_IS_DEVICE_PTR:
> +      name = "is_device_ptr";
> +      goto print_remap;
> +    case OMP_CLAUSE_INCLUSIVE:
> +      name = "inclusive";
> +      goto print_remap;
> +    case OMP_CLAUSE_EXCLUSIVE:
> +      name = "exclusive";
> +      goto print_remap;
> +    case OMP_CLAUSE__LOOPTEMP_:
> +      name = "_looptemp_";
> +      goto print_remap;
> +    case OMP_CLAUSE__REDUCTEMP_:
> +      name = "_reductemp_";
> +      goto print_remap;
> +    case OMP_CLAUSE__CONDTEMP_:
> +      name = "_condtemp_";
> +      goto print_remap;
> +    case OMP_CLAUSE__SCANTEMP_:
> +      name = "_scantemp_";
> +      goto print_remap;
> +    case OMP_CLAUSE_ENTER:
> +      if (OMP_CLAUSE_ENTER_TO (clause))
> +       name = "to";
> +      else
> +       name = "enter";
> +      goto print_remap;
> +    case OMP_CLAUSE_LINK:
> +      name = "link";
> +      goto print_remap;
> +    case OMP_CLAUSE_NONTEMPORAL:
> +      name = "nontemporal";
> +      goto print_remap;
> +  print_remap: //FIX LATER
> +      strcpy(buffer, name);
> +      if (modifier)
> +        strcat(buffer, modifier);
> +      dummy->set (buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_TASK_REDUCTION:
> +    case OMP_CLAUSE_IN_REDUCTION:
> +    case OMP_CLAUSE_REDUCTION:
> +      break;
> +
> +    case OMP_CLAUSE_IF:
> +      strcpy(buffer, "omp_clause_if");
> +      switch (OMP_CLAUSE_IF_MODIFIER (clause))
> +        {
> +        case ERROR_MARK: break;
> +        case VOID_CST: strcat(buffer, "_cancel"); break;
> +        case OMP_PARALLEL: strcat(buffer, "_parallel"); break;
> +        case OMP_SIMD: strcat(buffer, "_simd"); break;
> +        case OMP_TASK: strcat(buffer, "_task"); break;
> +        case OMP_TASKLOOP: strcat(buffer, "_taskloop"); break;
> +        case OMP_TARGET_DATA: strcat(buffer, "_target_data"); break;
> +        case OMP_TARGET: strcat(buffer, "_target"); break;
> +        case OMP_TARGET_UPDATE: strcat(buffer, "_target_update"); break;
> +        case OMP_TARGET_ENTER_DATA: strcat(buffer, "_target_enter_data");
> +          break;
> +        case OMP_TARGET_EXIT_DATA: strcat(buffer, "_target_exit_data"); break;
> +        default: gcc_unreachable ();
> +        }
> +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_IF_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_SELF:
> +      dummy->set("omp_self", node_emit_json (OMP_CLAUSE_SELF_EXPR(clause)));
> +      break;
> +
> +    case OMP_CLAUSE_NUM_THREADS:
> +      dummy->set("omp_num_threads",
> +                 node_emit_json (OMP_CLAUSE_NUM_THREADS_EXPR(clause)));
> +      break;
> +
> +    case OMP_CLAUSE_NOWAIT:
> +      break;
> +
> +    case OMP_CLAUSE_ORDERED:
> +      dummy->set("omp_ordered",
> +                 node_emit_json (OMP_CLAUSE_ORDERED_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_DEFAULT:
> +      strcpy(buffer, "omp_default");
> +      switch (OMP_CLAUSE_DEFAULT_KIND (clause))
> +        {
> +       case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
> +         break;
> +       case OMP_CLAUSE_DEFAULT_SHARED:
> +         strcat (buffer, "_shared");
> +         break;
> +       case OMP_CLAUSE_DEFAULT_NONE:
> +         strcat (buffer, "_none");
> +         break;
> +       case OMP_CLAUSE_DEFAULT_PRIVATE:
> +         strcat (buffer, "_private");
> +         break;
> +       case OMP_CLAUSE_DEFAULT_FIRSTPRIVATE:
> +         strcat (buffer, "_firstprivate");
> +         break;
> +       case OMP_CLAUSE_DEFAULT_PRESENT:
> +         strcat (buffer, "_present");
> +         break;
> +       default:
> +         gcc_unreachable ();
> +        }
> +      dummy->set_bool(buffer, true);
> +      break;
> +
> +    case OMP_CLAUSE_SCHEDULE:
> +      strcpy (buffer, "schedule");
> +      if (OMP_CLAUSE_SCHEDULE_KIND (clause)
> +         & (OMP_CLAUSE_SCHEDULE_MONOTONIC
> +            | OMP_CLAUSE_SCHEDULE_NONMONOTONIC))
> +       {
> +         if (OMP_CLAUSE_SCHEDULE_KIND (clause)
> +             & OMP_CLAUSE_SCHEDULE_MONOTONIC)
> +           strcat (buffer, "_monotonic");
> +         else
> +           strcat (buffer, "_nonmonotonic");
> +       }
> +      if (OMP_CLAUSE_SCHEDULE_SIMD (clause))
> +       strcat (buffer, "_simd");
> +
> +      switch (OMP_CLAUSE_SCHEDULE_KIND (clause) & OMP_CLAUSE_SCHEDULE_MASK)
> +       {
> +       case OMP_CLAUSE_SCHEDULE_STATIC:
> +         strcat (buffer, "_static");
> +         break;
> +       case OMP_CLAUSE_SCHEDULE_DYNAMIC:
> +         strcat (buffer, "_dynamic");
> +         break;
> +       case OMP_CLAUSE_SCHEDULE_GUIDED:
> +         strcat (buffer, "_guided");
> +         break;
> +       case OMP_CLAUSE_SCHEDULE_RUNTIME:
> +         strcat (buffer, "_runtime");
> +         break;
> +       case OMP_CLAUSE_SCHEDULE_AUTO:
> +         strcat (buffer, "_auto");
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +      dummy->set(buffer,
> +                 node_emit_json(OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(clause)));
> +      break;
> +
> +    case OMP_CLAUSE_UNTIED:
> +      dummy->set_bool("omp_clause_untied", true);
> +      break;
> +
> +    case OMP_CLAUSE_COLLAPSE:
> +      dummy->set("omp_collapse_collapse",
> +                 node_emit_json (OMP_CLAUSE_COLLAPSE_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_FINAL:
> +      dummy->set("omp_final",
> +                 node_emit_json (OMP_CLAUSE_FINAL_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_MERGEABLE:
> +      dummy->set_bool("omp_clause_mergeable", true);
> +      break;
> +
> +    case OMP_CLAUSE_LINEAR:
> +      strcpy (buffer, "omp_linear");
> +      if (OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause))
> +       switch (OMP_CLAUSE_LINEAR_KIND (clause))
> +         {
> +         case OMP_CLAUSE_LINEAR_DEFAULT:
> +           break;
> +         case OMP_CLAUSE_LINEAR_REF:
> +           strcat (buffer, "_ref");
> +           break;
> +         case OMP_CLAUSE_LINEAR_VAL:
> +           strcat (buffer, "_val");
> +           break;
> +         case OMP_CLAUSE_LINEAR_UVAL:
> +           strcat (buffer, "_uval");
> +           break;
> +         default:
> +           gcc_unreachable ();
> +         }
> +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> +      if (!OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause)
> +         && OMP_CLAUSE_LINEAR_KIND (clause) != OMP_CLAUSE_LINEAR_DEFAULT)
> +       switch (OMP_CLAUSE_LINEAR_KIND (clause))
> +         {
> +           case OMP_CLAUSE_LINEAR_REF:
> +             strcpy (buffer, "_ref,step");
> +             break;
> +           case OMP_CLAUSE_LINEAR_VAL:
> +             strcpy (buffer, "_val,step");
> +             break;
> +           case OMP_CLAUSE_LINEAR_UVAL:
> +             strcpy (buffer, "_uval,step");
> +             break;
> +           default:
> +             gcc_unreachable ();
> +         }
> +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_LINEAR_STEP (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_ALIGNED:
> +      dummy->set("omp_aligned", node_emit_json (OMP_CLAUSE_DECL(clause)));
> +      if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause))
> +       {
> +          dummy->set("omp_aligned_alignment",
> +                     node_emit_json (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause)));
> +       }
> +      break;
> +
> +    case OMP_CLAUSE_ALLOCATE:
> +      if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause))
> +          dummy->set("omp_allocator",
> +                     node_emit_json (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause)));
> +      if (OMP_CLAUSE_ALLOCATE_ALIGN (clause))
> +          dummy->set("omp_allocate_align",
> +                     node_emit_json (OMP_CLAUSE_ALLOCATE_ALIGN (clause)));
> +      dummy->set("omp_allocate",
> +                 node_emit_json (OMP_CLAUSE_DECL (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_AFFINITY:
> +      {
> +       tree t = OMP_CLAUSE_DECL (clause);
> +       if (TREE_CODE (t) == TREE_LIST
> +           && TREE_PURPOSE (t)
> +           && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
> +         {
> +            omp_iterator_add_json(TREE_PURPOSE (t), dummy);
> +           t = TREE_VALUE (t);
> +         }
> +        dummy->set("omp_affinity", node_emit_json(t));
> +      }
> +      break;
> +
> +    case OMP_CLAUSE_DEPEND:
> +      strcpy (buffer, "omp_depend");
> +      switch (OMP_CLAUSE_DEPEND_KIND (clause))
> +       {
> +       case OMP_CLAUSE_DEPEND_DEPOBJ:
> +         strcat (buffer, "_depobj");
> +         break;
> +       case OMP_CLAUSE_DEPEND_IN:
> +         strcat (buffer, "_in");
> +         break;
> +       case OMP_CLAUSE_DEPEND_OUT:
> +         strcat (buffer, "_out");
> +         break;
> +       case OMP_CLAUSE_DEPEND_INOUT:
> +         strcat (buffer, "_inout");
> +         break;
> +       case OMP_CLAUSE_DEPEND_MUTEXINOUTSET:
> +         strcat (buffer, "_mutexinoutset");
> +         break;
> +       case OMP_CLAUSE_DEPEND_INOUTSET:
> +         strcat (buffer, "_inoutset");
> +         break;
> +       case OMP_CLAUSE_DEPEND_LAST:
> +         strcat (buffer, "__internal__");
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +      {
> +       tree t = OMP_CLAUSE_DECL (clause);
> +       if (TREE_CODE (t) == TREE_LIST
> +           && TREE_PURPOSE (t)
> +           && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
> +         {
> +           omp_iterator_add_json(TREE_PURPOSE (t), dummy);
> +           t = TREE_VALUE (t);
> +         }
> +       if (t == null_pointer_node)
> +         dummy->set_bool("omp_all_memory", true);
> +       else
> +          dummy->set(buffer, node_emit_json(t));
> +      }
> +      break;
> +
> +    case OMP_CLAUSE_DOACROSS:
> +      strcpy (buffer, OMP_CLAUSE_DOACROSS_DEPEND (clause)
> +                    ? "omp_depend" : "omp_doacross");
> +      switch (OMP_CLAUSE_DOACROSS_KIND (clause))
> +       {
> +       case OMP_CLAUSE_DOACROSS_SOURCE:
> +         if (OMP_CLAUSE_DOACROSS_DEPEND (clause))
> +           strcat (buffer, "_source");
> +         else
> +           strcat (buffer, "_source:");
> +          dummy->set_bool(buffer, true);
> +         break;
> +
> +       case OMP_CLAUSE_DOACROSS_SINK:
> +          json::array* iter_holder;
> +          iter_holder = new json::array ();
> +         strcat (buffer, "_sink:");
> +         if (OMP_CLAUSE_DECL (clause) == NULL_TREE)
> +           {
> +             strcat (buffer, "_omp_cur_iteration-1");
> +              dummy->set_bool(buffer, true);
> +             break;
> +           }
> +         for (tree t = OMP_CLAUSE_DECL (clause); t; t = TREE_CHAIN (t))
> +           if (TREE_CODE (t) == TREE_LIST)
> +             {
> +               iter_holder->append(node_emit_json(TREE_VALUE (t)));
> +               if (TREE_PURPOSE (t) != integer_zero_node)
> +                 {
> +                    json::object *_x;
> +                    _x = new json::object ();
> +                   if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (t))
> +                      _x->set("-", node_emit_json(TREE_PURPOSE (t)));
> +                   else
> +                      _x->set("+", node_emit_json(TREE_PURPOSE (t)));
> +                    iter_holder->append(_x);
> +                 }
> +             }
> +           else
> +             gcc_unreachable ();
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +      break;
> +    case OMP_CLAUSE_MAP:
> +      strcat (buffer, "omp_map");
> +      if (OMP_CLAUSE_MAP_READONLY (clause))
> +       strcat (buffer, "_readonly,");
> +      switch (OMP_CLAUSE_MAP_KIND (clause))
> +       {
> +       case GOMP_MAP_ALLOC:
> +       case GOMP_MAP_POINTER:
> +       case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
> +         strcat (buffer, "_alloc");
> +         break;
> +       case GOMP_MAP_IF_PRESENT:
> +         strcat (buffer, "_no_alloc");
> +         break;
> +       case GOMP_MAP_TO:
> +       case GOMP_MAP_TO_PSET:
> +         strcat (buffer, "_to");
> +         break;
> +       case GOMP_MAP_FROM:
> +         strcat (buffer, "_from");
> +         break;
> +       case GOMP_MAP_TOFROM:
> +         strcat (buffer, "_tofrom");
> +         break;
> +       case GOMP_MAP_FORCE_ALLOC:
> +         strcat (buffer, "_force_alloc");
> +         break;
> +       case GOMP_MAP_FORCE_TO:
> +         strcat (buffer, "_force_to");
> +         break;
> +       case GOMP_MAP_FORCE_FROM:
> +         strcat (buffer, "_force_from");
> +         break;
> +       case GOMP_MAP_FORCE_TOFROM:
> +         strcat (buffer, "_force_tofrom");
> +         break;
> +       case GOMP_MAP_FORCE_PRESENT:
> +         strcat (buffer, "_force_present");
> +         break;
> +       case GOMP_MAP_DELETE:
> +         strcat (buffer, "_delete");
> +         break;
> +       case GOMP_MAP_FORCE_DEVICEPTR:
> +         strcat (buffer, "_force_deviceptr");
> +         break;
> +       case GOMP_MAP_ALWAYS_TO:
> +         strcat (buffer, "_always,to");
> +         break;
> +       case GOMP_MAP_ALWAYS_FROM:
> +         strcat (buffer, "_always,from");
> +         break;
> +       case GOMP_MAP_ALWAYS_TOFROM:
> +         strcat (buffer, "_always,tofrom");
> +         break;
> +       case GOMP_MAP_RELEASE:
> +         strcat (buffer, "_release");
> +         break;
> +       case GOMP_MAP_FIRSTPRIVATE_POINTER:
> +         strcat (buffer, "_firstprivate");
> +         break;
> +       case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
> +         strcat (buffer, "_firstprivate ref");
> +         break;
> +       case GOMP_MAP_STRUCT:
> +         strcat (buffer, "_struct");
> +         break;
> +       case GOMP_MAP_STRUCT_UNORD:
> +         strcat (buffer, "_struct_unord");
> +         break;
> +       case GOMP_MAP_ALWAYS_POINTER:
> +         strcat (buffer, "_always_pointer");
> +         break;
> +       case GOMP_MAP_DEVICE_RESIDENT:
> +         strcat (buffer, "_device_resident");
> +         break;
> +       case GOMP_MAP_LINK:
> +         strcat (buffer, "_link");
> +         break;
> +       case GOMP_MAP_ATTACH:
> +         strcat (buffer, "_attach");
> +         break;
> +       case GOMP_MAP_DETACH:
> +         strcat (buffer, "_detach");
> +         break;
> +       case GOMP_MAP_FORCE_DETACH:
> +         strcat (buffer, "_force_detach");
> +         break;
> +       case GOMP_MAP_ATTACH_DETACH:
> +         strcat (buffer, "_attach_detach");
> +         break;
> +       case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
> +         strcat (buffer, "_attach_zero_length_array_section");
> +         break;
> +       case GOMP_MAP_PRESENT_ALLOC:
> +         strcat (buffer, "_present,alloc");
> +         break;
> +       case GOMP_MAP_PRESENT_TO:
> +         strcat (buffer, "_present,to");
> +         break;
> +       case GOMP_MAP_PRESENT_FROM:
> +         strcat (buffer, "_present,from");
> +         break;
> +       case GOMP_MAP_PRESENT_TOFROM:
> +         strcat (buffer, "_present,tofrom");
> +         break;
> +       case GOMP_MAP_ALWAYS_PRESENT_TO:
> +         strcat (buffer, "_always,present,to");
> +         break;
> +       case GOMP_MAP_ALWAYS_PRESENT_FROM:
> +         strcat (buffer, "_always,present,from");
> +         break;
> +       case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
> +         strcat (buffer, "_always,present,tofrom");
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +      dummy->set (buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> +     print_clause_size:
> +      if (OMP_CLAUSE_SIZE (clause))
> +       {
> +         switch (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
> +                 ? OMP_CLAUSE_MAP_KIND (clause) : GOMP_MAP_TO)
> +           {
> +           case GOMP_MAP_POINTER:
> +           case GOMP_MAP_FIRSTPRIVATE_POINTER:
> +           case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
> +           case GOMP_MAP_ALWAYS_POINTER:
> +             strcpy (buffer, "pointer assign, bias");
> +             break;
> +           case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
> +             strcpy (buffer,
> +                     "pointer assign, zero-length array section, bias");
> +             break;
> +           case GOMP_MAP_TO_PSET:
> +             strcpy (buffer, "pointer set, len");
> +             break;
> +           case GOMP_MAP_ATTACH:
> +           case GOMP_MAP_DETACH:
> +           case GOMP_MAP_FORCE_DETACH:
> +           case GOMP_MAP_ATTACH_DETACH:
> +           case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
> +             strcpy (buffer, "bias");
> +             break;
> +           case GOMP_MAP_RELEASE:
> +           case GOMP_MAP_DELETE:
> +             if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
> +                 && OMP_CLAUSE_RELEASE_DESCRIPTOR (clause))
> +               {
> +                 strcpy (buffer, "pointer set, len");
> +                 break;
> +               }
> +             /* Fallthrough.  */
> +           default:
> +             strcpy (buffer, "len");
> +             break;
> +           }
> +          dummy->set (buffer, node_emit_json (OMP_CLAUSE_SIZE (clause)));
> +       }
> +      if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
> +         && OMP_CLAUSE_MAP_RUNTIME_IMPLICIT_P (clause))
> +        dummy->set_bool("implicit", true);
> +      break;
> +
> +    case OMP_CLAUSE_FROM:
> +      strcat (buffer, "omp_from");
> +      if (OMP_CLAUSE_MOTION_PRESENT (clause))
> +       strcat (buffer, "_present");
> +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> +      goto print_clause_size;
> +
> +    case OMP_CLAUSE_TO:
> +      strcpy (buffer, "omp_to");
> +      if (OMP_CLAUSE_MOTION_PRESENT (clause))
> +       strcat (buffer, "_present");
> +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> +      goto print_clause_size;
> +
> +    case OMP_CLAUSE__CACHE_:
> +      strcat (buffer, "omp__cache__");
> +      if (OMP_CLAUSE__CACHE__READONLY (clause))
> +       strcat (buffer, "_readonly");
> +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> +      goto print_clause_size;
> +
> +    case OMP_CLAUSE_NUM_TEAMS:
> +      strcat (buffer, "omp_num_teams");
> +      if (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (clause))
> +       {
> +          dummy->set("omp_num_teams_lower",
> +                     node_emit_json (
> +                         OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (clause)));
> +          strcat (buffer, "_upper");
> +       }
> +      else
> +        dummy->set(buffer,
> +                   node_emit_json (OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_THREAD_LIMIT:
> +      dummy->set("omp_thread_limit",
> +                 node_emit_json (OMP_CLAUSE_THREAD_LIMIT_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_DEVICE:
> +      strcpy (buffer, "omp_device(");
> +      if (OMP_CLAUSE_DEVICE_ANCESTOR (clause))
> +       strcat (buffer, "_ancestor:");
> +      dummy->set(buffer,
> +                 node_emit_json (OMP_CLAUSE_DEVICE_ID (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_DIST_SCHEDULE:
> +      strcat (buffer, "omp_dist_schedule(static)");
> +      if (OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause))
> +       {
> +         dummy->set(buffer,
> +                    node_emit_json (
> +                        OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause)));
> +       }
> +      else
> +        dummy->set_bool(buffer, true);
> +      break;
> +
> +    case OMP_CLAUSE_PROC_BIND:
> +      strcpy (buffer, "omp_proc_bind(");
> +      switch (OMP_CLAUSE_PROC_BIND_KIND (clause))
> +       {
> +       case OMP_CLAUSE_PROC_BIND_MASTER:
> +         strcat (buffer, "_master");
> +         break;
> +       case OMP_CLAUSE_PROC_BIND_CLOSE:
> +         strcat (buffer, "_close");
> +         break;
> +       case OMP_CLAUSE_PROC_BIND_SPREAD:
> +         strcat (buffer, "_spread");
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +      dummy->set_bool(buffer, true);
> +      break;
> +
> +    case OMP_CLAUSE_DEVICE_TYPE:
> +    strcpy (buffer, "omp_device_type");
> +      switch (OMP_CLAUSE_DEVICE_TYPE_KIND (clause))
> +       {
> +       case OMP_CLAUSE_DEVICE_TYPE_HOST:
> +         strcat (buffer, "_host");
> +         break;
> +       case OMP_CLAUSE_DEVICE_TYPE_NOHOST:
> +         strcat (buffer, "_nohost");
> +         break;
> +       case OMP_CLAUSE_DEVICE_TYPE_ANY:
> +         strcat (buffer, "_any");
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +      dummy->set_bool(buffer, true);
> +      break;
> +
> +    case OMP_CLAUSE_SAFELEN:
> +      dummy->set("omp_safelen",
> +                 node_emit_json (OMP_CLAUSE_SAFELEN_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_SIMDLEN:
> +      dummy->set("omp_simdlen",
> +                 node_emit_json (OMP_CLAUSE_SIMDLEN_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_PRIORITY:
> +      dummy->set("omp_priority",
> +                 node_emit_json (OMP_CLAUSE_PRIORITY_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_GRAINSIZE:
> +      strcpy (buffer, "omp_grainsize");
> +      if (OMP_CLAUSE_GRAINSIZE_STRICT (clause))
> +        strcat (buffer, "_strict");
> +      dummy->set(buffer,
> +                 node_emit_json (OMP_CLAUSE_GRAINSIZE_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_NUM_TASKS:
> +      strcpy (buffer, "omp_num_tasks");
> +      if (OMP_CLAUSE_NUM_TASKS_STRICT (clause))
> +       strcat (buffer, "_strict");
> +      dummy->set(buffer,
> +                 node_emit_json (OMP_CLAUSE_NUM_TASKS_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_HINT:
> +      dummy->set("omp_hint",
> +                 node_emit_json (OMP_CLAUSE_HINT_EXPR(clause)));
> +      break;
> +
> +    case OMP_CLAUSE_FILTER:
> +      dummy->set("omp_filter",
> +                 node_emit_json (OMP_CLAUSE_FILTER_EXPR(clause)));
> +      break;
> +
> +    case OMP_CLAUSE_DEFAULTMAP:
> +      strcat (buffer, "omp_defaultmap");
> +      switch (OMP_CLAUSE_DEFAULTMAP_BEHAVIOR (clause))
> +       {
> +       case OMP_CLAUSE_DEFAULTMAP_ALLOC:
> +         strcat (buffer, "_alloc");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_TO:
> +         strcat (buffer, "_to");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_FROM:
> +         strcat (buffer, "_from");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_TOFROM:
> +         strcat (buffer, "_tofrom");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE:
> +         strcat (buffer, "_firstprivate");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_NONE:
> +         strcat (buffer, "_none");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_PRESENT:
> +         strcat (buffer, "_present");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_DEFAULT:
> +         strcat (buffer, "_default");
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +      //Check later if we're happy with this
> +      switch (OMP_CLAUSE_DEFAULTMAP_CATEGORY (clause))
> +       {
> +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED:
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL:
> +         strcat (buffer, ":all");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR:
> +         strcat (buffer, ":scalar");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE:
> +         strcat (buffer, ":aggregate");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALLOCATABLE:
> +         strcat (buffer, ":allocatable");
> +         break;
> +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER:
> +         strcat (buffer, ":pointer");
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +      dummy->set_bool(buffer, true);
> +      break;
> +
> +    case OMP_CLAUSE_ORDER:
> +      strcpy (buffer, "omp_order_");
> +      if (OMP_CLAUSE_ORDER_UNCONSTRAINED (clause))
> +       strcat (buffer, "unconstrained:");
> +      else if (OMP_CLAUSE_ORDER_REPRODUCIBLE (clause))
> +       strcat (buffer, "reproducible:");
> +      strcat (buffer, "concurrent)");
> +      dummy->set_bool(buffer, true);
> +      break;
> +
> +    case OMP_CLAUSE_BIND:
> +      strcpy (buffer, "omp_bind");
> +      switch (OMP_CLAUSE_BIND_KIND (clause))
> +       {
> +       case OMP_CLAUSE_BIND_TEAMS:
> +         strcat (buffer, "_teams");
> +         break;
> +       case OMP_CLAUSE_BIND_PARALLEL:
> +         strcat (buffer, "_parallel");
> +         break;
> +       case OMP_CLAUSE_BIND_THREAD:
> +         strcat (buffer, "_thread");
> +         break;
> +       default:
> +         gcc_unreachable ();
> +       }
> +      dummy->set_bool(buffer, true);
> +      break;
> +
> +    case OMP_CLAUSE__SIMDUID_:
> +      dummy->set("omp__simduid__",
> +                 node_emit_json(OMP_CLAUSE__SIMDUID__DECL (clause)));
> +      break;
> +
> +    case OMP_CLAUSE__SIMT_:
> +      dummy->set_bool("omp__simt__", true);
> +      break;
> +
> +    //In our current implementation, we dump exprs etc even if not NULL.
> +    case OMP_CLAUSE_GANG:
> +      dummy->set_bool ("omp_gang", true);
> +      if (OMP_CLAUSE_GANG_EXPR (clause) != NULL_TREE)
> +          dummy->set("num", node_emit_json (OMP_CLAUSE_GANG_EXPR (clause)));
> +      if (OMP_CLAUSE_GANG_STATIC_EXPR (clause) != NULL_TREE)
> +       {
> +         strcpy (buffer, "static");
> +         if (OMP_CLAUSE_GANG_STATIC_EXPR (clause)
> +             == integer_minus_one_node)
> +           strcat (buffer, "*");
> +          dummy->set(buffer,
> +                     node_emit_json (OMP_CLAUSE_GANG_STATIC_EXPR (clause)));
> +       }
> +      break;
> +
> +    case OMP_CLAUSE_ASYNC:
> +      dummy->set("omp_async",
> +                 node_emit_json (OMP_CLAUSE_ASYNC_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_AUTO:
> +    case OMP_CLAUSE_SEQ:
> +      strcpy (buffer, omp_clause_code_name[OMP_CLAUSE_CODE (clause)]);
> +      dummy->set_bool(buffer, true);
> +      break;
> +
> +    case OMP_CLAUSE_WAIT:
> +      dummy->set("omp_wait",
> +                 node_emit_json (OMP_CLAUSE_WAIT_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_WORKER:
> +      dummy->set("omp_worker",
> +                 node_emit_json (OMP_CLAUSE_WORKER_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_VECTOR:
> +      dummy->set("omp_vector",
> +                 node_emit_json (OMP_CLAUSE_VECTOR_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_NUM_GANGS:
> +      dummy->set("omp_num_gangs",
> +                 node_emit_json (OMP_CLAUSE_NUM_GANGS_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_NUM_WORKERS:
> +      dummy->set("omp_num_workers",
> +                 node_emit_json (OMP_CLAUSE_NUM_WORKERS_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_VECTOR_LENGTH:
> +      dummy->set("omp_vector_length",
> +                 node_emit_json (OMP_CLAUSE_VECTOR_LENGTH_EXPR (clause)));
> +      break;
> +
> +    case OMP_CLAUSE_INBRANCH:
> +      dummy->set_bool ("inbranch", true);
> +      break;
> +    case OMP_CLAUSE_NOTINBRANCH:
> +      dummy->set_bool ("notinbranch", true);
> +      break;
> +    case OMP_CLAUSE_FOR:
> +      dummy->set_bool ("for", true);
> +      break;
> +    case OMP_CLAUSE_PARALLEL:
> +      dummy->set_bool ("parallel", true);
> +      break;
> +    case OMP_CLAUSE_SECTIONS:
> +      dummy->set_bool ("sections", true);
> +      break;
> +    case OMP_CLAUSE_TASKGROUP:
> +      dummy->set_bool ("taskgroup", true);
> +      break;
> +    case OMP_CLAUSE_NOGROUP:
> +      dummy->set_bool ("nogroup", true);
> +      break;
> +    case OMP_CLAUSE_THREADS:
> +      dummy->set_bool ("threads", true);
> +      break;
> +    case OMP_CLAUSE_SIMD:
> +      dummy->set_bool ("simd", true);
> +      break;
> +    case OMP_CLAUSE_INDEPENDENT:
> +      dummy->set_bool ("independent", true);
> +      break;
> +    case OMP_CLAUSE_TILE:
> +      dummy->set ("omp_tile", node_emit_json (OMP_CLAUSE_TILE_LIST (clause)));
> +      break;
> +    case OMP_CLAUSE_PARTIAL:
> +      dummy->set ("omp_partial",
> +                  node_emit_json (OMP_CLAUSE_PARTIAL_EXPR (clause)));
> +      break;
> +    case OMP_CLAUSE_FULL:
> +      dummy->set_bool("full", true);
> +      break;
> +    case OMP_CLAUSE_SIZES:
> +      dummy->set("omp_sizes", node_emit_json (
> +                 OMP_CLAUSE_SIZES_LIST (clause)));
> +      break;
> +    case OMP_CLAUSE_IF_PRESENT:
> +      dummy->set_bool("if_present", true);
> +      break;
> +    case OMP_CLAUSE_FINALIZE:
> +      dummy->set_bool("finalize", true);
> +      break;
> +    case OMP_CLAUSE_NOHOST:
> +      dummy->set_bool("nohost", true);
> +      break;
> +    case OMP_CLAUSE_DETACH:
> +      dummy->set("omp_detach", node_emit_json (OMP_CLAUSE_DECL (clause)));
> +      break;
> +    default:
> +      gcc_unreachable();
> +    }
> +}
> +
> +void
> +omp_atomic_memory_order_add_json (json::object* dummy,
> +                                  enum omp_memory_order mo)
> +{
> +  switch (mo & OMP_MEMORY_ORDER_MASK)
> +    {
> +    case OMP_MEMORY_ORDER_RELAXED:
> +      dummy->set_string ("omp_memory_order", "relaxed");
> +      break;
> +    case OMP_MEMORY_ORDER_SEQ_CST:
> +      dummy->set_string ("omp_memory_order", "seq_cst");
> +      break;
> +    case OMP_MEMORY_ORDER_ACQ_REL:
> +      dummy->set_string ("omp_memory_order", "acq_rel");
> +      break;
> +    case OMP_MEMORY_ORDER_ACQUIRE:
> +      dummy->set_string ("omp_memory_order", "acquire");
> +      break;
> +    case OMP_MEMORY_ORDER_RELEASE:
> +      dummy->set_string ("omp_memory_order", "release");
> +      break;
> +    case OMP_MEMORY_ORDER_UNSPECIFIED:
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +  switch (mo & OMP_FAIL_MEMORY_ORDER_MASK)
> +    {
> +    case OMP_FAIL_MEMORY_ORDER_RELAXED:
> +      dummy->set_string ("omp_memory_order", "fail(relaxed)");
> +      break;
> +    case OMP_FAIL_MEMORY_ORDER_SEQ_CST:
> +      dummy->set_string ("omp_memory_order", "fail(seq_cst)");
> +      break;
> +    case OMP_FAIL_MEMORY_ORDER_ACQUIRE:
> +      dummy->set_string ("omp_memory_order", "fail(acquire)");
> +      break;
> +    case OMP_FAIL_MEMORY_ORDER_UNSPECIFIED:
> +      dummy->set_string ("omp_memory_order", "fail(unspecified)");
> +      break;
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +
> +json::object*
> +omp_atomic_memory_order_emit_json(omp_memory_order mo)
> +{
> +  json::object* _x;
> +  _x = new json::object ();
> +  omp_atomic_memory_order_add_json(_x, mo);
> +  return _x;
> +}
> +
> +json::object*
> +omp_clause_emit_json(tree t)
> +{
> +  json::object* _x;
> +  _x = new json::object ();
> +  omp_clause_add_json(t, _x);
> +  return _x;
> +}
> +
> +json::array*
> +loc_emit_json (expanded_location xloc)
> +{
> +  json::array *loc_holder;
> +  json::object *loc_info;
> +  loc_info = new json::object ();
> +  loc_info->set_string("file", xloc.file);
> +  loc_info->set_integer("line", xloc.line);
> +  loc_info->set_integer("column", xloc.column);
> +  loc_holder = new json::array ();
> +  loc_holder->append(loc_info);
> +  return loc_holder;
> +}
> +
> +/* Here we emit JSON data for a GENERIC node and children.
> + * c.f. dump_generic_node and print-tree's debug_tree().   */
> +
> +json::object*
> +node_emit_json(tree t)
> +{
> +  tree op0, op1, type;
> +  enum tree_code code;
> +  expanded_location xloc;
> +  json::object *dummy;
> +  json::array* holder;
> +  char address_buffer[sizeof(&t)] = {"\0"};
> +
> +  dummy = new json::object ();
> +  holder = new json::array ();
> +
> +  code = TREE_CODE (t);
> +
> +  address_add_json(t, dummy, address_buffer);
> +
> +  if (TREE_CODE_CLASS (code) == tcc_declaration
> +      && code != TRANSLATION_UNIT_DECL)
> +    {
> +    xloc = expand_location (DECL_SOURCE_LOCATION (t));
> +    dummy->set("decl_loc", loc_emit_json(xloc));
> +    }
> +  if (EXPR_HAS_LOCATION(t))
> +    {
> +      xloc = expand_location (EXPR_LOCATION (t));
> +      dummy->set("expr_loc", loc_emit_json(xloc));
> +    }
> +  if (EXPR_HAS_RANGE (t))
> +    {
> +      source_range r = EXPR_LOCATION_RANGE (t);
> +      if (r.m_start)
> +      {
> +        xloc = expand_location (r.m_start);
> +        dummy->set("start_loc", loc_emit_json(xloc));
> +      } else {
> +        dummy->set_string("start_loc", "unknown");
> +      }
> +      if (r.m_finish)
> +      {
> +        xloc = expand_location (r.m_finish);
> +        dummy->set("finish_loc", loc_emit_json(xloc));
> +      } else {
> +        dummy->set_string("finish_loc", "unknown");
> +      }
> +    }
> +  dummy->set_string("tree code", get_tree_code_name(TREE_CODE (t)));
> +  //Flag handling
> +  if (TREE_ADDRESSABLE (t))
> +    dummy->set_bool ("addressable", true);
> +  if (TREE_THIS_VOLATILE (t))
> +    dummy->set_bool ("volatile", true);
> +  if (TREE_ASM_WRITTEN (t))
> +    dummy->set_bool ("asm_written", true);
> +  if (TREE_USED (t))
> +    dummy->set_bool ("used", true);
> +  if (TREE_NOTHROW (t))
> +    dummy->set_bool ("nothrow", true);
> +  if (TREE_PUBLIC (t))
> +    dummy->set_bool ("public", true);
> +  if (TREE_PRIVATE (t))
> +    dummy->set_bool ("private", true);
> +  if (TREE_PROTECTED (t))
> +    dummy->set_bool ("protected", true);
> +  if (TREE_STATIC (t))
> +    dummy->set_bool (code == CALL_EXPR ? " must-tail-call"
> +                                       : " static", true);
> +  if (TREE_DEPRECATED (t))
> +    dummy->set_bool ("deprecated", true);
> +  if (TREE_VISITED (t))
> +    dummy->set_bool ("visited", true);
> +
> +  if (code != TREE_VEC && code != SSA_NAME && code != INTEGER_CST)
> +    {
> +      if (TREE_UNAVAILABLE (t))
> +       dummy->set_bool ("unavailable", true);
> +      if (TREE_LANG_FLAG_0 (t))
> +       dummy->set_bool ("tree_0", true);
> +      if (TREE_LANG_FLAG_1 (t))
> +        dummy->set_bool ("tree_1", true);
> +      if (TREE_LANG_FLAG_2 (t))
> +       dummy->set_bool ("tree_2", true);
> +      if (TREE_LANG_FLAG_3 (t))
> +       dummy->set_bool ("tree_3", true);
> +      if (TREE_LANG_FLAG_4 (t))
> +       dummy->set_bool ("tree_4", true);
> +      if (TREE_LANG_FLAG_5 (t))
> +       dummy->set_bool ("tree_5", true);
> +      if (TREE_LANG_FLAG_6 (t))
> +       dummy->set_bool ("tree_6", true);
> +    }
> +
> +  if (TREE_CODE_CLASS(code) == tcc_declaration)
> +    {
> +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> +        {
> +          if (DECL_UNSIGNED (t))
> +            dummy->set_bool ("unsigned", true);
> +          if (DECL_IGNORED_P (t))
> +            dummy->set_bool ("ignored", true);
> +          if (DECL_ABSTRACT_P (t))
> +            dummy->set_bool ("abstract", true);
> +          if (DECL_EXTERNAL (t))
> +            dummy->set_bool ("external", true);
> +         if (DECL_NONLOCAL (t))
> +           dummy->set_bool ("nonlocal", true);
> +       }
> +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> +        {
> +         if (DECL_WEAK (t))
> +           dummy->set_bool ("weak", true);
> +         if (DECL_IN_SYSTEM_HEADER (t))
> +           dummy->set_bool ("in_system_header", true);
> +        }
> +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)
> +         && code != LABEL_DECL
> +         && code != FUNCTION_DECL
> +         && DECL_REGISTER (t))
> +       dummy->set_bool ("regdecl", true);
> +
> +      if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (t))
> +       dummy->set_bool ("suppress-debug", true);
> +
> +      if (code == FUNCTION_DECL
> +         && DECL_FUNCTION_SPECIFIC_TARGET (t))
> +       dummy->set_bool ("function-specific-target", true);
> +      if (code == FUNCTION_DECL
> +         && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (t))
> +       dummy->set_bool ("function-specific-opt", true);
> +      if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (t))
> +       dummy->set_bool ("autoinline", true);
> +      if (code == FUNCTION_DECL && DECL_UNINLINABLE (t))
> +       dummy->set_bool ("uninlinable", true);
> +      if (code == FUNCTION_DECL && fndecl_built_in_p (t))
> +       dummy->set_bool ("built-in", true);
> +      if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (t))
> +       dummy->set_bool ("static-chain", true);
> +      if (TREE_CODE (t) == FUNCTION_DECL && decl_is_tm_clone (t))
> +       dummy->set_bool ("tm-clone", true);
> +
> +      if (code == FIELD_DECL && DECL_PACKED (t))
> +       dummy->set_bool ("packed", true);
> +      if (code == FIELD_DECL && DECL_BIT_FIELD (t))
> +       dummy->set_bool ("bit-field", true);
> +      if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (t))
> +       dummy->set_bool ("nonaddressable", true);
> +
> +      if (code == LABEL_DECL && EH_LANDING_PAD_NR (t))
> +        dummy->set_integer("landing_pad", EH_LANDING_PAD_NR(t));
> +
> +      if (code == VAR_DECL && DECL_IN_TEXT_SECTION (t))
> +       dummy->set_bool ("in-text-section", true);
> +      if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (t))
> +       dummy->set_bool ("in-constant-pool", true);
> +      if (code == VAR_DECL && DECL_COMMON (t))
> +       dummy->set_bool ("common", true);
> +      if ((code == VAR_DECL || code == PARM_DECL) && DECL_READ_P (t))
> +       dummy->set_bool ("read", true);
> +      if (code == VAR_DECL && DECL_THREAD_LOCAL_P (t))
> +         dummy->set_bool (tls_model_names[DECL_TLS_MODEL (t)], true);
> +
> +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> +       {
> +         if (DECL_VIRTUAL_P (t))
> +           dummy->set_bool ("virtual", true);
> +         if (DECL_PRESERVE_P (t))
> +           dummy->set_bool ("preserve", true);
> +         if (DECL_LANG_FLAG_0 (t))
> +           dummy->set_bool ("decl_0", true);
> +         if (DECL_LANG_FLAG_1 (t))
> +           dummy->set_bool ("decl_1", true);
> +         if (DECL_LANG_FLAG_2 (t))
> +           dummy->set_bool ("decl_2", true);
> +         if (DECL_LANG_FLAG_3 (t))
> +           dummy->set_bool ("decl_3", true);
> +         if (DECL_LANG_FLAG_4 (t))
> +           dummy->set_bool ("decl_4", true);
> +         if (DECL_LANG_FLAG_5 (t))
> +           dummy->set_bool ("decl_5", true);
> +         if (DECL_LANG_FLAG_6 (t))
> +           dummy->set_bool ("decl_6", true);
> +         if (DECL_LANG_FLAG_7 (t))
> +           dummy->set_bool ("decl_7", true);
> +         if (DECL_LANG_FLAG_8 (t))
> +           dummy->set_bool ("decl_8", true);
> +
> +         dummy->set_string("mode", GET_MODE_NAME (DECL_MODE (t)));
> +       }
> +
> +
> +      if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
> +         && DECL_BY_REFERENCE (t))
> +       dummy->set_bool ("passed-by-reference", true);
> +
> +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)
> +                                && DECL_DEFER_OUTPUT (t))
> +       dummy->set_bool ("defer-output", true);
> +
> +    } //end tcc_decl flags
> +
> +    if (TREE_CODE_CLASS(code) == tcc_type)
> +      {
> +      if (TYPE_UNSIGNED (t))
> +       dummy->set_bool ("unsigned", true);
> +
> +      if (TYPE_NO_FORCE_BLK (t))
> +       dummy->set_bool ("no-force-blk", true);
> +
> +      if (code == ARRAY_TYPE && TYPE_STRING_FLAG (t))
> +       dummy->set_bool ("string-flag", true);
> +
> +      if (TYPE_NEEDS_CONSTRUCTING (t))
> +       dummy->set_bool ("needs-constructing", true);
> +
> +      if ((code == RECORD_TYPE
> +          || code == UNION_TYPE
> +          || code == QUAL_UNION_TYPE
> +          || code == ARRAY_TYPE)
> +         && TYPE_REVERSE_STORAGE_ORDER (t))
> +       dummy->set_bool ("reverse-storage-order", true);
> +
> +      if ((code == RECORD_TYPE
> +          || code == UNION_TYPE)
> +         && TYPE_CXX_ODR_P (t))
> +       dummy->set_bool ("cxx-odr-p", true);
> +
> +      if ((code == RECORD_TYPE
> +          || code == UNION_TYPE)
> +         && TYPE_CXX_ODR_P (t))
> +       dummy->set_bool ("cxx-odr-p", true);
> +
> +      if ((code == RECORD_TYPE
> +          || code == UNION_TYPE)
> +         && TYPE_INCLUDES_FLEXARRAY (t))
> +       dummy->set_bool ("includes-flexarray", true);
> +
> +      if ((code == UNION_TYPE || code == RECORD_TYPE)
> +         && TYPE_TRANSPARENT_AGGR (t))
> +       dummy->set_bool ("transparent-aggr", true);
> +      else if (code == ARRAY_TYPE
> +              && TYPE_NONALIASED_COMPONENT (t))
> +       dummy->set_bool ("nonaliased-component", true);
> +
> +      if (TYPE_PACKED (t))
> +       dummy->set_bool ("packed", true);
> +
> +      if (TYPE_RESTRICT (t))
> +       dummy->set_bool ("restrict", true);
> +
> +      if (TYPE_LANG_FLAG_0 (t))
> +       dummy->set_bool ("type_0", true);
> +      if (TYPE_LANG_FLAG_1 (t))
> +       dummy->set_bool ("type_1", true);
> +      if (TYPE_LANG_FLAG_2 (t))
> +       dummy->set_bool ("type_2", true);
> +      if (TYPE_LANG_FLAG_3 (t))
> +       dummy->set_bool ("type_3", true);
> +      if (TYPE_LANG_FLAG_4 (t))
> +       dummy->set_bool ("type_4", true);
> +      if (TYPE_LANG_FLAG_5 (t))
> +       dummy->set_bool ("type_5", true);
> +      if (TYPE_LANG_FLAG_6 (t))
> +       dummy->set_bool ("type_6", true);
> +      if (TYPE_LANG_FLAG_7 (t))
> +       dummy->set_bool ("type_7", true);
> +      } //end tcc_type flags
> +
> +  // Accessors
> +  switch (code)
> +  {
> +    case IDENTIFIER_NODE:
> +      dummy->set_string("identifier",
> +                        identifier_to_locale ((IDENTIFIER_POINTER(t))));
> +      break;
> +    case TREE_LIST:
> +      while (t && t != error_mark_node)
> +      {
> +        if (TREE_PURPOSE (t))
> +       {
> +          holder->append(node_emit_json(TREE_PURPOSE(t)));
> +       }
> +       holder->append(node_emit_json(TREE_VALUE(t)));
> +        t = TREE_CHAIN(t);
> +      }
> +      break;
> +    case TREE_BINFO:
> +      holder->append(node_emit_json(BINFO_TYPE(t)));
> +      break;
> +    case TREE_VEC:
> +      {
> +        size_t i;
> +        if (TREE_VEC_LENGTH(t) > 0)
> +         {
> +            size_t len = TREE_VEC_LENGTH (t);
> +           for (i = 0; i < len ; i++)
> +           {
> +             holder->append(node_emit_json(TREE_VEC_ELT(t, i)));
> +           }
> +         }
> +      }
> +      break;
> +
> +    case VOID_TYPE:
> +    case INTEGER_TYPE:
> +    case REAL_TYPE:
> +    case FIXED_POINT_TYPE:
> +    case COMPLEX_TYPE:
> +    case VECTOR_TYPE:
> +    case ENUMERAL_TYPE:
> +    case BOOLEAN_TYPE:
> +    case BITINT_TYPE:
> +    case OPAQUE_TYPE:
> +      {
> +       unsigned int quals = TYPE_QUALS (t);
> +       enum tree_code_class tclass;
> +        json::object* _x;
> +
> +        _x = new json::object ();
> +
> +       if (quals & TYPE_QUAL_ATOMIC)
> +         _x->set_bool("atomic", true);
> +       if (quals & TYPE_QUAL_CONST)
> +         _x->set_bool("const", true);
> +       if (quals & TYPE_QUAL_VOLATILE)
> +         _x->set_bool("volatile", true);
> +       if (quals & TYPE_QUAL_RESTRICT)
> +         _x->set_bool("restrict", true);
> +
> +        dummy->set("quals", _x);
> +
> +       if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t)))
> +           dummy->set_integer("address space", TYPE_ADDR_SPACE(t));
> +
> +       tclass = TREE_CODE_CLASS (TREE_CODE(t));
> +
> +       if (tclass == tcc_declaration)
> +         {
> +         if (DECL_NAME (t))
> +            decl_node_add_json(t, dummy);
> +         else
> +           dummy->set_string("decl", "<unnamed type decl>");
> +         }
> +       else if (tclass == tcc_type)
> +         {
> +           if (TYPE_NAME (t))
> +           {
> +             if (TREE_CODE(TYPE_NAME (t)) == IDENTIFIER_NODE)
> +                dummy->set("identifier", node_emit_json(TYPE_NAME(t)));
> +             else if (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
> +                      && DECL_NAME (TYPE_NAME (t)))
> +                decl_node_add_json( TYPE_NAME (t), dummy);
> +             else
> +                dummy->set_string("type_name", "unnamed");
> +           }
> +            else if (TREE_CODE (t) == VECTOR_TYPE)
> +             {
> +              for (long unsigned int i = 0; i < NUM_POLY_INT_COEFFS; i++)
> +                {
> +                  auto _poly_int = TYPE_VECTOR_SUBPARTS(t);
> +                  dummy->set_integer("foo", _poly_int.coeffs[i]);
> +                }
> +              dummy->set("vector_subparts", holder);
> +             }
> +            else if (TREE_CODE (t) == INTEGER_TYPE)
> +             {
> +               if (TYPE_PRECISION (t) == CHAR_TYPE_SIZE)
> +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> +                                                  ? "unsigned char"
> +                                                  : "signed char"));
> +               else if (TYPE_PRECISION (t) == SHORT_TYPE_SIZE)
> +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> +                                                  ? "unsigned short"
> +                                                  : "signed short"));
> +               else if (TYPE_PRECISION (t) == INT_TYPE_SIZE)
> +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> +                                                  ? "unsigned int"
> +                                                  : "signed int"));
> +               else if (TYPE_PRECISION (t) == LONG_TYPE_SIZE)
> +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> +                                                  ? "unsigned long"
> +                                                  : "signed long"));
> +               else if (TYPE_PRECISION (t) == LONG_LONG_TYPE_SIZE)
> +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> +                                                  ? "unsigned long long"
> +                                                  : "signed long long"));
> +               else if (TYPE_PRECISION (t) == CHAR_TYPE_SIZE
> + && pow2p_hwi (TYPE_PRECISION (t)))
> +                   dummy->set_integer(TYPE_UNSIGNED(t) ? "uint": "int",
> +                                      TYPE_PRECISION(t));
> +               else
> +                   dummy->set_integer(TYPE_UNSIGNED(t)
> +                                     ? "unnamed-unsigned"
> +                                     : "unnamed-signed", TYPE_PRECISION(t));
> +             }
> +           else if (TREE_CODE (t) == COMPLEX_TYPE)
> +             {
> +               holder->append(node_emit_json(TREE_TYPE(t)));
> +                dummy->set("complex", holder);
> +             }
> +           else if (TREE_CODE (t) == REAL_TYPE)
> +             {
> +               dummy->set_integer("float", TYPE_PRECISION(t));
> +             }
> +           else if (TREE_CODE (t) == FIXED_POINT_TYPE)
> +             {
> +               dummy->set_integer("fixed point", TYPE_PRECISION(t));
> +             }
> +           else if (TREE_CODE (t) == BOOLEAN_TYPE)
> +             {
> +               dummy->set_integer(TYPE_UNSIGNED(t)
> +                                  ? "unsigned boolean"
> +                                  : "signed boolean", TYPE_PRECISION(t));
> +             }
> +           else if (TREE_CODE (t) == BITINT_TYPE)
> +             {
> +               dummy->set_integer(TYPE_UNSIGNED (t)
> +                                  ? "unsigned_BitInt"
> +                                  : "_BitInt", TYPE_PRECISION(t));
> +             }
> +           else if (TREE_CODE (t) == VOID_TYPE)
> +             dummy->set_bool("float", true);
> +           else
> +             dummy->set_bool("unnamed type", true);
> +          }
> +      }
> +      break;
> +
> +    case POINTER_TYPE:
> +    case REFERENCE_TYPE:
> +      {
> +        if (TREE_TYPE (t) == NULL)
> +         dummy->set_bool("null type", true);
> +        else if (TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
> +          {
> +            tree function_node = TREE_TYPE(t);
> +           tree arg_node = TYPE_ARG_TYPES(function_node);
> +           json::array* args_holder;
> +           json::object* it_args;
> +           json::object* _id;
> +
> +           args_holder = new json::array ();
> +           _id = new json::object ();
> +
> +            dummy->set("fnode", node_emit_json(function_node));
> +
> +           if (TYPE_IDENTIFIER (t))
> +             _id->set("type identifier", node_emit_json(TYPE_NAME(t)));
> +            else
> +              {
> +                char* buff;
> +                buff = new char ();
> +                print_hex(TYPE_UID(t), buff);
> +               _id->set_string("uid", buff);
> +              }
> +            dummy->set("function decl",
> +                       function_decl_emit_json(function_node));
> +            if (arg_node && arg_node != void_list_node
> +                && arg_node != error_mark_node)
> +             it_args = new json::object();
> +            while (arg_node && arg_node != void_list_node
> +                   && arg_node != error_mark_node)
> +             {
> +               it_args = node_emit_json(arg_node);
> +               args_holder->append(it_args);
> +               arg_node = TREE_CHAIN (arg_node);
> +             }
> +           dummy->set("type_uid", _id);
> +           dummy->set("args", args_holder);
> +          }
> +        else
> +          {
> +         unsigned int quals = TYPE_QUALS (t);
> +         dummy->set("tree_type", node_emit_json(TREE_TYPE(t)));
> +         json::object *_x;
> +
> +          _x = new json::object ();
> +
> +         if (quals & TYPE_QUAL_ATOMIC)
> +           _x->set_bool("atomic", true);
> +         if (quals & TYPE_QUAL_CONST)
> +           _x->set_bool("const", true);
> +         if (quals & TYPE_QUAL_VOLATILE)
> +           _x->set_bool("volatile", true);
> +         if (quals & TYPE_QUAL_RESTRICT)
> +           _x->set_bool("restrict", true);
> +
> +          dummy->set("quals", _x);
> +         if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t)))
> +           dummy->set_integer("address space", TYPE_ADDR_SPACE (t));
> +         if (TYPE_REF_CAN_ALIAS_ALL (t))
> +           dummy->set_bool("ref can alias all", true);
> +          }
> +      }
> +      break;
> +
> +    case OFFSET_TYPE:
> +      break;
> +
> +    case MEM_REF:
> +    case TARGET_MEM_REF:
> +      {
> +        if (TREE_CODE (t) == MEM_REF
> +            && integer_zerop (TREE_OPERAND (t, 1))
> +            && TREE_CODE (TREE_OPERAND (t, 0)) != INTEGER_CST
> +            && TREE_TYPE (TREE_OPERAND (t, 0)) != NULL_TREE
> +            && (TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)))
> +                == TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 1))))
> +            && (TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0)))
> +                == TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 1))))
> +            && (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (t, 0)))
> +                == TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (t, 1))))
> +            && (TYPE_MAIN_VARIANT (TREE_TYPE (t))
> +                == TYPE_MAIN_VARIANT (
> +                       TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 1))))))
> +          {
> +            if (TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR)
> +              {
> +                dummy->set("base", node_emit_json(TREE_OPERAND (t, 0)));
> +              }
> +            else
> +              dummy->set("base", node_emit_json(
> +                                     TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
> +          }
> +        else
> +          { //Check later
> +            tree type = TREE_TYPE(t);
> +            tree op1 = TREE_OPERAND(t, 1);
> +            tree op1type = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
> +
> +            tree op0size = TYPE_SIZE(type);
> +            tree op1size = TYPE_SIZE (TREE_TYPE(op1type));
> +
> +            if (!op0size || !op1size
> +                || ! operand_equal_p(op0size, op1size, 0))
> +            {
> +              dummy->set("tree_type_size", node_emit_json(type));
> +            }
> +            dummy->set("op1_type_size", node_emit_json(op1type));
> +
> +            if (!integer_zerop (op1))
> +              dummy->set("offset", node_emit_json(op1));
> +            if (TREE_CODE(t) == TARGET_MEM_REF)
> +              {
> +                tree temp = TMR_INDEX2 (t);
> +                if (temp)
> +                  dummy->set("tmr_index2", node_emit_json(temp));
> +                temp = TMR_INDEX (t);
> +                if (temp)
> +                  {
> +                    dummy->set("tmr_index", node_emit_json(temp));
> +                    temp = TMR_STEP(t);
> +                    if (temp)
> +                      dummy->set("tmr_step", node_emit_json(temp));
> +                  }
> +              }
> +          }
> +        if (MR_DEPENDENCE_CLIQUE (t) != 0)
> +          {
> +            dummy->set_integer("clique", MR_DEPENDENCE_CLIQUE(t));
> +            dummy->set_integer("base", MR_DEPENDENCE_BASE(t));
> +          }
> +      }
> +    break;
> +
> +    /* FIXME : As in tree-pretty-print.cc, the following four codes are
> +     *         incomplete. See print_struct_decl therein the above. */
> +    case ARRAY_TYPE:
> +      {
> +        unsigned int quals = TYPE_QUALS (t);
> +       if (quals & TYPE_QUAL_ATOMIC)
> +         dummy->set_bool("atomic", true);
> +       if (quals & TYPE_QUAL_CONST)
> +         dummy->set_bool("const", true);
> +       if (quals & TYPE_QUAL_VOLATILE)
> +         dummy->set_bool("volatile", true);
> +      }
> +      break;
> +    case RECORD_TYPE:
> +    case UNION_TYPE:
> +    case QUAL_UNION_TYPE:
> +      {
> +        unsigned int quals = TYPE_QUALS (t);
> +        json::object *_x;
> +
> +        _x = new json::object ();
> +
> +        if (quals & TYPE_QUAL_ATOMIC)
> +          _x->set_bool("atomic", true);
> +        if (quals & TYPE_QUAL_CONST)
> +          _x->set_bool("const", true);
> +        if (quals & TYPE_QUAL_VOLATILE)
> +          _x->set_bool("volatile", true);
> +
> +        dummy->set("type_quals", _x);
> +
> +        if (TYPE_NAME(t))
> +          dummy->set("type_name", node_emit_json(TYPE_NAME(t)));
> +      }
> +      break;
> +    case LANG_TYPE:
> +      break;
> +    case INTEGER_CST:
> +      {
> +        dummy->set_bool("integer_cst", true);
> +
> +        if ((POINTER_TYPE_P (TREE_TYPE (t)))
> +            || (TYPE_PRECISION (TREE_TYPE (t))
> +                < TYPE_PRECISION (integer_type_node))
> +            || exact_log2 (TYPE_PRECISION (TREE_TYPE (t))) == -1
> +            || tree_int_cst_sgn (t) < 0)
> +          {
> +            holder->append( node_emit_json (TREE_TYPE(t)));
> +            dummy->set("_Literal", holder);
> +          }
> +        if (TREE_CODE (TREE_TYPE(t)) == POINTER_TYPE)
> +          {
> +            // In bytes
> +            dummy->set_bool("pointer", true);
> +            dummy->set_integer("val", TREE_INT_CST_LOW(t));
> +          }
> +        else if (tree_fits_shwi_p(t))
> +          dummy->set_integer("val", tree_to_shwi (t));
> +        else if (tree_fits_uhwi_p(t))
> +          dummy->set_integer("val", tree_to_uhwi (t));
> +        else
> +          {
> +            wide_int val = wi::to_wide (t);
> +            char buff[WIDE_INT_PRINT_BUFFER_SIZE];
> +
> +            print_dec(wi::to_wide (t), buff, TYPE_SIGN (TREE_TYPE (t)));
> +            dummy->set_string("val", buff);
> +        }
> +      if (TREE_OVERFLOW (t))
> +        dummy->set_bool("overflow", true);
> +      }
> +      break;
> +
> +    case POLY_INT_CST:
> +      for (unsigned int i = 1; i < NUM_POLY_INT_COEFFS; i++)
> +        holder->append(node_emit_json(POLY_INT_CST_COEFF(t, i)));
> +      dummy->set("poly_int_cst", holder);
> +      break;
> +
> +    case REAL_CST:
> +      {
> +        REAL_VALUE_TYPE d;
> +
> +        d = TREE_REAL_CST (t);
> +
> +        if (TREE_OVERFLOW (t))
> +          dummy->set_bool("overflow", true);
> +
> +        if (REAL_VALUE_ISINF (d))
> +          dummy->set_string("value", REAL_VALUE_NEGATIVE(d) ? "-Inf" : "Inf");
> +        else if (REAL_VALUE_ISNAN(d))
> +          dummy->set_string("value", "NaN");
> +        else
> +          {
> +            char string[100];
> +            real_to_decimal(string, &d, sizeof (string), 0, 1);
> +            dummy->set_string("real_value", string);
> +          }
> +      }
> +      break;
> +
> +    case FIXED_CST:
> +      {
> +        char string[100];
> +        fixed_to_decimal(string, TREE_FIXED_CST_PTR(t), sizeof (string));
> +        dummy->set_string("fixed_cst", string);
> +      }
> +      break;
> +
> +    case STRING_CST:
> +        dummy->set_string("string_cst", TREE_STRING_POINTER(t));
> +        break;
> +
> +    case VECTOR_CST:
> +      {
> +        unsigned int i;
> +        unsigned HOST_WIDE_INT nunits;
> +
> +        if (!VECTOR_CST_NELTS (t).is_constant (&nunits))
> +          nunits = vector_cst_encoded_nelts (t);
> +        for (i = 0; i < nunits; i++)
> +          {
> +            holder->append(node_emit_json(VECTOR_CST_ELT (t, i)));
> +          }
> +        dummy->set("vector_cst", holder);
> +      }
> +      break;
> +
> +    case FUNCTION_TYPE:
> +    case METHOD_TYPE:
> +      dummy->set("type_data", node_emit_json(TREE_TYPE (t)));
> +
> +      if (TREE_CODE (t) == METHOD_TYPE)
> +        {
> +          dummy->set_bool("method_type", true);
> +          if (TYPE_METHOD_BASETYPE (t))
> +            dummy->set("basetype", node_emit_json (
> +                                       TYPE_NAME (TYPE_METHOD_BASETYPE(t))));
> +          else
> +            dummy->set_string("basetype", "null method basetype");
> +        }
> +      if (TYPE_IDENTIFIER (t))
> +        dummy->set("type_identifier", node_emit_json (TYPE_NAME(t)));
> +      else if ( TYPE_NAME (t) && DECL_NAME (TYPE_NAME (t)) )
> +        decl_node_add_json( TYPE_NAME(t), dummy);
> +      else //TDF_NOUID
> +        {
> +          char* buff;
> +          buff = new char ();
> +          print_hex(TYPE_UID(t), buff);
> +         dummy->set_string("uid", buff);
> +        }
> +      dummy->set("function_decl", function_decl_emit_json(t));
> +      break;
> +
> +
> +    case FUNCTION_DECL:
> +    case CONST_DECL:
> +      decl_node_add_json(t, dummy);
> +      break;
> +    case LABEL_DECL:
> +      if (DECL_NAME (t))
> +        decl_node_add_json(t, dummy);
> +      else if (LABEL_DECL_UID (t) != -1)
> +        dummy->set_integer("LabelDeclUID", LABEL_DECL_UID (t));
> +      else
> +        dummy->set_integer("DeclUID", DECL_UID(t));
> +      break;
> +
> +    case TYPE_DECL:
> +      if (DECL_IS_UNDECLARED_BUILTIN (t)) //parity w/ dump_generic_node
> +        break;
> +      if (DECL_NAME (t))
> +        decl_node_add_json(t, dummy);
> +      else if (TYPE_NAME (TREE_TYPE (t)) != t)
> +        {
> +          dummy->set(TREE_CODE (TREE_TYPE (t)) == UNION_TYPE ? "union"
> +                                                             : "struct",
> +                     node_emit_json( TREE_TYPE (t)));
> +        }
> +      else
> +        dummy->set_bool("anon_type_decl", true);
> +      break;
> +
> +    case VAR_DECL:
> +    case PARM_DECL:
> +    case FIELD_DECL:
> +    case DEBUG_EXPR_DECL:
> +    case NAMESPACE_DECL:
> +    case NAMELIST_DECL:
> +      decl_node_add_json(t, dummy);
> +      break;
> +
> +    case RESULT_DECL:
> +      dummy->set_bool("retval", true);
> +      break;
> +
> +    case COMPONENT_REF:
> +      op0 = TREE_OPERAND (t, 0);
> +      op1 = TREE_OPERAND (t, 1);
> +      if (op0
> +          && (TREE_CODE (op0) == INDIRECT_REF
> +              || (TREE_CODE (op0) == MEM_REF
> +                  && TREE_CODE (TREE_OPERAND (op0, 0)) != ADDR_EXPR
> +                  && integer_zerop (TREE_OPERAND (op0, 1))
> +                  //We want to be explicit about Integer_CSTs
> +                  && TREE_CODE (TREE_OPERAND (op0, 0)) != INTEGER_CST
> +                  // To play nice with SSA
> +                  && TREE_TYPE (TREE_OPERAND (op0, 0)) != NULL_TREE
> +                  // I don't understand what the qualm is here
> +                  && (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0)))
> +                      == (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
> +                  && (TYPE_MODE (TREE_TYPE (TREE_OPERAND (op0, 0)))
> +                      == (TYPE_MODE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
> +                  && (TYPE_REF_CAN_ALIAS_ALL (
> +                          TREE_TYPE (TREE_OPERAND (op0, 0)))
> +                      == (TYPE_REF_CAN_ALIAS_ALL (
> +                              TREE_TYPE (TREE_OPERAND (op0, 1)))))
> +                  // Understand this later too
> +                  && (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
> +                      == TYPE_MAIN_VARIANT (
> +                             TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
> +                  && MR_DEPENDENCE_CLIQUE (op0) == 0)))
> +        {
> +          //
> +          op0 = TREE_OPERAND (op0, 0);
> +        }
> +      dummy->set("expr", node_emit_json(op0));
> +      dummy->set("field", node_emit_json(op1));
> +      if (DECL_P (op1))
> +        if (tree off = component_ref_field_offset(t))
> +          if (TREE_CODE (off) != INTEGER_CST)
> +            {
> +              dummy->set("offset", node_emit_json(off));
> +            }
> +    break;
> +
> +    case BIT_FIELD_REF:
> +      dummy->set_string("tree_code", "bit_field_ref");
> +      dummy->set("expr",
> +                 node_emit_json( TREE_OPERAND (t, 0)));
> +      dummy->set("bits_ref",
> +                 node_emit_json( TREE_OPERAND (t, 1)));
> +      dummy->set("bits_first_pos",
> +                 node_emit_json( TREE_OPERAND (t, 2)));
> +      break;
> +
> +    case BIT_INSERT_EXPR:
> +      dummy->set_string("tree_code", "bit_insert_expr");
> +      dummy->set("container",
> +                 node_emit_json( TREE_OPERAND (t, 0)));
> +      dummy->set("replacement",
> +                 node_emit_json( TREE_OPERAND (t, 1)));
> +      dummy->set("constant_bit_pos",
> +                 node_emit_json( TREE_OPERAND (t, 2)));
> +      break;
> +
> +    case ARRAY_REF:
> +    case ARRAY_RANGE_REF:
> +      op0 = TREE_OPERAND (t, 0);
> +      dummy->set("array",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("index",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      if (TREE_OPERAND(t, 2))
> +        dummy->set("type_min_val",
> +                   node_emit_json (TREE_OPERAND (t, 2)));
> +      if (TREE_OPERAND(t, 3))
> +        dummy->set("element_size",
> +                   node_emit_json (TREE_OPERAND (t, 3)));
> +      break;
> +
> +    case OMP_ARRAY_SECTION:
> +      dummy->set("op0",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("op1",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      dummy->set("op2",
> +                 node_emit_json (TREE_OPERAND (t, 2)));
> +      break;
> +
> +    case CONSTRUCTOR:
> +      {
> +        unsigned HOST_WIDE_INT ix;
> +        tree field, val;
> +        bool is_struct_init = false;
> +        bool is_array_init = false;
> +        widest_int curidx;
> +
> +        if (TREE_CLOBBER_P (t))
> +          switch (CLOBBER_KIND(t))
> +            {
> +          case CLOBBER_STORAGE_BEGIN:
> +              dummy->set_string("CLOBBER", "storage_begin");
> +              break;
> +            case CLOBBER_STORAGE_END:
> +              dummy->set_bool("CLOBBER", "storage_end");
> +              break;
> +            case CLOBBER_OBJECT_BEGIN:
> +              dummy->set_bool("CLOBBER", "object_begin");
> +              break;
> +            case CLOBBER_OBJECT_END:
> +              dummy->set_bool("CLOBBER", "object_end");
> +              break;
> +            default:
> +              break;
> +          }
> +        else if (TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE
> +                 || TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
> +          is_struct_init = true;
> +        else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE
> +                 && TYPE_DOMAIN (TREE_TYPE (t))
> +                 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t))))
> +                    == INTEGER_CST)
> +          {
> +            tree minv = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
> +            is_array_init = true;
> +            curidx = wi::to_widest (minv);
> +          }
> +        FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), ix, field, val)
> +          {
> +            json::object* cst_elt;
> +            json::object* _val_json;
> +            cst_elt = new json::object ();
> +            cst_elt->set_integer("", ix); //fix
> +            if (field)
> +              {
> +                if (is_struct_init)
> +                  cst_elt->set("field", node_emit_json(field));
> +                else if (is_array_init
> +                         && (TREE_CODE (field) != INTEGER_CST
> +                             || curidx != wi::to_widest (field)))
> +                  {
> +                    json::array* _array_init_json;
> +                    if (TREE_CODE (field) == RANGE_EXPR)
> +                      {
> +                        _array_init_json = new json::array ();
> +                        _array_init_json->append(node_emit_json(
> +                                                     TREE_OPERAND(field, 0)));
> +                        _array_init_json->append(node_emit_json(
> +                                                     TREE_OPERAND(field, 1)));
> +                        cst_elt->set("field", _array_init_json);
> +                      }
> +                    else
> +                      cst_elt->set ("field", node_emit_json (field));
> +                  }
> +              }
> +            if (is_array_init)
> +              curidx += 1;
> +            if (val && TREE_CODE (val) == ADDR_EXPR)
> +              if (TREE_CODE (TREE_OPERAND (val, 0)) == FUNCTION_DECL)
> +                val = TREE_OPERAND (val, 0);
> +            if (val && TREE_CODE (val) == FUNCTION_DECL)
> +              {
> +                _val_json = new json::object ();
> +                decl_node_add_json (val, _val_json);
> +                cst_elt->set("val", _val_json);
> +              }
> +            else
> +              cst_elt->set("val", node_emit_json(val));
> +
> +            if (TREE_CODE (field) == INTEGER_CST)
> +              curidx = wi::to_widest (field);
> +            holder->append(cst_elt);
> +          }
> +        dummy->set("ctor_elts", holder);
> +      }
> +    break;
> +
> +   case COMPOUND_EXPR:
> +     {
> +        tree *tp;
> +        holder->append( node_emit_json( TREE_OPERAND (t, 0)));
> +
> +        for (tp = &TREE_OPERAND (t, 1);
> +             TREE_CODE (*tp) == COMPOUND_EXPR;
> +             tp = &TREE_OPERAND (*tp, 1))
> +          {
> +          holder->append( node_emit_json ( TREE_OPERAND (*tp, 0)));
> +          }
> +
> +        dummy->set("compound_expr", holder);
> +      }
> +      break;
> +
> +    case STATEMENT_LIST:
> +      {
> +        tree_stmt_iterator si;
> +
> +        for (si =  tsi_start (t); !tsi_end_p (si); tsi_next (&si))
> +          {
> +            holder->append( node_emit_json (tsi_stmt (si)));
> +          }
> +        dummy->set("statement_list", holder);
> +      }
> +      break;
> +
> +    case MODIFY_EXPR:
> +    case INIT_EXPR:
> +      dummy->set("op0",
> +                 node_emit_json( TREE_OPERAND (t, 0)));
> +      dummy->set("op1",
> +                 node_emit_json( TREE_OPERAND (t, 1)));
> +      break;
> +
> +    case TARGET_EXPR:
> +      dummy->set("slot", node_emit_json (TARGET_EXPR_SLOT(t)));
> +      dummy->set("initial", node_emit_json (TARGET_EXPR_INITIAL(t)));
> +      break;
> +
> +    case DECL_EXPR:
> +      decl_node_add_json(DECL_EXPR_DECL(t), dummy);
> +      break;
> +
> +    case COND_EXPR:
> +      dummy->set("if",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      if (COND_EXPR_THEN(t))
> +      {
> +        dummy->set("then",
> +                   node_emit_json (TREE_OPERAND (t, 1)));
> +      }
> +      if (COND_EXPR_ELSE(t))
> +      {
> +        dummy->set("else",
> +                 node_emit_json (TREE_OPERAND (t, 2)));
> +      }
> +      break;
> +
> +    case BIND_EXPR:
> +      if (BIND_EXPR_VARS (t))
> +        {
> +          for (op0 = BIND_EXPR_VARS (t); op0; op0 = DECL_CHAIN (op0))
> +            {
> +              holder->append(node_emit_json (op0));
> +            }
> +          dummy->set("bind_expr_vars", holder);
> +        }
> +      dummy->set("bind_expr_body",
> +                 node_emit_json(BIND_EXPR_BODY(t)));
> +      break;
> +
> +    case CALL_EXPR:
> +      {
> +        if (CALL_EXPR_FN (t) != NULL_TREE)
> +          call_name_add_json (CALL_EXPR_FN(t), dummy);
> +        else
> +          dummy->set_string("internal_fn",
> +                            internal_fn_name (CALL_EXPR_IFN (t)));
> +        dummy->set_bool("return_slot_optimization",
> +                        CALL_EXPR_RETURN_SLOT_OPT(t));
> +        dummy->set_bool("tail_call", CALL_EXPR_TAILCALL(t));
> +
> +        tree arg;
> +        call_expr_arg_iterator iter;
> +        bool call;
> +        FOR_EACH_CALL_EXPR_ARG(arg, iter, t)
> +          {
> +            call = true;
> +            holder->append(node_emit_json(arg));
> +          }
> +        if (call)
> +          dummy->set("call_expr_arg", holder);
> +
> +        if (CALL_EXPR_VA_ARG_PACK (t))
> +          dummy->set_bool("__builtin_va_arg_pack", true);
> +
> +        op1 = CALL_EXPR_STATIC_CHAIN (t);
> +        if (op1)
> +          dummy->set("static_chain", node_emit_json(op1));
> +      }
> +      break;
> +    case WITH_CLEANUP_EXPR:
> +      break;
> +    case CLEANUP_POINT_EXPR:
> +      dummy->set("cleanup_point", node_emit_json (TREE_OPERAND(t, 0)));
> +      break;
> +    case PLACEHOLDER_EXPR:
> +      dummy->set("placeholder_expr", node_emit_json (TREE_OPERAND(t, 0)));
> +      break;
> +
> +    /* Binary operations */
> +    case WIDEN_SUM_EXPR:
> +    case WIDEN_MULT_EXPR:
> +    case MULT_EXPR:
> +    case MULT_HIGHPART_EXPR:
> +    case PLUS_EXPR:
> +    case POINTER_PLUS_EXPR:
> +    case POINTER_DIFF_EXPR:
> +    case MINUS_EXPR:
> +    case TRUNC_DIV_EXPR:
> +    case CEIL_DIV_EXPR:
> +    case FLOOR_DIV_EXPR:
> +    case ROUND_DIV_EXPR:
> +    case TRUNC_MOD_EXPR:
> +    case CEIL_MOD_EXPR:
> +    case FLOOR_MOD_EXPR:
> +    case ROUND_MOD_EXPR:
> +    case RDIV_EXPR:
> +    case EXACT_DIV_EXPR:
> +    case LSHIFT_EXPR:
> +    case RSHIFT_EXPR:
> +    case LROTATE_EXPR:
> +    case RROTATE_EXPR:
> +    case WIDEN_LSHIFT_EXPR:
> +    case BIT_IOR_EXPR:
> +    case BIT_XOR_EXPR:
> +    case BIT_AND_EXPR:
> +    case TRUTH_ANDIF_EXPR:
> +    case TRUTH_ORIF_EXPR:
> +    case TRUTH_AND_EXPR:
> +    case TRUTH_OR_EXPR:
> +    case TRUTH_XOR_EXPR:
> +    case LT_EXPR:
> +    case LE_EXPR:
> +    case GT_EXPR:
> +    case GE_EXPR:
> +    case EQ_EXPR:
> +    case NE_EXPR:
> +    case UNLT_EXPR:
> +    case UNLE_EXPR:
> +    case UNGT_EXPR:
> +    case UNGE_EXPR:
> +    case UNEQ_EXPR:
> +    case LTGT_EXPR:
> +    case ORDERED_EXPR:
> +    case UNORDERED_EXPR:
> +      {
> +        const char* c = op_symbol_code(TREE_CODE(t), TDF_NONE);
> +        op0 = TREE_OPERAND(t, 0);
> +        op1 = TREE_OPERAND(t, 1);
> +
> +        dummy->set_string("bin_operator", c);
> +        holder->append(node_emit_json(op0));
> +        holder->append(node_emit_json(op1));
> +        dummy->set("operands", holder);
> +      }
> +      break;
> +
> +    case ADDR_EXPR:
> +      //TDF_GIMPLE_VAL
> +      dummy->set("_Literal", node_emit_json( TREE_TYPE (t)));
> +      /* FALLTHROUGH */
> +    case NEGATE_EXPR:
> +    case BIT_NOT_EXPR:
> +    case TRUTH_NOT_EXPR:
> +    case PREDECREMENT_EXPR:
> +    case PREINCREMENT_EXPR:
> +    case INDIRECT_REF:
> +    case POSTDECREMENT_EXPR:
> +    case POSTINCREMENT_EXPR:
> +      {
> +        const char * c = op_symbol_code(code, TDF_NONE);
> +        dummy->set(c, node_emit_json (TREE_OPERAND (t, 0)));
> +      }
> +      break;
> +
> +    case MIN_EXPR:
> +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> +      holder->append (node_emit_json (TREE_OPERAND (t,1)));
> +      dummy->set("min_expr", holder);
> +      break;
> +
> +    case MAX_EXPR:
> +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> +      holder->append (node_emit_json (TREE_OPERAND (t,1)));
> +      dummy->set("max_expr", holder);
> +      break;
> +
> +    case ABS_EXPR:
> +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> +      dummy->set("abs_expr", holder);
> +      break;
> +
> +    case ABSU_EXPR:
> +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> +      dummy->set("absu_expr", holder);
> +      break;
> +
> +    case RANGE_EXPR:
> +      break;
> +
> +    case ADDR_SPACE_CONVERT_EXPR:
> +    case FIXED_CONVERT_EXPR:
> +    case FIX_TRUNC_EXPR:
> +    case FLOAT_EXPR:
> +    CASE_CONVERT:
> +      type = TREE_TYPE (t);
> +      op0 = TREE_OPERAND (t, 0);
> +      if (type != TREE_TYPE(op0))
> +        {
> +          dummy->set ("type", node_emit_json (type));
> +        }
> +      dummy->set ("operand", node_emit_json (op0));
> +      break;
> +
> +    case VIEW_CONVERT_EXPR:
> +      holder->append (node_emit_json (TREE_TYPE(t)));
> +      holder->append (node_emit_json (TREE_OPERAND(t, 0)));
> +      dummy->set("view_convert_expr", holder);
> +      break;
> +
> +    case PAREN_EXPR:
> +      dummy->set("paren_expr",
> +                 node_emit_json (TREE_OPERAND (t,0)));
> +      break;
> +
> +    case NON_LVALUE_EXPR:
> +      dummy->set("non_lvalue_expr",
> +                 node_emit_json (TREE_OPERAND (t,0)));
> +      break;
> +
> +    case SAVE_EXPR:
> +      dummy->set("save_expr",
> +                 node_emit_json (TREE_OPERAND (t,0)));
> +      break;
> +
> +    case COMPLEX_EXPR:
> +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> +      holder->append (node_emit_json (TREE_OPERAND (t,1)));
> +      dummy->set("complex_expr", holder);
> +      break;
> +
> +    case CONJ_EXPR:
> +      dummy->set("conj_expr",
> +                 node_emit_json (TREE_OPERAND (t,0)));
> +      break;
> +
> +    case REALPART_EXPR:
> +      dummy->set("realpart_expr",
> +                 node_emit_json (TREE_OPERAND (t,0)));
> +      break;
> +
> +    case IMAGPART_EXPR:
> +      dummy->set("imagpart_expr",
> +                 node_emit_json (TREE_OPERAND (t,0)));
> +      break;
> +
> +    case VA_ARG_EXPR:
> +      dummy->set("va_arg_expr",
> +                 node_emit_json (TREE_OPERAND (t,0)));
> +      break;
> +
> +    case TRY_FINALLY_EXPR:
> +    case TRY_CATCH_EXPR:
> +      {
> +        tree _t;
> +        dummy->set("try",
> +                   node_emit_json (TREE_OPERAND (t, 0)));
> +        if (TREE_CODE (t) == TRY_CATCH_EXPR)
> +          {
> +            _t = TREE_OPERAND(t, 1);
> +            dummy->set("catch",
> +                        node_emit_json (_t));
> +          }
> +        else
> +          {
> +            gcc_assert(TREE_CODE (t) == TRY_FINALLY_EXPR);
> +            _t = TREE_OPERAND(t, 1);
> +            if (TREE_CODE (t) == EH_ELSE_EXPR)
> +              {
> +                _t = TREE_OPERAND (_t, 0);
> +                dummy->set("finally",
> +                           node_emit_json (_t));
> +                _t = TREE_OPERAND(_t, 1);
> +                dummy->set("else",
> +                           node_emit_json (_t));
> +              }
> +            else
> +              {
> +              dummy->set("finally",
> +                         node_emit_json(_t));
> +              }
> +          }
> +      }
> +      break;
> +
> +    case CATCH_EXPR:
> +      dummy->set("catch_types", node_emit_json(CATCH_TYPES(t)));
> +      dummy->set("catch_body", node_emit_json(CATCH_BODY(t)));
> +      break;
> +
> +    case EH_FILTER_EXPR:
> +      dummy->set("eh_filter_types", node_emit_json(EH_FILTER_TYPES(t)));
> +      dummy->set("eh_filter_failure", node_emit_json(EH_FILTER_FAILURE(t)));
> +      break;
> +
> +    case LABEL_EXPR:
> +      decl_node_add_json (TREE_OPERAND (t, 0), dummy);
> +      break;
> +
> +    case LOOP_EXPR:
> +      dummy->set("while (1)", node_emit_json (LOOP_EXPR_BODY (t)));
> +      break;
> +
> +    case PREDICT_EXPR:
> +      if (PREDICT_EXPR_OUTCOME (t))
> +        dummy->set_string("likely by",
> +                          predictor_name (PREDICT_EXPR_PREDICTOR (t)));
> +      else
> +        dummy->set_string("unlikely by",
> +                          predictor_name (PREDICT_EXPR_PREDICTOR (t)));
> +      break;
> +    case ANNOTATE_EXPR:
> +      {
> +      switch ((enum annot_expr_kind) TREE_INT_CST_LOW (TREE_OPERAND(t,1)))
> +        { //Is this expensive? ask later
> +          case annot_expr_ivdep_kind:
> +            dummy->set("ivdep", node_emit_json (TREE_OPERAND (t, 0)));
> +            break;
> +          case annot_expr_unroll_kind:
> +            dummy->set("unroll", node_emit_json (TREE_OPERAND (t, 0)));
> +            break;
> +          case annot_expr_no_vector_kind:
> +            dummy->set("no-vector", node_emit_json (TREE_OPERAND (t, 0)));
> +            break;
> +          case annot_expr_vector_kind:
> +            dummy->set("vector", node_emit_json (TREE_OPERAND (t, 0)));
> +            break;
> +          case annot_expr_parallel_kind:
> +            dummy->set("parallel", node_emit_json (TREE_OPERAND (t, 0)));
> +            break;
> +          case annot_expr_maybe_infinite_kind:
> +            dummy->set("maybe_infinite",
> +                       node_emit_json (TREE_OPERAND (t, 0)));
> +            break;
> +          default:
> +            gcc_unreachable();
> +        }
> +      }
> +      break;
> +
> +    case RETURN_EXPR:
> +      {
> +        op0 = TREE_OPERAND(t, 0);
> +        if (op0)
> +          {
> +            if (TREE_CODE(op0) == MODIFY_EXPR)
> +              dummy->set("return_expr", node_emit_json(TREE_OPERAND(op0, 1)));
> +            else
> +              dummy->set("return_expr", node_emit_json(op0));
> +          }
> +      }
> +      break;
> +
> +    case EXIT_EXPR:
> +      dummy->set("exit_if", node_emit_json(TREE_OPERAND (t, 0)));
> +      break;
> +
> +    case SWITCH_EXPR:
> +      dummy->set("switch_cond", node_emit_json(SWITCH_COND(t)));
> +      dummy->set("switch_body", node_emit_json(SWITCH_BODY(t)));
> +      break;
> +
> +    case GOTO_EXPR:
> +      op0 = GOTO_DESTINATION(t);
> +      dummy->set("goto", node_emit_json(op0));
> +      break;
> +
> +    case ASM_EXPR:
> +      dummy->set("asm_string", node_emit_json (ASM_STRING (t)));
> +      dummy->set("asm_outputs", node_emit_json (ASM_OUTPUTS (t)));
> +      dummy->set("asm_inputs", node_emit_json (ASM_INPUTS (t)));
> +      if (ASM_CLOBBERS (t))
> +        dummy->set("asm_clobbers", node_emit_json (ASM_CLOBBERS (t)));
> +      break;
> +
> +    case CASE_LABEL_EXPR:
> +      if (CASE_LOW(t) && CASE_HIGH(t))
> +        {
> +          dummy->set ("case_low", node_emit_json (CASE_LOW(t)));
> +          dummy->set ("case_high", node_emit_json (CASE_HIGH(t)));
> +        }
> +      else if (CASE_LOW(t))
> +        dummy->set ("case", node_emit_json (CASE_LOW(t)));
> +      else
> +        dummy->set_string("case", "default");
> +      break;
> +
> +    // check later - okay?
> +    case OBJ_TYPE_REF:
> +      dummy->set("obj_type_ref_expr",
> +                 node_emit_json(OBJ_TYPE_REF_EXPR(t)));
> +      dummy->set("obj_type_ref_object",
> +                 node_emit_json(OBJ_TYPE_REF_OBJECT(t)));
> +      dummy->set("obj_type_ref_token",
> +                 node_emit_json(OBJ_TYPE_REF_TOKEN(t)));
> +      break;
> +
> +    case SSA_NAME:
> +      {
> +      if (SSA_NAME_IDENTIFIER (t))
> +        dummy->set("ssa_name_identifier",
> +                   node_emit_json (SSA_NAME_IDENTIFIER (t)));
> +      if (SSA_NAME_IS_DEFAULT_DEF (t))
> +        dummy->set_bool("ssa_default_def", true);
> +      if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (t))
> +       dummy->set_bool("abnormal_phi", true);
> +      }
> +      break;
> +
> +    case WITH_SIZE_EXPR:
> +      dummy->set("expr", node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("size", node_emit_json (TREE_OPERAND (t, 1)));
> +      break;
> +
> +    case SCEV_KNOWN:
> +    case SCEV_NOT_KNOWN:
> +      break;
> +
> +    case POLYNOMIAL_CHREC:
> +      dummy->set_integer("chrec_var", CHREC_VARIABLE(t));
> +      dummy->set("chrec_left", node_emit_json (CHREC_LEFT(t)));
> +      dummy->set("chrec_right", node_emit_json (CHREC_RIGHT(t)));
> +      dummy->set_bool("chrec_nowrap", CHREC_NOWRAP(t));
> +      break;
> +
> +    case REALIGN_LOAD_EXPR:
> +      dummy->set("input_0", node_emit_json(TREE_OPERAND (t, 0)));
> +      dummy->set("input_1", node_emit_json(TREE_OPERAND (t, 1)));
> +      dummy->set("offset", node_emit_json(TREE_OPERAND (t, 2)));
> +      break;
> +
> +    case VEC_COND_EXPR:
> +      dummy->set("if",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("then",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      dummy->set("else",
> +                 node_emit_json (TREE_OPERAND (t, 2)));
> +      break;
> +
> +    case VEC_PERM_EXPR:
> +      dummy->set("v0",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("v1",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      dummy->set("mask",
> +                 node_emit_json (TREE_OPERAND (t, 2)));
> +      break;
> +
> +    case DOT_PROD_EXPR: //check later
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("arg2",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      dummy->set("arg3",
> +                 node_emit_json (TREE_OPERAND (t, 2)));
> +      break;
> +
> +    case WIDEN_MULT_PLUS_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("arg2",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      dummy->set("arg3",
> +                 node_emit_json (TREE_OPERAND (t, 2)));
> +      break;
> +
> +    case WIDEN_MULT_MINUS_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("arg2",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      dummy->set("arg3",
> +                 node_emit_json (TREE_OPERAND (t, 2)));
> +      break;
> +
> +    case VEC_SERIES_EXPR:
> +    case VEC_WIDEN_MULT_HI_EXPR:
> +    case VEC_WIDEN_MULT_LO_EXPR:
> +    case VEC_WIDEN_MULT_ODD_EXPR:
> +    case VEC_WIDEN_LSHIFT_HI_EXPR:
> +    case VEC_WIDEN_LSHIFT_LO_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("arg2",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      break;
> +
> +    case VEC_DUPLICATE_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      break;
> +
> +    case VEC_UNPACK_HI_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      break;
> +
> +    case VEC_UNPACK_LO_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      break;
> +
> +    case VEC_UNPACK_FLOAT_HI_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      break;
> +
> +    case VEC_UNPACK_FLOAT_LO_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      break;
> +
> +    case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      break;
> +
> +    case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      break;
> +
> +    case VEC_PACK_TRUNC_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("arg2",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      break;
> +
> +    case VEC_PACK_SAT_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("arg2",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      break;
> +
> +    case VEC_PACK_FIX_TRUNC_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("arg2",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      break;
> +
> +    case VEC_PACK_FLOAT_EXPR:
> +      dummy->set("arg1",
> +                 node_emit_json (TREE_OPERAND (t, 0)));
> +      dummy->set("arg2",
> +                 node_emit_json (TREE_OPERAND (t, 1)));
> +      break;
> +    /*OACC and OMP */
> +    case OACC_PARALLEL:
> +      goto dump_omp_clauses_body;
> +
> +    case OACC_KERNELS:
> +      goto dump_omp_clauses_body;
> +
> +    case OACC_SERIAL:
> +      goto dump_omp_clauses_body;
> +
> +    case OACC_DATA:
> +      goto dump_omp_clauses_body;
> +
> +    case OACC_HOST_DATA:
> +      dummy->set("oacc_host_data_clauses",
> +                 omp_clause_emit_json (OACC_HOST_DATA_CLAUSES(t)));
> +      dummy->set("oacc_host_data_body",
> +                 omp_clause_emit_json (OACC_HOST_DATA_BODY(t)));
> +      break;
> +
> +    case OACC_DECLARE:
> +      dummy->set("oacc_declare_clauses",
> +                 omp_clause_emit_json (OACC_DECLARE_CLAUSES(t)));
> +      break;
> +
> +    case OACC_UPDATE:
> +      dummy->set("oacc_update_clauses",
> +                 omp_clause_emit_json (OACC_UPDATE_CLAUSES(t)));
> +      break;
> +
> +    case OACC_ENTER_DATA:
> +      dummy->set("oacc_enter_data_clauses",
> +                 omp_clause_emit_json (OACC_ENTER_DATA_CLAUSES(t)));
> +      break;
> +
> +    case OACC_EXIT_DATA:
> +      dummy->set("oacc_exit_data_clauses",
> +                 omp_clause_emit_json (OACC_EXIT_DATA_CLAUSES(t)));
> +      break;
> +
> +    case OACC_CACHE:
> +      dummy->set("oacc_cache_clauses",
> +                 omp_clause_emit_json (OACC_CACHE_CLAUSES(t)));
> +      break;
> +
> +    case OMP_PARALLEL:
> +      dummy->set("omp_parallel_body",
> +                 node_emit_json (OMP_PARALLEL_BODY(t)));
> +      dummy->set("omp_parallel_clauses",
> +                 omp_clause_emit_json (OMP_PARALLEL_CLAUSES(t)));
> +      break;
> +
> +    case OMP_TASK:
> +      {
> +      if (OMP_TASK_BODY (t))
> +        {
> +          dummy->set_bool("omp_task", true);
> +          dummy->set("omp_task_body",
> +                     node_emit_json(OMP_TASK_BODY (t)));
> +          dummy->set("omp_task_clauses",
> +                     omp_clause_emit_json (OMP_TASK_CLAUSES(t)));
> +        } else {
> +          dummy->set_bool("omp_taskwait", true);
> +          dummy->set("omp_taskwait_clauses",
> +                     omp_clause_emit_json (OMP_TASK_CLAUSES(t)));
> +        }
> +        break;
> +      }
> +
> +    dump_omp_clauses_body:
> +      dummy->set("omp_clauses", omp_clause_emit_json (OMP_CLAUSES (t)));
> +      goto dump_omp_body;
> +
> +    dump_omp_body:
> +      dummy->set("omp_body", node_emit_json (OMP_BODY(t)));
> +      dummy->set_bool("is_expr", false);
> +      break;
> +
> +    case OMP_FOR:
> +      goto dump_omp_loop;
> +
> +    case OMP_SIMD:
> +      goto dump_omp_loop;
> +
> +    case OMP_DISTRIBUTE:
> +      goto dump_omp_loop;
> +
> +    case OMP_TASKLOOP:
> +      goto dump_omp_loop;
> +
> +    case OMP_LOOP:
> +      goto dump_omp_loop;
> +
> +    case OMP_TILE:
> +      goto dump_omp_loop;
> +
> +    case OMP_UNROLL:
> +      goto dump_omp_loop;
> +
> +    case OACC_LOOP:
> +      goto dump_omp_loop;
> +
> +    dump_omp_loop:
> +      dummy->set("omp_for_body",
> +                 node_emit_json(OMP_FOR_BODY (t)));
> +      dummy->set("omp_for_clauses",
> +                 omp_clause_emit_json (OMP_FOR_CLAUSES(t)));
> +      dummy->set("omp_for_init",
> +                 node_emit_json(OMP_FOR_INIT (t)));
> +      dummy->set("omp_for_incr",
> +                 node_emit_json(OMP_FOR_INCR (t)));
> +      dummy->set("omp_for_pre_body",
> +                 node_emit_json(OMP_FOR_PRE_BODY (t)));
> +      dummy->set("omp_for_orig_decls",
> +                 node_emit_json(OMP_FOR_ORIG_DECLS (t)));
> +      break;
> +
> +    case OMP_TEAMS:
> +      dummy->set("omp_teams_body",
> +                 omp_clause_emit_json (OMP_TEAMS_BODY(t)));
> +      dummy->set("omp_teams_clauses",
> +                 omp_clause_emit_json (OMP_TEAMS_CLAUSES(t)));
> +      break;
> +
> +    case OMP_TARGET_DATA:
> +      dummy->set("omp_target_data_body",
> +                 omp_clause_emit_json (OMP_TARGET_DATA_BODY(t)));
> +      dummy->set("omp_target_data_clauses",
> +                 omp_clause_emit_json (OMP_TARGET_DATA_CLAUSES(t)));
> +      break;
> +
> +    case OMP_TARGET_ENTER_DATA:
> +      dummy->set("omp_target_enter_data_clauses",
> +                 omp_clause_emit_json (OMP_TARGET_ENTER_DATA_CLAUSES(t)));
> +      break;
> +
> +    case OMP_TARGET_EXIT_DATA:
> +      dummy->set("omp_target_exit_data_clauses",
> +                 omp_clause_emit_json (OMP_TARGET_EXIT_DATA_CLAUSES(t)));
> +      break;
> +
> +    case OMP_TARGET:
> +      dummy->set("omp_target_body",
> +                 omp_clause_emit_json (OMP_TARGET_BODY(t)));
> +      dummy->set("omp_target_clauses",
> +                 omp_clause_emit_json (OMP_TARGET_CLAUSES(t)));
> +      break;
> +
> +    case OMP_TARGET_UPDATE:
> +      dummy->set("omp_target_update_clauses",
> +                 omp_clause_emit_json (OMP_TARGET_UPDATE_CLAUSES(t)));
> +      break;
> +
> +    case OMP_SECTIONS:
> +      dummy->set("omp_sections_body",
> +                 omp_clause_emit_json (OMP_SECTIONS_BODY(t)));
> +      dummy->set("omp_sections_clauses",
> +                 omp_clause_emit_json (OMP_SECTIONS_CLAUSES(t)));
> +      break;
> +
> +    case OMP_SECTION:
> +      dummy->set("omp_section_body",
> +                 omp_clause_emit_json (OMP_SECTION_BODY(t)));
> +      break;
> +
> +    case OMP_STRUCTURED_BLOCK:
> +      dummy->set("omp_structured_block_body",
> +                 omp_clause_emit_json (OMP_STRUCTURED_BLOCK_BODY(t)));
> +      break;
> +
> +    case OMP_SCAN:
> +      dummy->set("omp_scan_body",
> +                 omp_clause_emit_json (OMP_SCAN_BODY(t)));
> +      dummy->set("omp_scan_clauses",
> +                 omp_clause_emit_json (OMP_SCAN_CLAUSES(t)));
> +      break;
> +
> +    case OMP_MASTER:
> +      dummy->set("omp_master_body",
> +                 omp_clause_emit_json (OMP_MASTER_BODY(t)));
> +      break;
> +
> +    case OMP_MASKED:
> +      dummy->set("omp_masked_body",
> +                 omp_clause_emit_json (OMP_MASKED_BODY(t)));
> +      dummy->set("omp_masked_clauses",
> +                 omp_clause_emit_json (OMP_MASKED_CLAUSES(t)));
> +      break;
> +
> +    case OMP_TASKGROUP:
> +      dummy->set("omp_taskgroup_body",
> +                 omp_clause_emit_json (OMP_TASKGROUP_BODY(t)));
> +      dummy->set("omp_taskgroup_clauses",
> +                 omp_clause_emit_json (OMP_TASKGROUP_CLAUSES(t)));
> +      break;
> +
> +    case OMP_ORDERED:
> +      dummy->set("omp_ordered_body",
> +                 omp_clause_emit_json (OMP_ORDERED_BODY(t)));
> +      dummy->set("omp_ordered_clauses",
> +                 omp_clause_emit_json (OMP_ORDERED_CLAUSES(t)));
> +      break;
> +
> +    case OMP_CRITICAL:
> +      dummy->set("omp_masked_body",
> +                 omp_clause_emit_json (OMP_CRITICAL_BODY(t)));
> +      dummy->set("omp_masked_clauses",
> +                 omp_clause_emit_json (OMP_CRITICAL_CLAUSES(t)));
> +      dummy->set("omp_masked_name",
> +                 node_emit_json (OMP_CRITICAL_NAME(t)));
> +      break;
> +
> +    case OMP_ATOMIC:
> +      if (OMP_ATOMIC_WEAK (t))
> +        dummy->set_bool("omp_atomic_weak", true);
> +      else
> +        dummy->set_bool("omp_atomic_weak", false);
> +      dummy->set("omp_atomic_memory_order",
> +                 omp_atomic_memory_order_emit_json(
> +                     OMP_ATOMIC_MEMORY_ORDER(t)));
> +      dummy->set("op0",
> +                 node_emit_json (TREE_OPERAND(t, 0)));
> +      dummy->set("op1",
> +                 node_emit_json (TREE_OPERAND(t, 1)));
> +      break;
> +
> +    case OMP_ATOMIC_READ:
> +      dummy->set("omp_atomic_memory_order",
> +                 omp_atomic_memory_order_emit_json(
> +                     OMP_ATOMIC_MEMORY_ORDER(t)));
> +      dummy->set("op0",
> +                 node_emit_json(TREE_OPERAND(t, 0)));
> +      break;
> +
> +    case OMP_ATOMIC_CAPTURE_OLD:
> +    case OMP_ATOMIC_CAPTURE_NEW:
> +      if (OMP_ATOMIC_WEAK (t))
> +        dummy->set_bool("omp_atomic_capture_weak", true);
> +      else
> +        dummy->set_bool("omp_atomic_capture", true);
> +      dummy->set("omp_atomic_memory_order",
> +                 omp_atomic_memory_order_emit_json (OMP_ATOMIC_MEMORY_ORDER(t)));
> +      dummy->set("op0",
> +                 node_emit_json(TREE_OPERAND(t, 0)));
> +      dummy->set("op1",
> +                 node_emit_json(TREE_OPERAND(t, 1)));
> +      break;
> +
> +    case OMP_SINGLE:
> +      dummy->set("omp_single_body",
> +                 omp_clause_emit_json (OMP_SINGLE_BODY(t)));
> +      dummy->set("omp_single_clauses",
> +                 omp_clause_emit_json (OMP_SINGLE_CLAUSES(t)));
> +      break;
> +
> +    case OMP_SCOPE:
> +      dummy->set("omp_scope_body",
> +                 omp_clause_emit_json (OMP_SCOPE_BODY(t)));
> +      dummy->set("omp_scope_clauses",
> +                 omp_clause_emit_json (OMP_SCOPE_CLAUSES(t)));
> +      break;
> +
> +    case OMP_CLAUSE:
> +      dummy->set("omp_clause",
> +                 omp_clause_emit_json(t));
> +      break;
> +
> +    case TRANSACTION_EXPR:
> +      if (TRANSACTION_EXPR_OUTER (t))
> +       dummy->set_bool ("transaction_expr_outer", true);
> +      if (TRANSACTION_EXPR_RELAXED (t))
> +       dummy->set_bool ("transaction_expr_relaxed", true);
> +      dummy->set("omp_transaction_body",
> +                 node_emit_json (TRANSACTION_EXPR_BODY(t)));
> +      break;
> +
> +    case BLOCK:
> +      {
> +      tree iter;
> +      json::array *subblock, *chain, *vars, *fragment_chain, *nlv_holder;
> +      dummy->set_integer ("block #", BLOCK_NUMBER (t));
> +      if (BLOCK_SUPERCONTEXT (t))
> +        dummy->set("block_supercontext",
> +                   node_emit_json(BLOCK_SUPERCONTEXT (t)));
> +      if (BLOCK_SUBBLOCKS(t))
> +        {
> +          subblock = new json::array ();
> +          for (iter = BLOCK_SUBBLOCKS (t); iter; iter = BLOCK_CHAIN (t))
> +            subblock->append(node_emit_json(iter));
> +          dummy->set("block_subblocks", subblock);
> +        }
> +      if (BLOCK_CHAIN (t))
> +        {
> +          chain = new json::array ();
> +          for (iter = BLOCK_SUBBLOCKS (t); iter; iter = BLOCK_CHAIN (t))
> +              chain->append(node_emit_json(iter));
> +          dummy->set("block_chain", chain);
> +
> +        }
> +      if (BLOCK_VARS (t))
> +        {
> +          vars = new json::array ();
> +          for (iter = BLOCK_VARS (t); iter; iter = TREE_CHAIN (t))
> +              vars->append(node_emit_json(iter));
> +          dummy->set("block_vars", vars);
> +        }
> +      if (vec_safe_length (BLOCK_NONLOCALIZED_VARS (t)) > 0)
> +        {
> +          unsigned i;
> +          vec<tree, va_gc> *nlv = BLOCK_NONLOCALIZED_VARS (t);
> +
> +          nlv_holder = new json::array ();
> +
> +          FOR_EACH_VEC_ELT (*nlv, i, t)
> +            {
> +              nlv_holder->append(node_emit_json(t));
> +            }
> +          dummy->set("block_nonlocalized_vars", nlv_holder);
> +        }
> +      if (BLOCK_ABSTRACT_ORIGIN (t))
> +        dummy->set("block_abstract_origin",
> +                   node_emit_json (BLOCK_ABSTRACT_ORIGIN (t)));
> +      if (BLOCK_FRAGMENT_ORIGIN (t))
> +        dummy->set("block_fragment_origin",
> +                   node_emit_json (BLOCK_FRAGMENT_ORIGIN (t)));
> +
> +      if (BLOCK_FRAGMENT_CHAIN (t))
> +        {
> +          fragment_chain = new json::array ();
> +          for( iter=BLOCK_FRAGMENT_CHAIN (t);
> +               iter;
> +               iter=BLOCK_FRAGMENT_CHAIN (t) )
> +              fragment_chain->append(node_emit_json(iter));
> +          dummy->set("block_fragment_chain", fragment_chain);
> +        }
> +      }
> +      break;
> +
> +    case DEBUG_BEGIN_STMT:
> +      dummy->set_bool("debug_begin", true);
> +      break;
> +    default:
> +      dummy->set_bool("unsupported code", true);
> +      dummy->set_string("fallthrough", get_tree_code_name(code));
> +      break;
> +  }
> +  return dummy;
> +}
> +
> +/* Dump the next node in the queue.  */
> +
> +static void
> +dequeue_and_dump (dump_info_p di)
> +{
> +  dump_queue_p dq;
> +  splay_tree_node stn;
> +//  dump_node_info_p dni;
> +  tree t;
> +  json::object* dummy;
> +
> +  dummy = new json::object ();
> +
> +  /* Get the next node from the queue.  */
> +  dq = di->queue;
> +  stn = dq->node;
> +  t = (tree) stn->key;
> +//  dni = (dump_node_info_p) stn->value;
> +
> +  /* Remove the node from the queue, and put it on the free list.  */
> +  di->queue = dq->next;
> +  if (!di->queue)
> +    di->queue_end = 0;
> +  dq->next = di->free_list;
> +  di->free_list = dq;
> +
> +  dummy = node_emit_json(t);
> +  di->json_dump->append(dummy);
> +}
> +
> +/* Dump T, and all its children, on STREAM.  */
> +
> +void
> +dump_node_json (const_tree t, dump_flags_t flags, FILE *stream)
> +{
> +  struct dump_info di;
> +  dump_queue_p dq;
> +  dump_queue_p next_dq;
> +  pretty_printer pp;
> +  /* Initialize the dump-information structure.  */
> +  di.stream = stream;
> +  di.index = 0;
> +  di.column = 0;
> +  di.queue = 0;
> +  di.queue_end = 0;
> +  di.free_list = 0;
> +  di.flags = flags;
> +  di.node = t;
> +  di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
> +                            splay_tree_delete_pointers);
> +  di.json_dump = new json::array ();
> +  /* Queue up the first node.  */
> +  queue (&di, t);
> +
> +  /* Until the queue is empty, keep dumping nodes.  */
> +  while (di.queue)
> +    dequeue_and_dump (&di);
> +
> +  di.json_dump->dump(stream, true);
> +  fputs("\n", stream);
> +  /* Now, clean up.  */
> +  for (dq = di.free_list; dq; dq = next_dq)
> +    {
> +      next_dq = dq->next;
> +      free (dq);
> +    }
> +  splay_tree_delete (di.nodes);
> +}
> +
> +DEBUG_FUNCTION void
> +debug_tree_json (tree t)
> +{
> +  json::object* _x = node_emit_json(t);
> +  _x->dump(stderr, true);
> +  fprintf(stderr, "\n");
> +}
> diff --git a/gcc/tree-emit-json.h b/gcc/tree-emit-json.h
> new file mode 100644
> index 00000000000..ea81466a940
> --- /dev/null
> +++ b/gcc/tree-emit-json.h
> @@ -0,0 +1,82 @@
> +/* Tree-dumping functionality for intermediate representation.
> +   Copyright (C) 1999-2024 Free Software Foundation, Inc.
> +   Written by Mark Mitchell <mark@codesourcery.com>
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_TREE_JSON_H
> +#define GCC_TREE_JSON_H
> +
> +#include "splay-tree.h"
> +#include "dumpfile.h"
> +#define INCLUDE_MEMORY
> +#include "json.h"
> +
> +typedef struct dump_info *dump_info_p;
> +
> +/* Information about a node to be dumped.  */
> +
> +typedef struct dump_node_info
> +{
> +  /* The index for the node.  */
> +  unsigned int index;
> +  /* Nonzero if the node is a binfo.  */
> +  unsigned int binfo_p : 1;
> +} *dump_node_info_p;
> +
> +/* A dump_queue is a link in the queue of things to be dumped.  */
> +
> +typedef struct dump_queue
> +{
> +  /* The queued tree node.  */
> +  splay_tree_node node;
> +  /* The next node in the queue.  */
> +  struct dump_queue *next;
> +} *dump_queue_p;
> +
> +/* A dump_info gives information about how we should perform the dump
> +   and about the current state of the dump.  */
> +
> +struct dump_info
> +{
> +  /* The stream on which to dump the information.  */
> +  FILE *stream;
> +  /* The original node.  */
> +  const_tree node;
> +  /* User flags.  */
> +  dump_flags_t flags;
> +  /* The next unused node index.  */
> +  unsigned int index;
> +  /* The next column.  */
> +  unsigned int column;
> +  /* The first node in the queue of nodes to be written out.  */
> +  dump_queue_p queue;
> +  /* The last node in the queue.  */
> +  dump_queue_p queue_end;
> +  /* Free queue nodes.  */
> +  dump_queue_p free_list;
> +  /* The tree nodes which we have already written out.  The
> +     keys are the addresses of the nodes; the values are the integer
> +     indices we assigned them.  */
> +  splay_tree nodes;
> +  /* JSON tree holder. Carries everything, each node is a sub-array */
> +  json::array* json_dump;
> +};
> +
> +extern json::object* node_emit_json(tree t);
> +extern void dump_node_json (const_tree t, dump_flags_t flags, FILE *stream);
> +#endif /* ! GCC_TREE_JSON_H */
> --
> 2.34.1
>
David Malcolm Sept. 12, 2024, 10:51 a.m. UTC | #2
On Wed, 2024-09-11 at 20:49 -0500, tcpreimesberger@gmail.com wrote:
> From: Thor C Preimesberger <tcpreimesberger@gmail.com>
> 
> This patch allows the compiler to dump GENERIC trees as JSON objects.
> 
> The dump flag -fdump-tree-original-json dumps each fndecl node in the
> C frontend's gimplifier as a JSON object and traverses related nodes 
> in an analagous manner as to raw-dumping.

Thanks for posting this patch.

Are you able to upload somewhere some examples of what the dumps look
like?

Some high level thoughts:

* the patch uses "dummy" throughout as a variable name.  To me the name
"dummy" suggests something unimportant that we had to give a name to,
or something that we'd prefer didn't exist but had to create.  However
in most(all?) cases "dummy" seems to refer to the json object being
created or having properties added to it, and thus the most interesting
thing in the function.  I suspect that renaming "dummy" to "js_obj" or
"json_obj" throughout would be an improvement in readability in terms
of capturing the intent of the code (assuming that all of them are
indeed json objects).

* I think the code is leaking memory for all of the json values created
- there are lots of uses of "naked new" in this code, but I don't see
any uses of "delete".  For example, in 

> +void
> +dump_node_json (const_tree t, dump_flags_t flags, FILE *stream)
> +{
> +  struct dump_info di;
> +  dump_queue_p dq;
> +  dump_queue_p next_dq;
> +  pretty_printer pp;
> +  /* Initialize the dump-information structure.  */
> +  di.stream = stream;
> +  di.index = 0;
> +  di.column = 0;
> +  di.queue = 0;
> +  di.queue_end = 0;
> +  di.free_list = 0;
> +  di.flags = flags;
> +  di.node = t;
> +  di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
> +			     splay_tree_delete_pointers);
> +  di.json_dump = new json::array ();
     ^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^
     allocated with naked new here

> +  /* Queue up the first node.  */
> +  queue (&di, t);
> +
> +  /* Until the queue is empty, keep dumping nodes.  */
> +  while (di.queue)
> +    dequeue_and_dump (&di);
> +
> +  di.json_dump->dump(stream, true);
> +  fputs("\n", stream);
> +  /* Now, clean up.  */
> +  for (dq = di.free_list; dq; dq = next_dq)
> +    {
> +      next_dq = dq->next;
> +      free (dq);
> +    }
> +  splay_tree_delete (di.nodes);

and di.json_dump goes out of scope here and is leaked, I think.  So I
*think* all of the json values being created during dumping are being
leaked.

> +}

Similarly, in:

> +DEBUG_FUNCTION void
> +debug_tree_json (tree t)
> +{
> +  json::object* _x = node_emit_json(t);
> +  _x->dump(stderr, true);
> +  fprintf(stderr, "\n");
> +}

if I'm reading things right, node_emit_json doesn't "emit" json so much
as create a new json::object on the heap via "new", and when "_x" goes
out of scope, it's leaked.

The pattern in the code seems to be that node_emit_json creates a new
json::object and populates it with properties (sometimes recursively).

Given that, and that we can use C++11, I recommend using
std::unique_ptr<json::object> for it, to capture the intent that this
is a heap-allocated pointer with responsibility for being "delete"-d at
some point.

That way, rather that:

  json::object* 
  node_emit_json(tree t)
  {
    tree op0, op1, type;
    enum tree_code code;
    expanded_location xloc;
    json::object *dummy;
    json::array* holder;
    char address_buffer[sizeof(&t)] = {"\0"};
  
    dummy = new json::object ();
    holder = new json::array ();

    [...snip...]

    return dummy;
  }


we could have (perhaps renaming to "node_to_json"):

  std::unique_ptr<json::object>
  node_to_json(tree t)
  {
    tree op0, op1, type;
    enum tree_code code;
    expanded_location xloc;
    char address_buffer[sizeof(&t)] = {"\0"};
  
    auto js_obj = ::make_unique<json::object> (); // to implicitly use std::unique_ptr<json::object>
    auto holder = ::make_unique<json::array> ();  // likewise std::unique_ptr<json::array>

    [...snip...]

    return js_obj;
  }

...assuming that I'm correctly understanding the ownership of the json
values in the patch.  Note that we have to use ::make_unique from our
make-unique.h, rather than std::make_unique from <memory> since the
latter was only added in C++14.

Many of our data structures don't properly handle objects with
destructors, and I suspect splay_tree is one of these.  You can use
js_obj.release () to transfer ownership to such data structures, and
will (probably) need to manually use "delete" on the pointers in the
right places.

What happens to "holder" in that function?  It seems to get populated
with json objects for the various tree nodes found recursively, but
then it seems to simply be leaked (or populated then auto-deleted, if
we use std::unique_ptr>.  Or am I missing something?

In case it's helpful, a couple of months ago I converted the SARIF
output code from using "naked" json pointers to using std::unique_ptr
in:
  https://gcc.gnu.org/pipermail/gcc-patches/2024-July/658204.html
and I found it helped a *lot* with documenting ownership and avoiding
leaks.  You might find other things of interest in the first half of
this patch kit:
  https://gcc.gnu.org/pipermail/gcc-patches/2024-July/658194.html
FWIW in that code I'm also using a class hierarchy of json::object
subclasses to help with compliance with a JSON schema (sarif_object is
a subclass of json::object), but given that there probably isn't a
schema for the JSON in TDF_JSON dumps, that's probably not relevant to
this case.

FWIW you can test for leaks by running the compiler under valgrind by
configuring with --enable-valgrind-annotations and appending "-wrapper
valgrind" to the command line (or "-wrapper valgrind,--leak-check=full"
IIRC).

Thanks again for the patch; hope this is constructive.
Dave
Richard Biener Sept. 12, 2024, 11:35 a.m. UTC | #3
On Thu, Sep 12, 2024 at 4:04 AM Andrew Pinski <pinskia@gmail.com> wrote:
>
> On Wed, Sep 11, 2024 at 6:51 PM <tcpreimesberger@gmail.com> wrote:
> >
> > From: Thor C Preimesberger <tcpreimesberger@gmail.com>
> >
> > This patch allows the compiler to dump GENERIC trees as JSON objects.
> >
> > The dump flag -fdump-tree-original-json dumps each fndecl node in the
> > C frontend's gimplifier as a JSON object and traverses related nodes
> > in an analagous manner as to raw-dumping.
> >
> > Some JSON parsers expect for there to be a single JSON value per file -
> > the following shell command makes the output conformant:
> >
> >   tr -d '\n ' < out.json | sed -e 's/\]\[/,/g' | sed -e 's/}{/},{/g'
> >
> > There is also a debug function that simply prints a node as formatted JSON to
> > stdout.
> >
> > The information in the dumped JSON is meant to be an amalgation of
> > tree-pretty-print.cc's dump_generic_node and print-tree.cc's debug_tree.
>
> I don't think this is a good idea and there is no obvious use case.
> GIMPLE yes but not GENERIC.

The project idea was mine, inspired by
https://gcc.gnu.org/pipermail/gcc-patches/2024-February/646295.html
which explains the use-case.

I don't think it's constructive to question a GSoC project when it's almost
finished.

Richard.

> Can you explain what the use case is for dumping generic as json. Also
> you only hooked up the C and C++ family set of front-ends. Why not
> hook up Fortran, Ada, Rust and go too? Why have it done in the
> gimplifier?
>
> Thanks,
> Andrew
>
> >
> > Bootstrapped and tested on x86_64-pc-linux-gnu without issue.
> >
> > ChangeLog:
> >         * gcc/Makefile.in: Link tree-emit-json.o to c-gimplify.o
> >         * gcc/c-family/c-gimplify.cc (c_genericize): Hook for
> >         -fdump-tree-original-json
> >         * gcc/dumpfile.cc: Include tree-emit-json.h to expose
> >         node_emit_json and debug_tree_json. Also new headers needed for
> >         json.h being implicitly exposed
> >         * gcc/dumpfile.h (dump_flag): New dump flag TDF_JSON
> >         * gcc/tree-emit-json.cc: Logic for converting a tree to JSON
>  >         and dumping.
> >         * gcc/tree-emit-json.h: Ditto
>
> A few comments about the changelog entry here.
> it should be something like:
> gcc/ChangeLog:
>          * Makefile.in: ...
>
> gcc/c-family/ChangeLog:
>           * c-gimplify.cc ...
>
> Also there is no testcase or indication on how you tested it.
>
>
> >
> > Signed-off-by: Thor C Preimesberger <tcpreimesberger@gmail.com>
> >
> > ---
> >  gcc/Makefile.in            |    2 +
> >  gcc/c-family/c-gimplify.cc |   30 +-
> >  gcc/cp/dump.cc             |    1 +
> >  gcc/dumpfile.cc            |    3 +
> >  gcc/dumpfile.h             |    6 +
> >  gcc/tree-emit-json.cc      | 3155 ++++++++++++++++++++++++++++++++++++
> >  gcc/tree-emit-json.h       |   82 +
> >  7 files changed, 3268 insertions(+), 11 deletions(-)
> >  create mode 100644 gcc/tree-emit-json.cc
> >  create mode 100644 gcc/tree-emit-json.h
> >
> > diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> > index 68fda1a7591..b65cc7f0ad5 100644
> > --- a/gcc/Makefile.in
> > +++ b/gcc/Makefile.in
> > @@ -1042,6 +1042,7 @@ OPTS_H = $(INPUT_H) $(VEC_H) opts.h $(OBSTACK_H)
> >  SYMTAB_H = $(srcdir)/../libcpp/include/symtab.h $(OBSTACK_H)
> >  CPP_INTERNAL_H = $(srcdir)/../libcpp/internal.h
> >  TREE_DUMP_H = tree-dump.h $(SPLAY_TREE_H) $(DUMPFILE_H)
> > +TREE_EMIT_JSON_H = tree-emit-json.h $(SPLAY_TREE_H) $(DUMPFILE_H) json.h
> >  TREE_PASS_H = tree-pass.h $(TIMEVAR_H) $(DUMPFILE_H)
> >  TREE_SSA_H = tree-ssa.h tree-ssa-operands.h \
> >                 $(BITMAP_H) sbitmap.h $(BASIC_BLOCK_H) $(GIMPLE_H) \
> > @@ -1709,6 +1710,7 @@ OBJS = \
> >         tree-diagnostic.o \
> >         tree-diagnostic-client-data-hooks.o \
> >         tree-dump.o \
> > +       tree-emit-json.o \
> >         tree-eh.o \
> >         tree-emutls.o \
> >         tree-if-conv.o \
> > diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc
> > index 3e29766e092..8b0c80f4f75 100644
> > --- a/gcc/c-family/c-gimplify.cc
> > +++ b/gcc/c-family/c-gimplify.cc
> > @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
> >  <http://www.gnu.org/licenses/>.  */
> >
> >  #include "config.h"
> > +#define INCLUDE_MEMORY
> >  #include "system.h"
> >  #include "coretypes.h"
> >  #include "tm.h"
> > @@ -43,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "context.h"
> >  #include "tree-pass.h"
> >  #include "internal-fn.h"
> > +#include "tree-emit-json.h"
> >
> >  /*  The gimplification pass converts the language-dependent trees
> >      (ld-trees) emitted by the parser into language-independent trees
> > @@ -629,20 +631,26 @@ c_genericize (tree fndecl)
> >    local_dump_flags = dfi->pflags;
> >    if (dump_orig)
> >      {
> > -      fprintf (dump_orig, "\n;; Function %s",
> > -              lang_hooks.decl_printable_name (fndecl, 2));
> > -      fprintf (dump_orig, " (%s)\n",
> > -              (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null"
> > -               : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))));
> > -      fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original));
> > -      fprintf (dump_orig, "\n");
> > -
> > -      if (local_dump_flags & TDF_RAW)
> > -       dump_node (DECL_SAVED_TREE (fndecl),
> > +      if (local_dump_flags & TDF_JSON)
> > +       dump_node_json (DECL_SAVED_TREE (fndecl),
> >                    TDF_SLIM | local_dump_flags, dump_orig);
> >        else
> > -       print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl));
> > +      {
> > +       fprintf (dump_orig, "\n;; Function %s",
> > +                lang_hooks.decl_printable_name (fndecl, 2));
> > +       fprintf (dump_orig, " (%s)\n",
> > +               (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null"
> > +                : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))));
> > +       fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original));
> > +       fprintf (dump_orig, "\n");
> > +       if (local_dump_flags & TDF_RAW)
> > +         dump_node (DECL_SAVED_TREE (fndecl),
> > +                    TDF_SLIM | local_dump_flags, dump_orig);
> > +       else
> > +         print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl));
> > +
> >        fprintf (dump_orig, "\n");
> > +      }
> >      }
> >
> >    /* Dump all nested functions now.  */
> > diff --git a/gcc/cp/dump.cc b/gcc/cp/dump.cc
> > index aafb62ffaa0..b1083de5f46 100644
> > --- a/gcc/cp/dump.cc
> > +++ b/gcc/cp/dump.cc
> > @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "system.h"
> >  #include "coretypes.h"
> >  #include "cp-tree.h"
> > +#define INCLUDE_MEMORY
> >  #include "tree-dump.h"
> >
> >  /* Dump a representation of the accessibility information associated
> > diff --git a/gcc/dumpfile.cc b/gcc/dumpfile.cc
> > index 074da7df216..44d9451cf7c 100644
> > --- a/gcc/dumpfile.cc
> > +++ b/gcc/dumpfile.cc
> > @@ -43,6 +43,8 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "spellcheck.h"
> >  #include "make-unique.h"
> >  #include "pretty-print-format-impl.h"
> > +#include "tree-emit-json.h"
> > +#include "tree-emit-json.h"
> >
> >  /* If non-NULL, return one past-the-end of the matching SUBPART of
> >     the WHOLE string.  */
> > @@ -148,6 +150,7 @@ static const kv_pair<dump_flags_t> dump_options[] =
> >    {"missed", MSG_MISSED_OPTIMIZATION},
> >    {"note", MSG_NOTE},
> >    {"optall", MSG_ALL_KINDS},
> > +  {"json", TDF_JSON},
> >    {"all", dump_flags_t (TDF_ALL_VALUES
> >                         & ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_GRAPH
> >                             | TDF_STMTADDR | TDF_RHS_ONLY | TDF_NOUID
> > diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
> > index 877d444ce00..a116df5096f 100644
> > --- a/gcc/dumpfile.h
> > +++ b/gcc/dumpfile.h
> > @@ -202,6 +202,9 @@ enum dump_flag : uint32_t
> >
> >    /* For error.  */
> >    TDF_ERROR = ((uint32_t)1 << 30),
> > +
> > +  /* Tree JSON dumping */
> > +  TDF_JSON = ((uint32_t)1 << 31),
> >  };
> >
> >  /* Dump flags type.  */
> > @@ -652,6 +655,9 @@ extern bool enable_rtl_dump_file (void);
> >  /* In tree-dump.cc  */
> >  extern void dump_node (const_tree, dump_flags_t, FILE *);
> >
> > +/* In tree-emit-json.cc */
> > +extern void dump_node_json(const_tree, dump_flags_t, FILE *);
> > +
> >  /* In cfghooks.cc  */
> >  extern void dump_bb (FILE *, basic_block, int, dump_flags_t);
> >
> > diff --git a/gcc/tree-emit-json.cc b/gcc/tree-emit-json.cc
> > new file mode 100644
> > index 00000000000..e6de2029265
> > --- /dev/null
> > +++ b/gcc/tree-emit-json.cc
> > @@ -0,0 +1,3180 @@
> > +/* Dumping functionality for GENERIC Trees as JSON. Both for
> > +   the dump -fdump-tree-original-json and a new debug
> > +   function.
> > +   Copyright (C) 2024 Thor Preimesberger <tcpreimesberger@gmail.com>
> > +   Adapted from tree-pretty-print.cc, tree-dump.cc, and
> > +   print-tree.cc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +
> > +#define INCLUDE_STRING
> > +#define INCLUDE_MEMORY
> > +#include "config.h"
> > +#include "system.h"
> > +#include "coretypes.h"
> > +#include "tree.h"
> > +#include "tree-pretty-print.h"
> > +#include "tree-emit-json.h"
> > +#include "langhooks.h"
> > +#include "tree-iterator.h"
> > +#include "dumpfile.h"
> > +#include "json.h"
> > +#include "tm.h"
> > +#include "wide-int-print.h"
> > +#include "real.h" //for real printing
> > +#include "poly-int.h"
> > +#include "gomp-constants.h"
> > +#include "internal-fn.h"
> > +#include "cgraph.h"
> > +#include "predict.h"
> > +#include "fold-const.h"
> > +#include "vec.h"
> > +
> > +static unsigned int queue (dump_info_p, const_tree);
> > +static void dequeue_and_dump (dump_info_p);
> > +static json::array* function_decl_emit_json (tree);
> > +static void identifier_node_add_json (tree, json::object*);
> > +static void decl_node_add_json (tree, json::object*);
> > +static void function_name_add_json (tree, json::object*);
> > +static void omp_iterator_add_json (tree, json::object*);
> > +static void omp_clause_add_json(tree, json::object*);
> > +static void omp_atomic_memory_order_add_json (json::object*,
> > +                                              enum omp_memory_order);
> > +static json::object* omp_atomic_memory_order_emit_json(omp_memory_order mo);
> > +static json::object* omp_clause_emit_json (tree);
> > +static json::array* loc_emit_json(expanded_location);
> > +
> > +/* Add T to the end of the queue of nodes to dump.  Returns the index
> > +   assigned to T.  */
> > +
> > +static unsigned int
> > +queue (dump_info_p di, const_tree t)
> > +{
> > +  dump_queue_p dq;
> > +  dump_node_info_p dni;
> > +  unsigned int index;
> > +
> > +  /* Assign the next available index to T.  */
> > +  index = ++di->index;
> > +
> > +  /* Obtain a new queue node.  */
> > +  if (di->free_list)
> > +    {
> > +      dq = di->free_list;
> > +      di->free_list = dq->next;
> > +    }
> > +  else
> > +    dq = XNEW (struct dump_queue);
> > +
> > +  /* Create a new entry in the splay-tree.  */
> > +  dni = XNEW (struct dump_node_info);
> > +  dni->index = index;
> > +  dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
> > +                               (splay_tree_value) dni);
> > +
> > +  /* Add it to the end of the queue.  */
> > +  dq->next = 0;
> > +  if (!di->queue_end)
> > +    di->queue = dq;
> > +  else
> > +    di->queue_end->next = dq;
> > +  di->queue_end = dq;
> > +
> > +  /* Return the index.  */
> > +  return index;
> > +}
> > +
> > +void
> > +address_add_json (const void* t, json::object* dummy, char* address_buffer)
> > +{
> > +  sprintf(address_buffer, HOST_PTR_PRINTF, t);
> > +  dummy->set_string("addr", address_buffer);
> > +}
> > +
> > +/* Return args of a function declaration */
> > +
> > +json::array*
> > +function_decl_emit_json (tree t)
> > +{
> > +  bool wrote_arg = false;
> > +  tree arg;
> > +  json::array* arg_holder;
> > +  json::object* arg_json;
> > +
> > +  arg_json = new json::object ();
> > +  arg_holder = new json::array ();
> > +
> > +  arg = TYPE_ARG_TYPES (t);
> > +
> > +  while (arg && arg != void_list_node && arg != error_mark_node)
> > +    {
> > +      wrote_arg = true;
> > +      arg_json = node_emit_json(TREE_VALUE (arg));
> > +      arg_holder->append(arg_json);
> > +      arg = TREE_CHAIN (arg);
> > +    }
> > +
> > +  if (arg == void_list_node && !wrote_arg)
> > +{
> > +      arg_json->set_bool("void_list_node", true);
> > +      arg_holder->append(arg_json);
> > +    }
> > +
> > +  return arg_holder;
> > +}
> > +
> > +/* Adds Identifier information to JSON object */
> > +
> > +void
> > +identifier_node_add_json (tree t, json::object* dummy)
> > +  {
> > +    const char* buff = IDENTIFIER_POINTER (t);
> > +    dummy->set_string("id_to_locale", identifier_to_locale(buff));
> > +    buff = IDENTIFIER_POINTER (t);
> > +    dummy->set_string("id_point", buff);
> > +  }
> > +
> > +void
> > +decl_node_add_json (tree t, json::object* dummy)
> > +{
> > +  tree name = DECL_NAME (t);
> > +
> > +  if (name)
> > +      {
> > +        if (HAS_DECL_ASSEMBLER_NAME_P(t)
> > +            && DECL_ASSEMBLER_NAME_SET_P(t))
> > +          identifier_node_add_json(DECL_ASSEMBLER_NAME_RAW(t), dummy);
> > +        else if (DECL_NAMELESS(t)
> > +                 && DECL_IGNORED_P(t))
> > +          name = NULL_TREE;
> > +        else
> > +          identifier_node_add_json(name, dummy);
> > +      }
> > +    if (name == NULL_TREE)
> > +      {
> > +        if (TREE_CODE (t) == LABEL_DECL && LABEL_DECL_UID (t) != -1)
> > +          {
> > +            dummy->set_integer("Label_UID", LABEL_DECL_UID(t));
> > +          }
> > +        else if (TREE_CODE (t) == DEBUG_EXPR_DECL)
> > +          {
> > +            dummy->set_integer("Debug_UID", DEBUG_TEMP_UID (t));
> > +          }
> > +        else
> > +          {
> > +            const char* c = TREE_CODE (t) == CONST_DECL ? "Const_UID"
> > +                                                        : "Decl_UID";
> > +            dummy->set_integer(c, DECL_UID(t));
> > +          }
> > +      }
> > +    if (DECL_PT_UID (t) != DECL_UID (t))
> > +      {
> > +        dummy->set_integer("ptDecl", DECL_PT_UID(t));
> > +      }
> > +}
> > +
> > +/* Function call */
> > +
> > +void
> > +function_name_add_json (tree t, json::object* dummy)
> > +{
> > +  if (CONVERT_EXPR_P (t))
> > +    t = TREE_OPERAND (t, 0);
> > +  if (DECL_NAME (t))
> > +    {
> > +      dummy->set_string("decl_name", lang_hooks.decl_printable_name (t, 1));
> > +      dummy->set_integer("uid", DECL_UID(t));
> > +    }
> > +  else
> > +    decl_node_add_json(t, dummy);
> > +}
> > +
> > +/* Adds the name of a call. Enter iff t is CALL_EXPR_FN */
> > +
> > +void
> > +call_name_add_json (tree t, json::object* dummy)
> > +{
> > +  tree op0 = t;
> > +
> > +  if (TREE_CODE (op0) == NON_LVALUE_EXPR)
> > +    op0 = TREE_OPERAND (op0, 0);
> > +  again:
> > +    switch (TREE_CODE (op0))
> > +      {
> > +      case VAR_DECL:
> > +      case PARM_DECL:
> > +      case FUNCTION_DECL:
> > +        function_name_add_json (op0, dummy);
> > +        break;
> > +
> > +      case ADDR_EXPR:
> > +      case INDIRECT_REF:
> > +      CASE_CONVERT:
> > +        op0 = TREE_OPERAND (op0, 0);
> > +        goto again;
> > +
> > +      case COND_EXPR:
> > +        {
> > +          json::object *_x;
> > +          _x = new json::object ();
> > +          _x->set("if", node_emit_json(TREE_OPERAND(op0, 0)));
> > +          _x->set("then", node_emit_json(TREE_OPERAND(op0, 1)));
> > +          _x->set("else", node_emit_json(TREE_OPERAND(op0, 2)));
> > +          dummy->set("call_name", _x);
> > +        }
> > +        break;
> > +
> > +      case ARRAY_REF:
> > +        if (VAR_P (TREE_OPERAND (op0, 0)))
> > +       function_name_add_json (TREE_OPERAND (op0, 0), dummy);
> > +        else
> > +       dummy->set("call_name", node_emit_json (op0));
> > +        break;
> > +
> > +      case MEM_REF:
> > +        if (integer_zerop (TREE_OPERAND (op0, 1)))
> > +       {
> > +         op0 = TREE_OPERAND (op0, 0);
> > +         goto again;
> > +       }
> > +        /* Fallthrough  */
> > +      case COMPONENT_REF:
> > +      case SSA_NAME:
> > +      case OBJ_TYPE_REF:
> > +        dummy->set("call_name", node_emit_json (op0));
> > +        break;
> > +      default:
> > +        break;
> > +    }
> > +}
> > +
> > +/* OMP helper. */
> > +void
> > +omp_iterator_add_json(tree iter, json::object* dummy)
> > +{
> > +  json::array* iter_holder;
> > +  iter_holder = new json::array ();
> > +
> > +  for (tree it = iter; it; it = TREE_CHAIN (it))
> > +    {
> > +      for (int i = 0; i < 4; i++)
> > +        {
> > +          if (TREE_VEC_ELT (it, 0) != NULL_TREE)
> > +            iter_holder->append (node_emit_json (TREE_VEC_ELT (it, 0)));
> > +        }
> > +    }
> > +  dummy->set("omp_iter", iter_holder);
> > +}
> > +/* Omp helper. */
> > +void
> > +omp_clause_add_json(tree clause, json::object* dummy)
> > +{
> > +  char buffer[100] = {'\0'};
> > +  const char* name;
> > +  const char* modifier = NULL;
> > +  switch (OMP_CLAUSE_CODE (clause))
> > +    {
> > +    case OMP_CLAUSE_PRIVATE:
> > +      name = "private";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_SHARED:
> > +      name = "shared";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_FIRSTPRIVATE:
> > +      name = "firstprivate";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_LASTPRIVATE:
> > +      name = "lastprivate";
> > +      if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (clause))
> > +       modifier = "conditional:";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_COPYIN:
> > +      name = "copyin";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_COPYPRIVATE:
> > +      name = "copyprivate";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_UNIFORM:
> > +      name = "uniform";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_USE_DEVICE_PTR:
> > +      name = "use_device_ptr";
> > +      if (OMP_CLAUSE_USE_DEVICE_PTR_IF_PRESENT (clause))
> > +       modifier = "if_present:";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_USE_DEVICE_ADDR:
> > +      name = "use_device_addr";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_HAS_DEVICE_ADDR:
> > +      name = "has_device_addr";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_IS_DEVICE_PTR:
> > +      name = "is_device_ptr";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_INCLUSIVE:
> > +      name = "inclusive";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_EXCLUSIVE:
> > +      name = "exclusive";
> > +      goto print_remap;
> > +    case OMP_CLAUSE__LOOPTEMP_:
> > +      name = "_looptemp_";
> > +      goto print_remap;
> > +    case OMP_CLAUSE__REDUCTEMP_:
> > +      name = "_reductemp_";
> > +      goto print_remap;
> > +    case OMP_CLAUSE__CONDTEMP_:
> > +      name = "_condtemp_";
> > +      goto print_remap;
> > +    case OMP_CLAUSE__SCANTEMP_:
> > +      name = "_scantemp_";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_ENTER:
> > +      if (OMP_CLAUSE_ENTER_TO (clause))
> > +       name = "to";
> > +      else
> > +       name = "enter";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_LINK:
> > +      name = "link";
> > +      goto print_remap;
> > +    case OMP_CLAUSE_NONTEMPORAL:
> > +      name = "nontemporal";
> > +      goto print_remap;
> > +  print_remap: //FIX LATER
> > +      strcpy(buffer, name);
> > +      if (modifier)
> > +        strcat(buffer, modifier);
> > +      dummy->set (buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_TASK_REDUCTION:
> > +    case OMP_CLAUSE_IN_REDUCTION:
> > +    case OMP_CLAUSE_REDUCTION:
> > +      break;
> > +
> > +    case OMP_CLAUSE_IF:
> > +      strcpy(buffer, "omp_clause_if");
> > +      switch (OMP_CLAUSE_IF_MODIFIER (clause))
> > +        {
> > +        case ERROR_MARK: break;
> > +        case VOID_CST: strcat(buffer, "_cancel"); break;
> > +        case OMP_PARALLEL: strcat(buffer, "_parallel"); break;
> > +        case OMP_SIMD: strcat(buffer, "_simd"); break;
> > +        case OMP_TASK: strcat(buffer, "_task"); break;
> > +        case OMP_TASKLOOP: strcat(buffer, "_taskloop"); break;
> > +        case OMP_TARGET_DATA: strcat(buffer, "_target_data"); break;
> > +        case OMP_TARGET: strcat(buffer, "_target"); break;
> > +        case OMP_TARGET_UPDATE: strcat(buffer, "_target_update"); break;
> > +        case OMP_TARGET_ENTER_DATA: strcat(buffer, "_target_enter_data");
> > +          break;
> > +        case OMP_TARGET_EXIT_DATA: strcat(buffer, "_target_exit_data"); break;
> > +        default: gcc_unreachable ();
> > +        }
> > +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_IF_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_SELF:
> > +      dummy->set("omp_self", node_emit_json (OMP_CLAUSE_SELF_EXPR(clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_NUM_THREADS:
> > +      dummy->set("omp_num_threads",
> > +                 node_emit_json (OMP_CLAUSE_NUM_THREADS_EXPR(clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_NOWAIT:
> > +      break;
> > +
> > +    case OMP_CLAUSE_ORDERED:
> > +      dummy->set("omp_ordered",
> > +                 node_emit_json (OMP_CLAUSE_ORDERED_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_DEFAULT:
> > +      strcpy(buffer, "omp_default");
> > +      switch (OMP_CLAUSE_DEFAULT_KIND (clause))
> > +        {
> > +       case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
> > +         break;
> > +       case OMP_CLAUSE_DEFAULT_SHARED:
> > +         strcat (buffer, "_shared");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULT_NONE:
> > +         strcat (buffer, "_none");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULT_PRIVATE:
> > +         strcat (buffer, "_private");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULT_FIRSTPRIVATE:
> > +         strcat (buffer, "_firstprivate");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULT_PRESENT:
> > +         strcat (buffer, "_present");
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +        }
> > +      dummy->set_bool(buffer, true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_SCHEDULE:
> > +      strcpy (buffer, "schedule");
> > +      if (OMP_CLAUSE_SCHEDULE_KIND (clause)
> > +         & (OMP_CLAUSE_SCHEDULE_MONOTONIC
> > +            | OMP_CLAUSE_SCHEDULE_NONMONOTONIC))
> > +       {
> > +         if (OMP_CLAUSE_SCHEDULE_KIND (clause)
> > +             & OMP_CLAUSE_SCHEDULE_MONOTONIC)
> > +           strcat (buffer, "_monotonic");
> > +         else
> > +           strcat (buffer, "_nonmonotonic");
> > +       }
> > +      if (OMP_CLAUSE_SCHEDULE_SIMD (clause))
> > +       strcat (buffer, "_simd");
> > +
> > +      switch (OMP_CLAUSE_SCHEDULE_KIND (clause) & OMP_CLAUSE_SCHEDULE_MASK)
> > +       {
> > +       case OMP_CLAUSE_SCHEDULE_STATIC:
> > +         strcat (buffer, "_static");
> > +         break;
> > +       case OMP_CLAUSE_SCHEDULE_DYNAMIC:
> > +         strcat (buffer, "_dynamic");
> > +         break;
> > +       case OMP_CLAUSE_SCHEDULE_GUIDED:
> > +         strcat (buffer, "_guided");
> > +         break;
> > +       case OMP_CLAUSE_SCHEDULE_RUNTIME:
> > +         strcat (buffer, "_runtime");
> > +         break;
> > +       case OMP_CLAUSE_SCHEDULE_AUTO:
> > +         strcat (buffer, "_auto");
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +       }
> > +      dummy->set(buffer,
> > +                 node_emit_json(OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_UNTIED:
> > +      dummy->set_bool("omp_clause_untied", true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_COLLAPSE:
> > +      dummy->set("omp_collapse_collapse",
> > +                 node_emit_json (OMP_CLAUSE_COLLAPSE_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_FINAL:
> > +      dummy->set("omp_final",
> > +                 node_emit_json (OMP_CLAUSE_FINAL_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_MERGEABLE:
> > +      dummy->set_bool("omp_clause_mergeable", true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_LINEAR:
> > +      strcpy (buffer, "omp_linear");
> > +      if (OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause))
> > +       switch (OMP_CLAUSE_LINEAR_KIND (clause))
> > +         {
> > +         case OMP_CLAUSE_LINEAR_DEFAULT:
> > +           break;
> > +         case OMP_CLAUSE_LINEAR_REF:
> > +           strcat (buffer, "_ref");
> > +           break;
> > +         case OMP_CLAUSE_LINEAR_VAL:
> > +           strcat (buffer, "_val");
> > +           break;
> > +         case OMP_CLAUSE_LINEAR_UVAL:
> > +           strcat (buffer, "_uval");
> > +           break;
> > +         default:
> > +           gcc_unreachable ();
> > +         }
> > +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> > +      if (!OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause)
> > +         && OMP_CLAUSE_LINEAR_KIND (clause) != OMP_CLAUSE_LINEAR_DEFAULT)
> > +       switch (OMP_CLAUSE_LINEAR_KIND (clause))
> > +         {
> > +           case OMP_CLAUSE_LINEAR_REF:
> > +             strcpy (buffer, "_ref,step");
> > +             break;
> > +           case OMP_CLAUSE_LINEAR_VAL:
> > +             strcpy (buffer, "_val,step");
> > +             break;
> > +           case OMP_CLAUSE_LINEAR_UVAL:
> > +             strcpy (buffer, "_uval,step");
> > +             break;
> > +           default:
> > +             gcc_unreachable ();
> > +         }
> > +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_LINEAR_STEP (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_ALIGNED:
> > +      dummy->set("omp_aligned", node_emit_json (OMP_CLAUSE_DECL(clause)));
> > +      if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause))
> > +       {
> > +          dummy->set("omp_aligned_alignment",
> > +                     node_emit_json (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause)));
> > +       }
> > +      break;
> > +
> > +    case OMP_CLAUSE_ALLOCATE:
> > +      if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause))
> > +          dummy->set("omp_allocator",
> > +                     node_emit_json (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause)));
> > +      if (OMP_CLAUSE_ALLOCATE_ALIGN (clause))
> > +          dummy->set("omp_allocate_align",
> > +                     node_emit_json (OMP_CLAUSE_ALLOCATE_ALIGN (clause)));
> > +      dummy->set("omp_allocate",
> > +                 node_emit_json (OMP_CLAUSE_DECL (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_AFFINITY:
> > +      {
> > +       tree t = OMP_CLAUSE_DECL (clause);
> > +       if (TREE_CODE (t) == TREE_LIST
> > +           && TREE_PURPOSE (t)
> > +           && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
> > +         {
> > +            omp_iterator_add_json(TREE_PURPOSE (t), dummy);
> > +           t = TREE_VALUE (t);
> > +         }
> > +        dummy->set("omp_affinity", node_emit_json(t));
> > +      }
> > +      break;
> > +
> > +    case OMP_CLAUSE_DEPEND:
> > +      strcpy (buffer, "omp_depend");
> > +      switch (OMP_CLAUSE_DEPEND_KIND (clause))
> > +       {
> > +       case OMP_CLAUSE_DEPEND_DEPOBJ:
> > +         strcat (buffer, "_depobj");
> > +         break;
> > +       case OMP_CLAUSE_DEPEND_IN:
> > +         strcat (buffer, "_in");
> > +         break;
> > +       case OMP_CLAUSE_DEPEND_OUT:
> > +         strcat (buffer, "_out");
> > +         break;
> > +       case OMP_CLAUSE_DEPEND_INOUT:
> > +         strcat (buffer, "_inout");
> > +         break;
> > +       case OMP_CLAUSE_DEPEND_MUTEXINOUTSET:
> > +         strcat (buffer, "_mutexinoutset");
> > +         break;
> > +       case OMP_CLAUSE_DEPEND_INOUTSET:
> > +         strcat (buffer, "_inoutset");
> > +         break;
> > +       case OMP_CLAUSE_DEPEND_LAST:
> > +         strcat (buffer, "__internal__");
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +       }
> > +      {
> > +       tree t = OMP_CLAUSE_DECL (clause);
> > +       if (TREE_CODE (t) == TREE_LIST
> > +           && TREE_PURPOSE (t)
> > +           && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
> > +         {
> > +           omp_iterator_add_json(TREE_PURPOSE (t), dummy);
> > +           t = TREE_VALUE (t);
> > +         }
> > +       if (t == null_pointer_node)
> > +         dummy->set_bool("omp_all_memory", true);
> > +       else
> > +          dummy->set(buffer, node_emit_json(t));
> > +      }
> > +      break;
> > +
> > +    case OMP_CLAUSE_DOACROSS:
> > +      strcpy (buffer, OMP_CLAUSE_DOACROSS_DEPEND (clause)
> > +                    ? "omp_depend" : "omp_doacross");
> > +      switch (OMP_CLAUSE_DOACROSS_KIND (clause))
> > +       {
> > +       case OMP_CLAUSE_DOACROSS_SOURCE:
> > +         if (OMP_CLAUSE_DOACROSS_DEPEND (clause))
> > +           strcat (buffer, "_source");
> > +         else
> > +           strcat (buffer, "_source:");
> > +          dummy->set_bool(buffer, true);
> > +         break;
> > +
> > +       case OMP_CLAUSE_DOACROSS_SINK:
> > +          json::array* iter_holder;
> > +          iter_holder = new json::array ();
> > +         strcat (buffer, "_sink:");
> > +         if (OMP_CLAUSE_DECL (clause) == NULL_TREE)
> > +           {
> > +             strcat (buffer, "_omp_cur_iteration-1");
> > +              dummy->set_bool(buffer, true);
> > +             break;
> > +           }
> > +         for (tree t = OMP_CLAUSE_DECL (clause); t; t = TREE_CHAIN (t))
> > +           if (TREE_CODE (t) == TREE_LIST)
> > +             {
> > +               iter_holder->append(node_emit_json(TREE_VALUE (t)));
> > +               if (TREE_PURPOSE (t) != integer_zero_node)
> > +                 {
> > +                    json::object *_x;
> > +                    _x = new json::object ();
> > +                   if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (t))
> > +                      _x->set("-", node_emit_json(TREE_PURPOSE (t)));
> > +                   else
> > +                      _x->set("+", node_emit_json(TREE_PURPOSE (t)));
> > +                    iter_holder->append(_x);
> > +                 }
> > +             }
> > +           else
> > +             gcc_unreachable ();
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +       }
> > +      break;
> > +    case OMP_CLAUSE_MAP:
> > +      strcat (buffer, "omp_map");
> > +      if (OMP_CLAUSE_MAP_READONLY (clause))
> > +       strcat (buffer, "_readonly,");
> > +      switch (OMP_CLAUSE_MAP_KIND (clause))
> > +       {
> > +       case GOMP_MAP_ALLOC:
> > +       case GOMP_MAP_POINTER:
> > +       case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
> > +         strcat (buffer, "_alloc");
> > +         break;
> > +       case GOMP_MAP_IF_PRESENT:
> > +         strcat (buffer, "_no_alloc");
> > +         break;
> > +       case GOMP_MAP_TO:
> > +       case GOMP_MAP_TO_PSET:
> > +         strcat (buffer, "_to");
> > +         break;
> > +       case GOMP_MAP_FROM:
> > +         strcat (buffer, "_from");
> > +         break;
> > +       case GOMP_MAP_TOFROM:
> > +         strcat (buffer, "_tofrom");
> > +         break;
> > +       case GOMP_MAP_FORCE_ALLOC:
> > +         strcat (buffer, "_force_alloc");
> > +         break;
> > +       case GOMP_MAP_FORCE_TO:
> > +         strcat (buffer, "_force_to");
> > +         break;
> > +       case GOMP_MAP_FORCE_FROM:
> > +         strcat (buffer, "_force_from");
> > +         break;
> > +       case GOMP_MAP_FORCE_TOFROM:
> > +         strcat (buffer, "_force_tofrom");
> > +         break;
> > +       case GOMP_MAP_FORCE_PRESENT:
> > +         strcat (buffer, "_force_present");
> > +         break;
> > +       case GOMP_MAP_DELETE:
> > +         strcat (buffer, "_delete");
> > +         break;
> > +       case GOMP_MAP_FORCE_DEVICEPTR:
> > +         strcat (buffer, "_force_deviceptr");
> > +         break;
> > +       case GOMP_MAP_ALWAYS_TO:
> > +         strcat (buffer, "_always,to");
> > +         break;
> > +       case GOMP_MAP_ALWAYS_FROM:
> > +         strcat (buffer, "_always,from");
> > +         break;
> > +       case GOMP_MAP_ALWAYS_TOFROM:
> > +         strcat (buffer, "_always,tofrom");
> > +         break;
> > +       case GOMP_MAP_RELEASE:
> > +         strcat (buffer, "_release");
> > +         break;
> > +       case GOMP_MAP_FIRSTPRIVATE_POINTER:
> > +         strcat (buffer, "_firstprivate");
> > +         break;
> > +       case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
> > +         strcat (buffer, "_firstprivate ref");
> > +         break;
> > +       case GOMP_MAP_STRUCT:
> > +         strcat (buffer, "_struct");
> > +         break;
> > +       case GOMP_MAP_STRUCT_UNORD:
> > +         strcat (buffer, "_struct_unord");
> > +         break;
> > +       case GOMP_MAP_ALWAYS_POINTER:
> > +         strcat (buffer, "_always_pointer");
> > +         break;
> > +       case GOMP_MAP_DEVICE_RESIDENT:
> > +         strcat (buffer, "_device_resident");
> > +         break;
> > +       case GOMP_MAP_LINK:
> > +         strcat (buffer, "_link");
> > +         break;
> > +       case GOMP_MAP_ATTACH:
> > +         strcat (buffer, "_attach");
> > +         break;
> > +       case GOMP_MAP_DETACH:
> > +         strcat (buffer, "_detach");
> > +         break;
> > +       case GOMP_MAP_FORCE_DETACH:
> > +         strcat (buffer, "_force_detach");
> > +         break;
> > +       case GOMP_MAP_ATTACH_DETACH:
> > +         strcat (buffer, "_attach_detach");
> > +         break;
> > +       case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
> > +         strcat (buffer, "_attach_zero_length_array_section");
> > +         break;
> > +       case GOMP_MAP_PRESENT_ALLOC:
> > +         strcat (buffer, "_present,alloc");
> > +         break;
> > +       case GOMP_MAP_PRESENT_TO:
> > +         strcat (buffer, "_present,to");
> > +         break;
> > +       case GOMP_MAP_PRESENT_FROM:
> > +         strcat (buffer, "_present,from");
> > +         break;
> > +       case GOMP_MAP_PRESENT_TOFROM:
> > +         strcat (buffer, "_present,tofrom");
> > +         break;
> > +       case GOMP_MAP_ALWAYS_PRESENT_TO:
> > +         strcat (buffer, "_always,present,to");
> > +         break;
> > +       case GOMP_MAP_ALWAYS_PRESENT_FROM:
> > +         strcat (buffer, "_always,present,from");
> > +         break;
> > +       case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
> > +         strcat (buffer, "_always,present,tofrom");
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +       }
> > +      dummy->set (buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> > +     print_clause_size:
> > +      if (OMP_CLAUSE_SIZE (clause))
> > +       {
> > +         switch (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
> > +                 ? OMP_CLAUSE_MAP_KIND (clause) : GOMP_MAP_TO)
> > +           {
> > +           case GOMP_MAP_POINTER:
> > +           case GOMP_MAP_FIRSTPRIVATE_POINTER:
> > +           case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
> > +           case GOMP_MAP_ALWAYS_POINTER:
> > +             strcpy (buffer, "pointer assign, bias");
> > +             break;
> > +           case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
> > +             strcpy (buffer,
> > +                     "pointer assign, zero-length array section, bias");
> > +             break;
> > +           case GOMP_MAP_TO_PSET:
> > +             strcpy (buffer, "pointer set, len");
> > +             break;
> > +           case GOMP_MAP_ATTACH:
> > +           case GOMP_MAP_DETACH:
> > +           case GOMP_MAP_FORCE_DETACH:
> > +           case GOMP_MAP_ATTACH_DETACH:
> > +           case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
> > +             strcpy (buffer, "bias");
> > +             break;
> > +           case GOMP_MAP_RELEASE:
> > +           case GOMP_MAP_DELETE:
> > +             if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
> > +                 && OMP_CLAUSE_RELEASE_DESCRIPTOR (clause))
> > +               {
> > +                 strcpy (buffer, "pointer set, len");
> > +                 break;
> > +               }
> > +             /* Fallthrough.  */
> > +           default:
> > +             strcpy (buffer, "len");
> > +             break;
> > +           }
> > +          dummy->set (buffer, node_emit_json (OMP_CLAUSE_SIZE (clause)));
> > +       }
> > +      if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
> > +         && OMP_CLAUSE_MAP_RUNTIME_IMPLICIT_P (clause))
> > +        dummy->set_bool("implicit", true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_FROM:
> > +      strcat (buffer, "omp_from");
> > +      if (OMP_CLAUSE_MOTION_PRESENT (clause))
> > +       strcat (buffer, "_present");
> > +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> > +      goto print_clause_size;
> > +
> > +    case OMP_CLAUSE_TO:
> > +      strcpy (buffer, "omp_to");
> > +      if (OMP_CLAUSE_MOTION_PRESENT (clause))
> > +       strcat (buffer, "_present");
> > +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> > +      goto print_clause_size;
> > +
> > +    case OMP_CLAUSE__CACHE_:
> > +      strcat (buffer, "omp__cache__");
> > +      if (OMP_CLAUSE__CACHE__READONLY (clause))
> > +       strcat (buffer, "_readonly");
> > +      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
> > +      goto print_clause_size;
> > +
> > +    case OMP_CLAUSE_NUM_TEAMS:
> > +      strcat (buffer, "omp_num_teams");
> > +      if (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (clause))
> > +       {
> > +          dummy->set("omp_num_teams_lower",
> > +                     node_emit_json (
> > +                         OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (clause)));
> > +          strcat (buffer, "_upper");
> > +       }
> > +      else
> > +        dummy->set(buffer,
> > +                   node_emit_json (OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_THREAD_LIMIT:
> > +      dummy->set("omp_thread_limit",
> > +                 node_emit_json (OMP_CLAUSE_THREAD_LIMIT_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_DEVICE:
> > +      strcpy (buffer, "omp_device(");
> > +      if (OMP_CLAUSE_DEVICE_ANCESTOR (clause))
> > +       strcat (buffer, "_ancestor:");
> > +      dummy->set(buffer,
> > +                 node_emit_json (OMP_CLAUSE_DEVICE_ID (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_DIST_SCHEDULE:
> > +      strcat (buffer, "omp_dist_schedule(static)");
> > +      if (OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause))
> > +       {
> > +         dummy->set(buffer,
> > +                    node_emit_json (
> > +                        OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause)));
> > +       }
> > +      else
> > +        dummy->set_bool(buffer, true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_PROC_BIND:
> > +      strcpy (buffer, "omp_proc_bind(");
> > +      switch (OMP_CLAUSE_PROC_BIND_KIND (clause))
> > +       {
> > +       case OMP_CLAUSE_PROC_BIND_MASTER:
> > +         strcat (buffer, "_master");
> > +         break;
> > +       case OMP_CLAUSE_PROC_BIND_CLOSE:
> > +         strcat (buffer, "_close");
> > +         break;
> > +       case OMP_CLAUSE_PROC_BIND_SPREAD:
> > +         strcat (buffer, "_spread");
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +       }
> > +      dummy->set_bool(buffer, true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_DEVICE_TYPE:
> > +    strcpy (buffer, "omp_device_type");
> > +      switch (OMP_CLAUSE_DEVICE_TYPE_KIND (clause))
> > +       {
> > +       case OMP_CLAUSE_DEVICE_TYPE_HOST:
> > +         strcat (buffer, "_host");
> > +         break;
> > +       case OMP_CLAUSE_DEVICE_TYPE_NOHOST:
> > +         strcat (buffer, "_nohost");
> > +         break;
> > +       case OMP_CLAUSE_DEVICE_TYPE_ANY:
> > +         strcat (buffer, "_any");
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +       }
> > +      dummy->set_bool(buffer, true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_SAFELEN:
> > +      dummy->set("omp_safelen",
> > +                 node_emit_json (OMP_CLAUSE_SAFELEN_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_SIMDLEN:
> > +      dummy->set("omp_simdlen",
> > +                 node_emit_json (OMP_CLAUSE_SIMDLEN_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_PRIORITY:
> > +      dummy->set("omp_priority",
> > +                 node_emit_json (OMP_CLAUSE_PRIORITY_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_GRAINSIZE:
> > +      strcpy (buffer, "omp_grainsize");
> > +      if (OMP_CLAUSE_GRAINSIZE_STRICT (clause))
> > +        strcat (buffer, "_strict");
> > +      dummy->set(buffer,
> > +                 node_emit_json (OMP_CLAUSE_GRAINSIZE_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_NUM_TASKS:
> > +      strcpy (buffer, "omp_num_tasks");
> > +      if (OMP_CLAUSE_NUM_TASKS_STRICT (clause))
> > +       strcat (buffer, "_strict");
> > +      dummy->set(buffer,
> > +                 node_emit_json (OMP_CLAUSE_NUM_TASKS_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_HINT:
> > +      dummy->set("omp_hint",
> > +                 node_emit_json (OMP_CLAUSE_HINT_EXPR(clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_FILTER:
> > +      dummy->set("omp_filter",
> > +                 node_emit_json (OMP_CLAUSE_FILTER_EXPR(clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_DEFAULTMAP:
> > +      strcat (buffer, "omp_defaultmap");
> > +      switch (OMP_CLAUSE_DEFAULTMAP_BEHAVIOR (clause))
> > +       {
> > +       case OMP_CLAUSE_DEFAULTMAP_ALLOC:
> > +         strcat (buffer, "_alloc");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_TO:
> > +         strcat (buffer, "_to");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_FROM:
> > +         strcat (buffer, "_from");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_TOFROM:
> > +         strcat (buffer, "_tofrom");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE:
> > +         strcat (buffer, "_firstprivate");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_NONE:
> > +         strcat (buffer, "_none");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_PRESENT:
> > +         strcat (buffer, "_present");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_DEFAULT:
> > +         strcat (buffer, "_default");
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +       }
> > +      //Check later if we're happy with this
> > +      switch (OMP_CLAUSE_DEFAULTMAP_CATEGORY (clause))
> > +       {
> > +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED:
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL:
> > +         strcat (buffer, ":all");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR:
> > +         strcat (buffer, ":scalar");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE:
> > +         strcat (buffer, ":aggregate");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALLOCATABLE:
> > +         strcat (buffer, ":allocatable");
> > +         break;
> > +       case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER:
> > +         strcat (buffer, ":pointer");
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +       }
> > +      dummy->set_bool(buffer, true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_ORDER:
> > +      strcpy (buffer, "omp_order_");
> > +      if (OMP_CLAUSE_ORDER_UNCONSTRAINED (clause))
> > +       strcat (buffer, "unconstrained:");
> > +      else if (OMP_CLAUSE_ORDER_REPRODUCIBLE (clause))
> > +       strcat (buffer, "reproducible:");
> > +      strcat (buffer, "concurrent)");
> > +      dummy->set_bool(buffer, true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_BIND:
> > +      strcpy (buffer, "omp_bind");
> > +      switch (OMP_CLAUSE_BIND_KIND (clause))
> > +       {
> > +       case OMP_CLAUSE_BIND_TEAMS:
> > +         strcat (buffer, "_teams");
> > +         break;
> > +       case OMP_CLAUSE_BIND_PARALLEL:
> > +         strcat (buffer, "_parallel");
> > +         break;
> > +       case OMP_CLAUSE_BIND_THREAD:
> > +         strcat (buffer, "_thread");
> > +         break;
> > +       default:
> > +         gcc_unreachable ();
> > +       }
> > +      dummy->set_bool(buffer, true);
> > +      break;
> > +
> > +    case OMP_CLAUSE__SIMDUID_:
> > +      dummy->set("omp__simduid__",
> > +                 node_emit_json(OMP_CLAUSE__SIMDUID__DECL (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE__SIMT_:
> > +      dummy->set_bool("omp__simt__", true);
> > +      break;
> > +
> > +    //In our current implementation, we dump exprs etc even if not NULL.
> > +    case OMP_CLAUSE_GANG:
> > +      dummy->set_bool ("omp_gang", true);
> > +      if (OMP_CLAUSE_GANG_EXPR (clause) != NULL_TREE)
> > +          dummy->set("num", node_emit_json (OMP_CLAUSE_GANG_EXPR (clause)));
> > +      if (OMP_CLAUSE_GANG_STATIC_EXPR (clause) != NULL_TREE)
> > +       {
> > +         strcpy (buffer, "static");
> > +         if (OMP_CLAUSE_GANG_STATIC_EXPR (clause)
> > +             == integer_minus_one_node)
> > +           strcat (buffer, "*");
> > +          dummy->set(buffer,
> > +                     node_emit_json (OMP_CLAUSE_GANG_STATIC_EXPR (clause)));
> > +       }
> > +      break;
> > +
> > +    case OMP_CLAUSE_ASYNC:
> > +      dummy->set("omp_async",
> > +                 node_emit_json (OMP_CLAUSE_ASYNC_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_AUTO:
> > +    case OMP_CLAUSE_SEQ:
> > +      strcpy (buffer, omp_clause_code_name[OMP_CLAUSE_CODE (clause)]);
> > +      dummy->set_bool(buffer, true);
> > +      break;
> > +
> > +    case OMP_CLAUSE_WAIT:
> > +      dummy->set("omp_wait",
> > +                 node_emit_json (OMP_CLAUSE_WAIT_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_WORKER:
> > +      dummy->set("omp_worker",
> > +                 node_emit_json (OMP_CLAUSE_WORKER_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_VECTOR:
> > +      dummy->set("omp_vector",
> > +                 node_emit_json (OMP_CLAUSE_VECTOR_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_NUM_GANGS:
> > +      dummy->set("omp_num_gangs",
> > +                 node_emit_json (OMP_CLAUSE_NUM_GANGS_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_NUM_WORKERS:
> > +      dummy->set("omp_num_workers",
> > +                 node_emit_json (OMP_CLAUSE_NUM_WORKERS_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_VECTOR_LENGTH:
> > +      dummy->set("omp_vector_length",
> > +                 node_emit_json (OMP_CLAUSE_VECTOR_LENGTH_EXPR (clause)));
> > +      break;
> > +
> > +    case OMP_CLAUSE_INBRANCH:
> > +      dummy->set_bool ("inbranch", true);
> > +      break;
> > +    case OMP_CLAUSE_NOTINBRANCH:
> > +      dummy->set_bool ("notinbranch", true);
> > +      break;
> > +    case OMP_CLAUSE_FOR:
> > +      dummy->set_bool ("for", true);
> > +      break;
> > +    case OMP_CLAUSE_PARALLEL:
> > +      dummy->set_bool ("parallel", true);
> > +      break;
> > +    case OMP_CLAUSE_SECTIONS:
> > +      dummy->set_bool ("sections", true);
> > +      break;
> > +    case OMP_CLAUSE_TASKGROUP:
> > +      dummy->set_bool ("taskgroup", true);
> > +      break;
> > +    case OMP_CLAUSE_NOGROUP:
> > +      dummy->set_bool ("nogroup", true);
> > +      break;
> > +    case OMP_CLAUSE_THREADS:
> > +      dummy->set_bool ("threads", true);
> > +      break;
> > +    case OMP_CLAUSE_SIMD:
> > +      dummy->set_bool ("simd", true);
> > +      break;
> > +    case OMP_CLAUSE_INDEPENDENT:
> > +      dummy->set_bool ("independent", true);
> > +      break;
> > +    case OMP_CLAUSE_TILE:
> > +      dummy->set ("omp_tile", node_emit_json (OMP_CLAUSE_TILE_LIST (clause)));
> > +      break;
> > +    case OMP_CLAUSE_PARTIAL:
> > +      dummy->set ("omp_partial",
> > +                  node_emit_json (OMP_CLAUSE_PARTIAL_EXPR (clause)));
> > +      break;
> > +    case OMP_CLAUSE_FULL:
> > +      dummy->set_bool("full", true);
> > +      break;
> > +    case OMP_CLAUSE_SIZES:
> > +      dummy->set("omp_sizes", node_emit_json (
> > +                 OMP_CLAUSE_SIZES_LIST (clause)));
> > +      break;
> > +    case OMP_CLAUSE_IF_PRESENT:
> > +      dummy->set_bool("if_present", true);
> > +      break;
> > +    case OMP_CLAUSE_FINALIZE:
> > +      dummy->set_bool("finalize", true);
> > +      break;
> > +    case OMP_CLAUSE_NOHOST:
> > +      dummy->set_bool("nohost", true);
> > +      break;
> > +    case OMP_CLAUSE_DETACH:
> > +      dummy->set("omp_detach", node_emit_json (OMP_CLAUSE_DECL (clause)));
> > +      break;
> > +    default:
> > +      gcc_unreachable();
> > +    }
> > +}
> > +
> > +void
> > +omp_atomic_memory_order_add_json (json::object* dummy,
> > +                                  enum omp_memory_order mo)
> > +{
> > +  switch (mo & OMP_MEMORY_ORDER_MASK)
> > +    {
> > +    case OMP_MEMORY_ORDER_RELAXED:
> > +      dummy->set_string ("omp_memory_order", "relaxed");
> > +      break;
> > +    case OMP_MEMORY_ORDER_SEQ_CST:
> > +      dummy->set_string ("omp_memory_order", "seq_cst");
> > +      break;
> > +    case OMP_MEMORY_ORDER_ACQ_REL:
> > +      dummy->set_string ("omp_memory_order", "acq_rel");
> > +      break;
> > +    case OMP_MEMORY_ORDER_ACQUIRE:
> > +      dummy->set_string ("omp_memory_order", "acquire");
> > +      break;
> > +    case OMP_MEMORY_ORDER_RELEASE:
> > +      dummy->set_string ("omp_memory_order", "release");
> > +      break;
> > +    case OMP_MEMORY_ORDER_UNSPECIFIED:
> > +      break;
> > +    default:
> > +      gcc_unreachable ();
> > +    }
> > +  switch (mo & OMP_FAIL_MEMORY_ORDER_MASK)
> > +    {
> > +    case OMP_FAIL_MEMORY_ORDER_RELAXED:
> > +      dummy->set_string ("omp_memory_order", "fail(relaxed)");
> > +      break;
> > +    case OMP_FAIL_MEMORY_ORDER_SEQ_CST:
> > +      dummy->set_string ("omp_memory_order", "fail(seq_cst)");
> > +      break;
> > +    case OMP_FAIL_MEMORY_ORDER_ACQUIRE:
> > +      dummy->set_string ("omp_memory_order", "fail(acquire)");
> > +      break;
> > +    case OMP_FAIL_MEMORY_ORDER_UNSPECIFIED:
> > +      dummy->set_string ("omp_memory_order", "fail(unspecified)");
> > +      break;
> > +    default:
> > +      gcc_unreachable ();
> > +    }
> > +}
> > +
> > +json::object*
> > +omp_atomic_memory_order_emit_json(omp_memory_order mo)
> > +{
> > +  json::object* _x;
> > +  _x = new json::object ();
> > +  omp_atomic_memory_order_add_json(_x, mo);
> > +  return _x;
> > +}
> > +
> > +json::object*
> > +omp_clause_emit_json(tree t)
> > +{
> > +  json::object* _x;
> > +  _x = new json::object ();
> > +  omp_clause_add_json(t, _x);
> > +  return _x;
> > +}
> > +
> > +json::array*
> > +loc_emit_json (expanded_location xloc)
> > +{
> > +  json::array *loc_holder;
> > +  json::object *loc_info;
> > +  loc_info = new json::object ();
> > +  loc_info->set_string("file", xloc.file);
> > +  loc_info->set_integer("line", xloc.line);
> > +  loc_info->set_integer("column", xloc.column);
> > +  loc_holder = new json::array ();
> > +  loc_holder->append(loc_info);
> > +  return loc_holder;
> > +}
> > +
> > +/* Here we emit JSON data for a GENERIC node and children.
> > + * c.f. dump_generic_node and print-tree's debug_tree().   */
> > +
> > +json::object*
> > +node_emit_json(tree t)
> > +{
> > +  tree op0, op1, type;
> > +  enum tree_code code;
> > +  expanded_location xloc;
> > +  json::object *dummy;
> > +  json::array* holder;
> > +  char address_buffer[sizeof(&t)] = {"\0"};
> > +
> > +  dummy = new json::object ();
> > +  holder = new json::array ();
> > +
> > +  code = TREE_CODE (t);
> > +
> > +  address_add_json(t, dummy, address_buffer);
> > +
> > +  if (TREE_CODE_CLASS (code) == tcc_declaration
> > +      && code != TRANSLATION_UNIT_DECL)
> > +    {
> > +    xloc = expand_location (DECL_SOURCE_LOCATION (t));
> > +    dummy->set("decl_loc", loc_emit_json(xloc));
> > +    }
> > +  if (EXPR_HAS_LOCATION(t))
> > +    {
> > +      xloc = expand_location (EXPR_LOCATION (t));
> > +      dummy->set("expr_loc", loc_emit_json(xloc));
> > +    }
> > +  if (EXPR_HAS_RANGE (t))
> > +    {
> > +      source_range r = EXPR_LOCATION_RANGE (t);
> > +      if (r.m_start)
> > +      {
> > +        xloc = expand_location (r.m_start);
> > +        dummy->set("start_loc", loc_emit_json(xloc));
> > +      } else {
> > +        dummy->set_string("start_loc", "unknown");
> > +      }
> > +      if (r.m_finish)
> > +      {
> > +        xloc = expand_location (r.m_finish);
> > +        dummy->set("finish_loc", loc_emit_json(xloc));
> > +      } else {
> > +        dummy->set_string("finish_loc", "unknown");
> > +      }
> > +    }
> > +  dummy->set_string("tree code", get_tree_code_name(TREE_CODE (t)));
> > +  //Flag handling
> > +  if (TREE_ADDRESSABLE (t))
> > +    dummy->set_bool ("addressable", true);
> > +  if (TREE_THIS_VOLATILE (t))
> > +    dummy->set_bool ("volatile", true);
> > +  if (TREE_ASM_WRITTEN (t))
> > +    dummy->set_bool ("asm_written", true);
> > +  if (TREE_USED (t))
> > +    dummy->set_bool ("used", true);
> > +  if (TREE_NOTHROW (t))
> > +    dummy->set_bool ("nothrow", true);
> > +  if (TREE_PUBLIC (t))
> > +    dummy->set_bool ("public", true);
> > +  if (TREE_PRIVATE (t))
> > +    dummy->set_bool ("private", true);
> > +  if (TREE_PROTECTED (t))
> > +    dummy->set_bool ("protected", true);
> > +  if (TREE_STATIC (t))
> > +    dummy->set_bool (code == CALL_EXPR ? " must-tail-call"
> > +                                       : " static", true);
> > +  if (TREE_DEPRECATED (t))
> > +    dummy->set_bool ("deprecated", true);
> > +  if (TREE_VISITED (t))
> > +    dummy->set_bool ("visited", true);
> > +
> > +  if (code != TREE_VEC && code != SSA_NAME && code != INTEGER_CST)
> > +    {
> > +      if (TREE_UNAVAILABLE (t))
> > +       dummy->set_bool ("unavailable", true);
> > +      if (TREE_LANG_FLAG_0 (t))
> > +       dummy->set_bool ("tree_0", true);
> > +      if (TREE_LANG_FLAG_1 (t))
> > +        dummy->set_bool ("tree_1", true);
> > +      if (TREE_LANG_FLAG_2 (t))
> > +       dummy->set_bool ("tree_2", true);
> > +      if (TREE_LANG_FLAG_3 (t))
> > +       dummy->set_bool ("tree_3", true);
> > +      if (TREE_LANG_FLAG_4 (t))
> > +       dummy->set_bool ("tree_4", true);
> > +      if (TREE_LANG_FLAG_5 (t))
> > +       dummy->set_bool ("tree_5", true);
> > +      if (TREE_LANG_FLAG_6 (t))
> > +       dummy->set_bool ("tree_6", true);
> > +    }
> > +
> > +  if (TREE_CODE_CLASS(code) == tcc_declaration)
> > +    {
> > +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> > +        {
> > +          if (DECL_UNSIGNED (t))
> > +            dummy->set_bool ("unsigned", true);
> > +          if (DECL_IGNORED_P (t))
> > +            dummy->set_bool ("ignored", true);
> > +          if (DECL_ABSTRACT_P (t))
> > +            dummy->set_bool ("abstract", true);
> > +          if (DECL_EXTERNAL (t))
> > +            dummy->set_bool ("external", true);
> > +         if (DECL_NONLOCAL (t))
> > +           dummy->set_bool ("nonlocal", true);
> > +       }
> > +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
> > +        {
> > +         if (DECL_WEAK (t))
> > +           dummy->set_bool ("weak", true);
> > +         if (DECL_IN_SYSTEM_HEADER (t))
> > +           dummy->set_bool ("in_system_header", true);
> > +        }
> > +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)
> > +         && code != LABEL_DECL
> > +         && code != FUNCTION_DECL
> > +         && DECL_REGISTER (t))
> > +       dummy->set_bool ("regdecl", true);
> > +
> > +      if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (t))
> > +       dummy->set_bool ("suppress-debug", true);
> > +
> > +      if (code == FUNCTION_DECL
> > +         && DECL_FUNCTION_SPECIFIC_TARGET (t))
> > +       dummy->set_bool ("function-specific-target", true);
> > +      if (code == FUNCTION_DECL
> > +         && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (t))
> > +       dummy->set_bool ("function-specific-opt", true);
> > +      if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (t))
> > +       dummy->set_bool ("autoinline", true);
> > +      if (code == FUNCTION_DECL && DECL_UNINLINABLE (t))
> > +       dummy->set_bool ("uninlinable", true);
> > +      if (code == FUNCTION_DECL && fndecl_built_in_p (t))
> > +       dummy->set_bool ("built-in", true);
> > +      if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (t))
> > +       dummy->set_bool ("static-chain", true);
> > +      if (TREE_CODE (t) == FUNCTION_DECL && decl_is_tm_clone (t))
> > +       dummy->set_bool ("tm-clone", true);
> > +
> > +      if (code == FIELD_DECL && DECL_PACKED (t))
> > +       dummy->set_bool ("packed", true);
> > +      if (code == FIELD_DECL && DECL_BIT_FIELD (t))
> > +       dummy->set_bool ("bit-field", true);
> > +      if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (t))
> > +       dummy->set_bool ("nonaddressable", true);
> > +
> > +      if (code == LABEL_DECL && EH_LANDING_PAD_NR (t))
> > +        dummy->set_integer("landing_pad", EH_LANDING_PAD_NR(t));
> > +
> > +      if (code == VAR_DECL && DECL_IN_TEXT_SECTION (t))
> > +       dummy->set_bool ("in-text-section", true);
> > +      if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (t))
> > +       dummy->set_bool ("in-constant-pool", true);
> > +      if (code == VAR_DECL && DECL_COMMON (t))
> > +       dummy->set_bool ("common", true);
> > +      if ((code == VAR_DECL || code == PARM_DECL) && DECL_READ_P (t))
> > +       dummy->set_bool ("read", true);
> > +      if (code == VAR_DECL && DECL_THREAD_LOCAL_P (t))
> > +         dummy->set_bool (tls_model_names[DECL_TLS_MODEL (t)], true);
> > +
> > +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
> > +       {
> > +         if (DECL_VIRTUAL_P (t))
> > +           dummy->set_bool ("virtual", true);
> > +         if (DECL_PRESERVE_P (t))
> > +           dummy->set_bool ("preserve", true);
> > +         if (DECL_LANG_FLAG_0 (t))
> > +           dummy->set_bool ("decl_0", true);
> > +         if (DECL_LANG_FLAG_1 (t))
> > +           dummy->set_bool ("decl_1", true);
> > +         if (DECL_LANG_FLAG_2 (t))
> > +           dummy->set_bool ("decl_2", true);
> > +         if (DECL_LANG_FLAG_3 (t))
> > +           dummy->set_bool ("decl_3", true);
> > +         if (DECL_LANG_FLAG_4 (t))
> > +           dummy->set_bool ("decl_4", true);
> > +         if (DECL_LANG_FLAG_5 (t))
> > +           dummy->set_bool ("decl_5", true);
> > +         if (DECL_LANG_FLAG_6 (t))
> > +           dummy->set_bool ("decl_6", true);
> > +         if (DECL_LANG_FLAG_7 (t))
> > +           dummy->set_bool ("decl_7", true);
> > +         if (DECL_LANG_FLAG_8 (t))
> > +           dummy->set_bool ("decl_8", true);
> > +
> > +         dummy->set_string("mode", GET_MODE_NAME (DECL_MODE (t)));
> > +       }
> > +
> > +
> > +      if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
> > +         && DECL_BY_REFERENCE (t))
> > +       dummy->set_bool ("passed-by-reference", true);
> > +
> > +      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)
> > +                                && DECL_DEFER_OUTPUT (t))
> > +       dummy->set_bool ("defer-output", true);
> > +
> > +    } //end tcc_decl flags
> > +
> > +    if (TREE_CODE_CLASS(code) == tcc_type)
> > +      {
> > +      if (TYPE_UNSIGNED (t))
> > +       dummy->set_bool ("unsigned", true);
> > +
> > +      if (TYPE_NO_FORCE_BLK (t))
> > +       dummy->set_bool ("no-force-blk", true);
> > +
> > +      if (code == ARRAY_TYPE && TYPE_STRING_FLAG (t))
> > +       dummy->set_bool ("string-flag", true);
> > +
> > +      if (TYPE_NEEDS_CONSTRUCTING (t))
> > +       dummy->set_bool ("needs-constructing", true);
> > +
> > +      if ((code == RECORD_TYPE
> > +          || code == UNION_TYPE
> > +          || code == QUAL_UNION_TYPE
> > +          || code == ARRAY_TYPE)
> > +         && TYPE_REVERSE_STORAGE_ORDER (t))
> > +       dummy->set_bool ("reverse-storage-order", true);
> > +
> > +      if ((code == RECORD_TYPE
> > +          || code == UNION_TYPE)
> > +         && TYPE_CXX_ODR_P (t))
> > +       dummy->set_bool ("cxx-odr-p", true);
> > +
> > +      if ((code == RECORD_TYPE
> > +          || code == UNION_TYPE)
> > +         && TYPE_CXX_ODR_P (t))
> > +       dummy->set_bool ("cxx-odr-p", true);
> > +
> > +      if ((code == RECORD_TYPE
> > +          || code == UNION_TYPE)
> > +         && TYPE_INCLUDES_FLEXARRAY (t))
> > +       dummy->set_bool ("includes-flexarray", true);
> > +
> > +      if ((code == UNION_TYPE || code == RECORD_TYPE)
> > +         && TYPE_TRANSPARENT_AGGR (t))
> > +       dummy->set_bool ("transparent-aggr", true);
> > +      else if (code == ARRAY_TYPE
> > +              && TYPE_NONALIASED_COMPONENT (t))
> > +       dummy->set_bool ("nonaliased-component", true);
> > +
> > +      if (TYPE_PACKED (t))
> > +       dummy->set_bool ("packed", true);
> > +
> > +      if (TYPE_RESTRICT (t))
> > +       dummy->set_bool ("restrict", true);
> > +
> > +      if (TYPE_LANG_FLAG_0 (t))
> > +       dummy->set_bool ("type_0", true);
> > +      if (TYPE_LANG_FLAG_1 (t))
> > +       dummy->set_bool ("type_1", true);
> > +      if (TYPE_LANG_FLAG_2 (t))
> > +       dummy->set_bool ("type_2", true);
> > +      if (TYPE_LANG_FLAG_3 (t))
> > +       dummy->set_bool ("type_3", true);
> > +      if (TYPE_LANG_FLAG_4 (t))
> > +       dummy->set_bool ("type_4", true);
> > +      if (TYPE_LANG_FLAG_5 (t))
> > +       dummy->set_bool ("type_5", true);
> > +      if (TYPE_LANG_FLAG_6 (t))
> > +       dummy->set_bool ("type_6", true);
> > +      if (TYPE_LANG_FLAG_7 (t))
> > +       dummy->set_bool ("type_7", true);
> > +      } //end tcc_type flags
> > +
> > +  // Accessors
> > +  switch (code)
> > +  {
> > +    case IDENTIFIER_NODE:
> > +      dummy->set_string("identifier",
> > +                        identifier_to_locale ((IDENTIFIER_POINTER(t))));
> > +      break;
> > +    case TREE_LIST:
> > +      while (t && t != error_mark_node)
> > +      {
> > +        if (TREE_PURPOSE (t))
> > +       {
> > +          holder->append(node_emit_json(TREE_PURPOSE(t)));
> > +       }
> > +       holder->append(node_emit_json(TREE_VALUE(t)));
> > +        t = TREE_CHAIN(t);
> > +      }
> > +      break;
> > +    case TREE_BINFO:
> > +      holder->append(node_emit_json(BINFO_TYPE(t)));
> > +      break;
> > +    case TREE_VEC:
> > +      {
> > +        size_t i;
> > +        if (TREE_VEC_LENGTH(t) > 0)
> > +         {
> > +            size_t len = TREE_VEC_LENGTH (t);
> > +           for (i = 0; i < len ; i++)
> > +           {
> > +             holder->append(node_emit_json(TREE_VEC_ELT(t, i)));
> > +           }
> > +         }
> > +      }
> > +      break;
> > +
> > +    case VOID_TYPE:
> > +    case INTEGER_TYPE:
> > +    case REAL_TYPE:
> > +    case FIXED_POINT_TYPE:
> > +    case COMPLEX_TYPE:
> > +    case VECTOR_TYPE:
> > +    case ENUMERAL_TYPE:
> > +    case BOOLEAN_TYPE:
> > +    case BITINT_TYPE:
> > +    case OPAQUE_TYPE:
> > +      {
> > +       unsigned int quals = TYPE_QUALS (t);
> > +       enum tree_code_class tclass;
> > +        json::object* _x;
> > +
> > +        _x = new json::object ();
> > +
> > +       if (quals & TYPE_QUAL_ATOMIC)
> > +         _x->set_bool("atomic", true);
> > +       if (quals & TYPE_QUAL_CONST)
> > +         _x->set_bool("const", true);
> > +       if (quals & TYPE_QUAL_VOLATILE)
> > +         _x->set_bool("volatile", true);
> > +       if (quals & TYPE_QUAL_RESTRICT)
> > +         _x->set_bool("restrict", true);
> > +
> > +        dummy->set("quals", _x);
> > +
> > +       if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t)))
> > +           dummy->set_integer("address space", TYPE_ADDR_SPACE(t));
> > +
> > +       tclass = TREE_CODE_CLASS (TREE_CODE(t));
> > +
> > +       if (tclass == tcc_declaration)
> > +         {
> > +         if (DECL_NAME (t))
> > +            decl_node_add_json(t, dummy);
> > +         else
> > +           dummy->set_string("decl", "<unnamed type decl>");
> > +         }
> > +       else if (tclass == tcc_type)
> > +         {
> > +           if (TYPE_NAME (t))
> > +           {
> > +             if (TREE_CODE(TYPE_NAME (t)) == IDENTIFIER_NODE)
> > +                dummy->set("identifier", node_emit_json(TYPE_NAME(t)));
> > +             else if (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
> > +                      && DECL_NAME (TYPE_NAME (t)))
> > +                decl_node_add_json( TYPE_NAME (t), dummy);
> > +             else
> > +                dummy->set_string("type_name", "unnamed");
> > +           }
> > +            else if (TREE_CODE (t) == VECTOR_TYPE)
> > +             {
> > +              for (long unsigned int i = 0; i < NUM_POLY_INT_COEFFS; i++)
> > +                {
> > +                  auto _poly_int = TYPE_VECTOR_SUBPARTS(t);
> > +                  dummy->set_integer("foo", _poly_int.coeffs[i]);
> > +                }
> > +              dummy->set("vector_subparts", holder);
> > +             }
> > +            else if (TREE_CODE (t) == INTEGER_TYPE)
> > +             {
> > +               if (TYPE_PRECISION (t) == CHAR_TYPE_SIZE)
> > +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> > +                                                  ? "unsigned char"
> > +                                                  : "signed char"));
> > +               else if (TYPE_PRECISION (t) == SHORT_TYPE_SIZE)
> > +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> > +                                                  ? "unsigned short"
> > +                                                  : "signed short"));
> > +               else if (TYPE_PRECISION (t) == INT_TYPE_SIZE)
> > +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> > +                                                  ? "unsigned int"
> > +                                                  : "signed int"));
> > +               else if (TYPE_PRECISION (t) == LONG_TYPE_SIZE)
> > +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> > +                                                  ? "unsigned long"
> > +                                                  : "signed long"));
> > +               else if (TYPE_PRECISION (t) == LONG_LONG_TYPE_SIZE)
> > +                 dummy->set_string("type precision", (TYPE_UNSIGNED(t)
> > +                                                  ? "unsigned long long"
> > +                                                  : "signed long long"));
> > +               else if (TYPE_PRECISION (t) == CHAR_TYPE_SIZE
> > + && pow2p_hwi (TYPE_PRECISION (t)))
> > +                   dummy->set_integer(TYPE_UNSIGNED(t) ? "uint": "int",
> > +                                      TYPE_PRECISION(t));
> > +               else
> > +                   dummy->set_integer(TYPE_UNSIGNED(t)
> > +                                     ? "unnamed-unsigned"
> > +                                     : "unnamed-signed", TYPE_PRECISION(t));
> > +             }
> > +           else if (TREE_CODE (t) == COMPLEX_TYPE)
> > +             {
> > +               holder->append(node_emit_json(TREE_TYPE(t)));
> > +                dummy->set("complex", holder);
> > +             }
> > +           else if (TREE_CODE (t) == REAL_TYPE)
> > +             {
> > +               dummy->set_integer("float", TYPE_PRECISION(t));
> > +             }
> > +           else if (TREE_CODE (t) == FIXED_POINT_TYPE)
> > +             {
> > +               dummy->set_integer("fixed point", TYPE_PRECISION(t));
> > +             }
> > +           else if (TREE_CODE (t) == BOOLEAN_TYPE)
> > +             {
> > +               dummy->set_integer(TYPE_UNSIGNED(t)
> > +                                  ? "unsigned boolean"
> > +                                  : "signed boolean", TYPE_PRECISION(t));
> > +             }
> > +           else if (TREE_CODE (t) == BITINT_TYPE)
> > +             {
> > +               dummy->set_integer(TYPE_UNSIGNED (t)
> > +                                  ? "unsigned_BitInt"
> > +                                  : "_BitInt", TYPE_PRECISION(t));
> > +             }
> > +           else if (TREE_CODE (t) == VOID_TYPE)
> > +             dummy->set_bool("float", true);
> > +           else
> > +             dummy->set_bool("unnamed type", true);
> > +          }
> > +      }
> > +      break;
> > +
> > +    case POINTER_TYPE:
> > +    case REFERENCE_TYPE:
> > +      {
> > +        if (TREE_TYPE (t) == NULL)
> > +         dummy->set_bool("null type", true);
> > +        else if (TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
> > +          {
> > +            tree function_node = TREE_TYPE(t);
> > +           tree arg_node = TYPE_ARG_TYPES(function_node);
> > +           json::array* args_holder;
> > +           json::object* it_args;
> > +           json::object* _id;
> > +
> > +           args_holder = new json::array ();
> > +           _id = new json::object ();
> > +
> > +            dummy->set("fnode", node_emit_json(function_node));
> > +
> > +           if (TYPE_IDENTIFIER (t))
> > +             _id->set("type identifier", node_emit_json(TYPE_NAME(t)));
> > +            else
> > +              {
> > +                char* buff;
> > +                buff = new char ();
> > +                print_hex(TYPE_UID(t), buff);
> > +               _id->set_string("uid", buff);
> > +              }
> > +            dummy->set("function decl",
> > +                       function_decl_emit_json(function_node));
> > +            if (arg_node && arg_node != void_list_node
> > +                && arg_node != error_mark_node)
> > +             it_args = new json::object();
> > +            while (arg_node && arg_node != void_list_node
> > +                   && arg_node != error_mark_node)
> > +             {
> > +               it_args = node_emit_json(arg_node);
> > +               args_holder->append(it_args);
> > +               arg_node = TREE_CHAIN (arg_node);
> > +             }
> > +           dummy->set("type_uid", _id);
> > +           dummy->set("args", args_holder);
> > +          }
> > +        else
> > +          {
> > +         unsigned int quals = TYPE_QUALS (t);
> > +         dummy->set("tree_type", node_emit_json(TREE_TYPE(t)));
> > +         json::object *_x;
> > +
> > +          _x = new json::object ();
> > +
> > +         if (quals & TYPE_QUAL_ATOMIC)
> > +           _x->set_bool("atomic", true);
> > +         if (quals & TYPE_QUAL_CONST)
> > +           _x->set_bool("const", true);
> > +         if (quals & TYPE_QUAL_VOLATILE)
> > +           _x->set_bool("volatile", true);
> > +         if (quals & TYPE_QUAL_RESTRICT)
> > +           _x->set_bool("restrict", true);
> > +
> > +          dummy->set("quals", _x);
> > +         if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t)))
> > +           dummy->set_integer("address space", TYPE_ADDR_SPACE (t));
> > +         if (TYPE_REF_CAN_ALIAS_ALL (t))
> > +           dummy->set_bool("ref can alias all", true);
> > +          }
> > +      }
> > +      break;
> > +
> > +    case OFFSET_TYPE:
> > +      break;
> > +
> > +    case MEM_REF:
> > +    case TARGET_MEM_REF:
> > +      {
> > +        if (TREE_CODE (t) == MEM_REF
> > +            && integer_zerop (TREE_OPERAND (t, 1))
> > +            && TREE_CODE (TREE_OPERAND (t, 0)) != INTEGER_CST
> > +            && TREE_TYPE (TREE_OPERAND (t, 0)) != NULL_TREE
> > +            && (TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)))
> > +                == TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 1))))
> > +            && (TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0)))
> > +                == TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 1))))
> > +            && (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (t, 0)))
> > +                == TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (t, 1))))
> > +            && (TYPE_MAIN_VARIANT (TREE_TYPE (t))
> > +                == TYPE_MAIN_VARIANT (
> > +                       TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 1))))))
> > +          {
> > +            if (TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR)
> > +              {
> > +                dummy->set("base", node_emit_json(TREE_OPERAND (t, 0)));
> > +              }
> > +            else
> > +              dummy->set("base", node_emit_json(
> > +                                     TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
> > +          }
> > +        else
> > +          { //Check later
> > +            tree type = TREE_TYPE(t);
> > +            tree op1 = TREE_OPERAND(t, 1);
> > +            tree op1type = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
> > +
> > +            tree op0size = TYPE_SIZE(type);
> > +            tree op1size = TYPE_SIZE (TREE_TYPE(op1type));
> > +
> > +            if (!op0size || !op1size
> > +                || ! operand_equal_p(op0size, op1size, 0))
> > +            {
> > +              dummy->set("tree_type_size", node_emit_json(type));
> > +            }
> > +            dummy->set("op1_type_size", node_emit_json(op1type));
> > +
> > +            if (!integer_zerop (op1))
> > +              dummy->set("offset", node_emit_json(op1));
> > +            if (TREE_CODE(t) == TARGET_MEM_REF)
> > +              {
> > +                tree temp = TMR_INDEX2 (t);
> > +                if (temp)
> > +                  dummy->set("tmr_index2", node_emit_json(temp));
> > +                temp = TMR_INDEX (t);
> > +                if (temp)
> > +                  {
> > +                    dummy->set("tmr_index", node_emit_json(temp));
> > +                    temp = TMR_STEP(t);
> > +                    if (temp)
> > +                      dummy->set("tmr_step", node_emit_json(temp));
> > +                  }
> > +              }
> > +          }
> > +        if (MR_DEPENDENCE_CLIQUE (t) != 0)
> > +          {
> > +            dummy->set_integer("clique", MR_DEPENDENCE_CLIQUE(t));
> > +            dummy->set_integer("base", MR_DEPENDENCE_BASE(t));
> > +          }
> > +      }
> > +    break;
> > +
> > +    /* FIXME : As in tree-pretty-print.cc, the following four codes are
> > +     *         incomplete. See print_struct_decl therein the above. */
> > +    case ARRAY_TYPE:
> > +      {
> > +        unsigned int quals = TYPE_QUALS (t);
> > +       if (quals & TYPE_QUAL_ATOMIC)
> > +         dummy->set_bool("atomic", true);
> > +       if (quals & TYPE_QUAL_CONST)
> > +         dummy->set_bool("const", true);
> > +       if (quals & TYPE_QUAL_VOLATILE)
> > +         dummy->set_bool("volatile", true);
> > +      }
> > +      break;
> > +    case RECORD_TYPE:
> > +    case UNION_TYPE:
> > +    case QUAL_UNION_TYPE:
> > +      {
> > +        unsigned int quals = TYPE_QUALS (t);
> > +        json::object *_x;
> > +
> > +        _x = new json::object ();
> > +
> > +        if (quals & TYPE_QUAL_ATOMIC)
> > +          _x->set_bool("atomic", true);
> > +        if (quals & TYPE_QUAL_CONST)
> > +          _x->set_bool("const", true);
> > +        if (quals & TYPE_QUAL_VOLATILE)
> > +          _x->set_bool("volatile", true);
> > +
> > +        dummy->set("type_quals", _x);
> > +
> > +        if (TYPE_NAME(t))
> > +          dummy->set("type_name", node_emit_json(TYPE_NAME(t)));
> > +      }
> > +      break;
> > +    case LANG_TYPE:
> > +      break;
> > +    case INTEGER_CST:
> > +      {
> > +        dummy->set_bool("integer_cst", true);
> > +
> > +        if ((POINTER_TYPE_P (TREE_TYPE (t)))
> > +            || (TYPE_PRECISION (TREE_TYPE (t))
> > +                < TYPE_PRECISION (integer_type_node))
> > +            || exact_log2 (TYPE_PRECISION (TREE_TYPE (t))) == -1
> > +            || tree_int_cst_sgn (t) < 0)
> > +          {
> > +            holder->append( node_emit_json (TREE_TYPE(t)));
> > +            dummy->set("_Literal", holder);
> > +          }
> > +        if (TREE_CODE (TREE_TYPE(t)) == POINTER_TYPE)
> > +          {
> > +            // In bytes
> > +            dummy->set_bool("pointer", true);
> > +            dummy->set_integer("val", TREE_INT_CST_LOW(t));
> > +          }
> > +        else if (tree_fits_shwi_p(t))
> > +          dummy->set_integer("val", tree_to_shwi (t));
> > +        else if (tree_fits_uhwi_p(t))
> > +          dummy->set_integer("val", tree_to_uhwi (t));
> > +        else
> > +          {
> > +            wide_int val = wi::to_wide (t);
> > +            char buff[WIDE_INT_PRINT_BUFFER_SIZE];
> > +
> > +            print_dec(wi::to_wide (t), buff, TYPE_SIGN (TREE_TYPE (t)));
> > +            dummy->set_string("val", buff);
> > +        }
> > +      if (TREE_OVERFLOW (t))
> > +        dummy->set_bool("overflow", true);
> > +      }
> > +      break;
> > +
> > +    case POLY_INT_CST:
> > +      for (unsigned int i = 1; i < NUM_POLY_INT_COEFFS; i++)
> > +        holder->append(node_emit_json(POLY_INT_CST_COEFF(t, i)));
> > +      dummy->set("poly_int_cst", holder);
> > +      break;
> > +
> > +    case REAL_CST:
> > +      {
> > +        REAL_VALUE_TYPE d;
> > +
> > +        d = TREE_REAL_CST (t);
> > +
> > +        if (TREE_OVERFLOW (t))
> > +          dummy->set_bool("overflow", true);
> > +
> > +        if (REAL_VALUE_ISINF (d))
> > +          dummy->set_string("value", REAL_VALUE_NEGATIVE(d) ? "-Inf" : "Inf");
> > +        else if (REAL_VALUE_ISNAN(d))
> > +          dummy->set_string("value", "NaN");
> > +        else
> > +          {
> > +            char string[100];
> > +            real_to_decimal(string, &d, sizeof (string), 0, 1);
> > +            dummy->set_string("real_value", string);
> > +          }
> > +      }
> > +      break;
> > +
> > +    case FIXED_CST:
> > +      {
> > +        char string[100];
> > +        fixed_to_decimal(string, TREE_FIXED_CST_PTR(t), sizeof (string));
> > +        dummy->set_string("fixed_cst", string);
> > +      }
> > +      break;
> > +
> > +    case STRING_CST:
> > +        dummy->set_string("string_cst", TREE_STRING_POINTER(t));
> > +        break;
> > +
> > +    case VECTOR_CST:
> > +      {
> > +        unsigned int i;
> > +        unsigned HOST_WIDE_INT nunits;
> > +
> > +        if (!VECTOR_CST_NELTS (t).is_constant (&nunits))
> > +          nunits = vector_cst_encoded_nelts (t);
> > +        for (i = 0; i < nunits; i++)
> > +          {
> > +            holder->append(node_emit_json(VECTOR_CST_ELT (t, i)));
> > +          }
> > +        dummy->set("vector_cst", holder);
> > +      }
> > +      break;
> > +
> > +    case FUNCTION_TYPE:
> > +    case METHOD_TYPE:
> > +      dummy->set("type_data", node_emit_json(TREE_TYPE (t)));
> > +
> > +      if (TREE_CODE (t) == METHOD_TYPE)
> > +        {
> > +          dummy->set_bool("method_type", true);
> > +          if (TYPE_METHOD_BASETYPE (t))
> > +            dummy->set("basetype", node_emit_json (
> > +                                       TYPE_NAME (TYPE_METHOD_BASETYPE(t))));
> > +          else
> > +            dummy->set_string("basetype", "null method basetype");
> > +        }
> > +      if (TYPE_IDENTIFIER (t))
> > +        dummy->set("type_identifier", node_emit_json (TYPE_NAME(t)));
> > +      else if ( TYPE_NAME (t) && DECL_NAME (TYPE_NAME (t)) )
> > +        decl_node_add_json( TYPE_NAME(t), dummy);
> > +      else //TDF_NOUID
> > +        {
> > +          char* buff;
> > +          buff = new char ();
> > +          print_hex(TYPE_UID(t), buff);
> > +         dummy->set_string("uid", buff);
> > +        }
> > +      dummy->set("function_decl", function_decl_emit_json(t));
> > +      break;
> > +
> > +
> > +    case FUNCTION_DECL:
> > +    case CONST_DECL:
> > +      decl_node_add_json(t, dummy);
> > +      break;
> > +    case LABEL_DECL:
> > +      if (DECL_NAME (t))
> > +        decl_node_add_json(t, dummy);
> > +      else if (LABEL_DECL_UID (t) != -1)
> > +        dummy->set_integer("LabelDeclUID", LABEL_DECL_UID (t));
> > +      else
> > +        dummy->set_integer("DeclUID", DECL_UID(t));
> > +      break;
> > +
> > +    case TYPE_DECL:
> > +      if (DECL_IS_UNDECLARED_BUILTIN (t)) //parity w/ dump_generic_node
> > +        break;
> > +      if (DECL_NAME (t))
> > +        decl_node_add_json(t, dummy);
> > +      else if (TYPE_NAME (TREE_TYPE (t)) != t)
> > +        {
> > +          dummy->set(TREE_CODE (TREE_TYPE (t)) == UNION_TYPE ? "union"
> > +                                                             : "struct",
> > +                     node_emit_json( TREE_TYPE (t)));
> > +        }
> > +      else
> > +        dummy->set_bool("anon_type_decl", true);
> > +      break;
> > +
> > +    case VAR_DECL:
> > +    case PARM_DECL:
> > +    case FIELD_DECL:
> > +    case DEBUG_EXPR_DECL:
> > +    case NAMESPACE_DECL:
> > +    case NAMELIST_DECL:
> > +      decl_node_add_json(t, dummy);
> > +      break;
> > +
> > +    case RESULT_DECL:
> > +      dummy->set_bool("retval", true);
> > +      break;
> > +
> > +    case COMPONENT_REF:
> > +      op0 = TREE_OPERAND (t, 0);
> > +      op1 = TREE_OPERAND (t, 1);
> > +      if (op0
> > +          && (TREE_CODE (op0) == INDIRECT_REF
> > +              || (TREE_CODE (op0) == MEM_REF
> > +                  && TREE_CODE (TREE_OPERAND (op0, 0)) != ADDR_EXPR
> > +                  && integer_zerop (TREE_OPERAND (op0, 1))
> > +                  //We want to be explicit about Integer_CSTs
> > +                  && TREE_CODE (TREE_OPERAND (op0, 0)) != INTEGER_CST
> > +                  // To play nice with SSA
> > +                  && TREE_TYPE (TREE_OPERAND (op0, 0)) != NULL_TREE
> > +                  // I don't understand what the qualm is here
> > +                  && (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0)))
> > +                      == (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
> > +                  && (TYPE_MODE (TREE_TYPE (TREE_OPERAND (op0, 0)))
> > +                      == (TYPE_MODE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
> > +                  && (TYPE_REF_CAN_ALIAS_ALL (
> > +                          TREE_TYPE (TREE_OPERAND (op0, 0)))
> > +                      == (TYPE_REF_CAN_ALIAS_ALL (
> > +                              TREE_TYPE (TREE_OPERAND (op0, 1)))))
> > +                  // Understand this later too
> > +                  && (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
> > +                      == TYPE_MAIN_VARIANT (
> > +                             TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
> > +                  && MR_DEPENDENCE_CLIQUE (op0) == 0)))
> > +        {
> > +          //
> > +          op0 = TREE_OPERAND (op0, 0);
> > +        }
> > +      dummy->set("expr", node_emit_json(op0));
> > +      dummy->set("field", node_emit_json(op1));
> > +      if (DECL_P (op1))
> > +        if (tree off = component_ref_field_offset(t))
> > +          if (TREE_CODE (off) != INTEGER_CST)
> > +            {
> > +              dummy->set("offset", node_emit_json(off));
> > +            }
> > +    break;
> > +
> > +    case BIT_FIELD_REF:
> > +      dummy->set_string("tree_code", "bit_field_ref");
> > +      dummy->set("expr",
> > +                 node_emit_json( TREE_OPERAND (t, 0)));
> > +      dummy->set("bits_ref",
> > +                 node_emit_json( TREE_OPERAND (t, 1)));
> > +      dummy->set("bits_first_pos",
> > +                 node_emit_json( TREE_OPERAND (t, 2)));
> > +      break;
> > +
> > +    case BIT_INSERT_EXPR:
> > +      dummy->set_string("tree_code", "bit_insert_expr");
> > +      dummy->set("container",
> > +                 node_emit_json( TREE_OPERAND (t, 0)));
> > +      dummy->set("replacement",
> > +                 node_emit_json( TREE_OPERAND (t, 1)));
> > +      dummy->set("constant_bit_pos",
> > +                 node_emit_json( TREE_OPERAND (t, 2)));
> > +      break;
> > +
> > +    case ARRAY_REF:
> > +    case ARRAY_RANGE_REF:
> > +      op0 = TREE_OPERAND (t, 0);
> > +      dummy->set("array",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("index",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      if (TREE_OPERAND(t, 2))
> > +        dummy->set("type_min_val",
> > +                   node_emit_json (TREE_OPERAND (t, 2)));
> > +      if (TREE_OPERAND(t, 3))
> > +        dummy->set("element_size",
> > +                   node_emit_json (TREE_OPERAND (t, 3)));
> > +      break;
> > +
> > +    case OMP_ARRAY_SECTION:
> > +      dummy->set("op0",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("op1",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      dummy->set("op2",
> > +                 node_emit_json (TREE_OPERAND (t, 2)));
> > +      break;
> > +
> > +    case CONSTRUCTOR:
> > +      {
> > +        unsigned HOST_WIDE_INT ix;
> > +        tree field, val;
> > +        bool is_struct_init = false;
> > +        bool is_array_init = false;
> > +        widest_int curidx;
> > +
> > +        if (TREE_CLOBBER_P (t))
> > +          switch (CLOBBER_KIND(t))
> > +            {
> > +          case CLOBBER_STORAGE_BEGIN:
> > +              dummy->set_string("CLOBBER", "storage_begin");
> > +              break;
> > +            case CLOBBER_STORAGE_END:
> > +              dummy->set_bool("CLOBBER", "storage_end");
> > +              break;
> > +            case CLOBBER_OBJECT_BEGIN:
> > +              dummy->set_bool("CLOBBER", "object_begin");
> > +              break;
> > +            case CLOBBER_OBJECT_END:
> > +              dummy->set_bool("CLOBBER", "object_end");
> > +              break;
> > +            default:
> > +              break;
> > +          }
> > +        else if (TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE
> > +                 || TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
> > +          is_struct_init = true;
> > +        else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE
> > +                 && TYPE_DOMAIN (TREE_TYPE (t))
> > +                 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t))))
> > +                    == INTEGER_CST)
> > +          {
> > +            tree minv = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
> > +            is_array_init = true;
> > +            curidx = wi::to_widest (minv);
> > +          }
> > +        FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), ix, field, val)
> > +          {
> > +            json::object* cst_elt;
> > +            json::object* _val_json;
> > +            cst_elt = new json::object ();
> > +            cst_elt->set_integer("", ix); //fix
> > +            if (field)
> > +              {
> > +                if (is_struct_init)
> > +                  cst_elt->set("field", node_emit_json(field));
> > +                else if (is_array_init
> > +                         && (TREE_CODE (field) != INTEGER_CST
> > +                             || curidx != wi::to_widest (field)))
> > +                  {
> > +                    json::array* _array_init_json;
> > +                    if (TREE_CODE (field) == RANGE_EXPR)
> > +                      {
> > +                        _array_init_json = new json::array ();
> > +                        _array_init_json->append(node_emit_json(
> > +                                                     TREE_OPERAND(field, 0)));
> > +                        _array_init_json->append(node_emit_json(
> > +                                                     TREE_OPERAND(field, 1)));
> > +                        cst_elt->set("field", _array_init_json);
> > +                      }
> > +                    else
> > +                      cst_elt->set ("field", node_emit_json (field));
> > +                  }
> > +              }
> > +            if (is_array_init)
> > +              curidx += 1;
> > +            if (val && TREE_CODE (val) == ADDR_EXPR)
> > +              if (TREE_CODE (TREE_OPERAND (val, 0)) == FUNCTION_DECL)
> > +                val = TREE_OPERAND (val, 0);
> > +            if (val && TREE_CODE (val) == FUNCTION_DECL)
> > +              {
> > +                _val_json = new json::object ();
> > +                decl_node_add_json (val, _val_json);
> > +                cst_elt->set("val", _val_json);
> > +              }
> > +            else
> > +              cst_elt->set("val", node_emit_json(val));
> > +
> > +            if (TREE_CODE (field) == INTEGER_CST)
> > +              curidx = wi::to_widest (field);
> > +            holder->append(cst_elt);
> > +          }
> > +        dummy->set("ctor_elts", holder);
> > +      }
> > +    break;
> > +
> > +   case COMPOUND_EXPR:
> > +     {
> > +        tree *tp;
> > +        holder->append( node_emit_json( TREE_OPERAND (t, 0)));
> > +
> > +        for (tp = &TREE_OPERAND (t, 1);
> > +             TREE_CODE (*tp) == COMPOUND_EXPR;
> > +             tp = &TREE_OPERAND (*tp, 1))
> > +          {
> > +          holder->append( node_emit_json ( TREE_OPERAND (*tp, 0)));
> > +          }
> > +
> > +        dummy->set("compound_expr", holder);
> > +      }
> > +      break;
> > +
> > +    case STATEMENT_LIST:
> > +      {
> > +        tree_stmt_iterator si;
> > +
> > +        for (si =  tsi_start (t); !tsi_end_p (si); tsi_next (&si))
> > +          {
> > +            holder->append( node_emit_json (tsi_stmt (si)));
> > +          }
> > +        dummy->set("statement_list", holder);
> > +      }
> > +      break;
> > +
> > +    case MODIFY_EXPR:
> > +    case INIT_EXPR:
> > +      dummy->set("op0",
> > +                 node_emit_json( TREE_OPERAND (t, 0)));
> > +      dummy->set("op1",
> > +                 node_emit_json( TREE_OPERAND (t, 1)));
> > +      break;
> > +
> > +    case TARGET_EXPR:
> > +      dummy->set("slot", node_emit_json (TARGET_EXPR_SLOT(t)));
> > +      dummy->set("initial", node_emit_json (TARGET_EXPR_INITIAL(t)));
> > +      break;
> > +
> > +    case DECL_EXPR:
> > +      decl_node_add_json(DECL_EXPR_DECL(t), dummy);
> > +      break;
> > +
> > +    case COND_EXPR:
> > +      dummy->set("if",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      if (COND_EXPR_THEN(t))
> > +      {
> > +        dummy->set("then",
> > +                   node_emit_json (TREE_OPERAND (t, 1)));
> > +      }
> > +      if (COND_EXPR_ELSE(t))
> > +      {
> > +        dummy->set("else",
> > +                 node_emit_json (TREE_OPERAND (t, 2)));
> > +      }
> > +      break;
> > +
> > +    case BIND_EXPR:
> > +      if (BIND_EXPR_VARS (t))
> > +        {
> > +          for (op0 = BIND_EXPR_VARS (t); op0; op0 = DECL_CHAIN (op0))
> > +            {
> > +              holder->append(node_emit_json (op0));
> > +            }
> > +          dummy->set("bind_expr_vars", holder);
> > +        }
> > +      dummy->set("bind_expr_body",
> > +                 node_emit_json(BIND_EXPR_BODY(t)));
> > +      break;
> > +
> > +    case CALL_EXPR:
> > +      {
> > +        if (CALL_EXPR_FN (t) != NULL_TREE)
> > +          call_name_add_json (CALL_EXPR_FN(t), dummy);
> > +        else
> > +          dummy->set_string("internal_fn",
> > +                            internal_fn_name (CALL_EXPR_IFN (t)));
> > +        dummy->set_bool("return_slot_optimization",
> > +                        CALL_EXPR_RETURN_SLOT_OPT(t));
> > +        dummy->set_bool("tail_call", CALL_EXPR_TAILCALL(t));
> > +
> > +        tree arg;
> > +        call_expr_arg_iterator iter;
> > +        bool call;
> > +        FOR_EACH_CALL_EXPR_ARG(arg, iter, t)
> > +          {
> > +            call = true;
> > +            holder->append(node_emit_json(arg));
> > +          }
> > +        if (call)
> > +          dummy->set("call_expr_arg", holder);
> > +
> > +        if (CALL_EXPR_VA_ARG_PACK (t))
> > +          dummy->set_bool("__builtin_va_arg_pack", true);
> > +
> > +        op1 = CALL_EXPR_STATIC_CHAIN (t);
> > +        if (op1)
> > +          dummy->set("static_chain", node_emit_json(op1));
> > +      }
> > +      break;
> > +    case WITH_CLEANUP_EXPR:
> > +      break;
> > +    case CLEANUP_POINT_EXPR:
> > +      dummy->set("cleanup_point", node_emit_json (TREE_OPERAND(t, 0)));
> > +      break;
> > +    case PLACEHOLDER_EXPR:
> > +      dummy->set("placeholder_expr", node_emit_json (TREE_OPERAND(t, 0)));
> > +      break;
> > +
> > +    /* Binary operations */
> > +    case WIDEN_SUM_EXPR:
> > +    case WIDEN_MULT_EXPR:
> > +    case MULT_EXPR:
> > +    case MULT_HIGHPART_EXPR:
> > +    case PLUS_EXPR:
> > +    case POINTER_PLUS_EXPR:
> > +    case POINTER_DIFF_EXPR:
> > +    case MINUS_EXPR:
> > +    case TRUNC_DIV_EXPR:
> > +    case CEIL_DIV_EXPR:
> > +    case FLOOR_DIV_EXPR:
> > +    case ROUND_DIV_EXPR:
> > +    case TRUNC_MOD_EXPR:
> > +    case CEIL_MOD_EXPR:
> > +    case FLOOR_MOD_EXPR:
> > +    case ROUND_MOD_EXPR:
> > +    case RDIV_EXPR:
> > +    case EXACT_DIV_EXPR:
> > +    case LSHIFT_EXPR:
> > +    case RSHIFT_EXPR:
> > +    case LROTATE_EXPR:
> > +    case RROTATE_EXPR:
> > +    case WIDEN_LSHIFT_EXPR:
> > +    case BIT_IOR_EXPR:
> > +    case BIT_XOR_EXPR:
> > +    case BIT_AND_EXPR:
> > +    case TRUTH_ANDIF_EXPR:
> > +    case TRUTH_ORIF_EXPR:
> > +    case TRUTH_AND_EXPR:
> > +    case TRUTH_OR_EXPR:
> > +    case TRUTH_XOR_EXPR:
> > +    case LT_EXPR:
> > +    case LE_EXPR:
> > +    case GT_EXPR:
> > +    case GE_EXPR:
> > +    case EQ_EXPR:
> > +    case NE_EXPR:
> > +    case UNLT_EXPR:
> > +    case UNLE_EXPR:
> > +    case UNGT_EXPR:
> > +    case UNGE_EXPR:
> > +    case UNEQ_EXPR:
> > +    case LTGT_EXPR:
> > +    case ORDERED_EXPR:
> > +    case UNORDERED_EXPR:
> > +      {
> > +        const char* c = op_symbol_code(TREE_CODE(t), TDF_NONE);
> > +        op0 = TREE_OPERAND(t, 0);
> > +        op1 = TREE_OPERAND(t, 1);
> > +
> > +        dummy->set_string("bin_operator", c);
> > +        holder->append(node_emit_json(op0));
> > +        holder->append(node_emit_json(op1));
> > +        dummy->set("operands", holder);
> > +      }
> > +      break;
> > +
> > +    case ADDR_EXPR:
> > +      //TDF_GIMPLE_VAL
> > +      dummy->set("_Literal", node_emit_json( TREE_TYPE (t)));
> > +      /* FALLTHROUGH */
> > +    case NEGATE_EXPR:
> > +    case BIT_NOT_EXPR:
> > +    case TRUTH_NOT_EXPR:
> > +    case PREDECREMENT_EXPR:
> > +    case PREINCREMENT_EXPR:
> > +    case INDIRECT_REF:
> > +    case POSTDECREMENT_EXPR:
> > +    case POSTINCREMENT_EXPR:
> > +      {
> > +        const char * c = op_symbol_code(code, TDF_NONE);
> > +        dummy->set(c, node_emit_json (TREE_OPERAND (t, 0)));
> > +      }
> > +      break;
> > +
> > +    case MIN_EXPR:
> > +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> > +      holder->append (node_emit_json (TREE_OPERAND (t,1)));
> > +      dummy->set("min_expr", holder);
> > +      break;
> > +
> > +    case MAX_EXPR:
> > +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> > +      holder->append (node_emit_json (TREE_OPERAND (t,1)));
> > +      dummy->set("max_expr", holder);
> > +      break;
> > +
> > +    case ABS_EXPR:
> > +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> > +      dummy->set("abs_expr", holder);
> > +      break;
> > +
> > +    case ABSU_EXPR:
> > +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> > +      dummy->set("absu_expr", holder);
> > +      break;
> > +
> > +    case RANGE_EXPR:
> > +      break;
> > +
> > +    case ADDR_SPACE_CONVERT_EXPR:
> > +    case FIXED_CONVERT_EXPR:
> > +    case FIX_TRUNC_EXPR:
> > +    case FLOAT_EXPR:
> > +    CASE_CONVERT:
> > +      type = TREE_TYPE (t);
> > +      op0 = TREE_OPERAND (t, 0);
> > +      if (type != TREE_TYPE(op0))
> > +        {
> > +          dummy->set ("type", node_emit_json (type));
> > +        }
> > +      dummy->set ("operand", node_emit_json (op0));
> > +      break;
> > +
> > +    case VIEW_CONVERT_EXPR:
> > +      holder->append (node_emit_json (TREE_TYPE(t)));
> > +      holder->append (node_emit_json (TREE_OPERAND(t, 0)));
> > +      dummy->set("view_convert_expr", holder);
> > +      break;
> > +
> > +    case PAREN_EXPR:
> > +      dummy->set("paren_expr",
> > +                 node_emit_json (TREE_OPERAND (t,0)));
> > +      break;
> > +
> > +    case NON_LVALUE_EXPR:
> > +      dummy->set("non_lvalue_expr",
> > +                 node_emit_json (TREE_OPERAND (t,0)));
> > +      break;
> > +
> > +    case SAVE_EXPR:
> > +      dummy->set("save_expr",
> > +                 node_emit_json (TREE_OPERAND (t,0)));
> > +      break;
> > +
> > +    case COMPLEX_EXPR:
> > +      holder->append (node_emit_json (TREE_OPERAND (t,0)));
> > +      holder->append (node_emit_json (TREE_OPERAND (t,1)));
> > +      dummy->set("complex_expr", holder);
> > +      break;
> > +
> > +    case CONJ_EXPR:
> > +      dummy->set("conj_expr",
> > +                 node_emit_json (TREE_OPERAND (t,0)));
> > +      break;
> > +
> > +    case REALPART_EXPR:
> > +      dummy->set("realpart_expr",
> > +                 node_emit_json (TREE_OPERAND (t,0)));
> > +      break;
> > +
> > +    case IMAGPART_EXPR:
> > +      dummy->set("imagpart_expr",
> > +                 node_emit_json (TREE_OPERAND (t,0)));
> > +      break;
> > +
> > +    case VA_ARG_EXPR:
> > +      dummy->set("va_arg_expr",
> > +                 node_emit_json (TREE_OPERAND (t,0)));
> > +      break;
> > +
> > +    case TRY_FINALLY_EXPR:
> > +    case TRY_CATCH_EXPR:
> > +      {
> > +        tree _t;
> > +        dummy->set("try",
> > +                   node_emit_json (TREE_OPERAND (t, 0)));
> > +        if (TREE_CODE (t) == TRY_CATCH_EXPR)
> > +          {
> > +            _t = TREE_OPERAND(t, 1);
> > +            dummy->set("catch",
> > +                        node_emit_json (_t));
> > +          }
> > +        else
> > +          {
> > +            gcc_assert(TREE_CODE (t) == TRY_FINALLY_EXPR);
> > +            _t = TREE_OPERAND(t, 1);
> > +            if (TREE_CODE (t) == EH_ELSE_EXPR)
> > +              {
> > +                _t = TREE_OPERAND (_t, 0);
> > +                dummy->set("finally",
> > +                           node_emit_json (_t));
> > +                _t = TREE_OPERAND(_t, 1);
> > +                dummy->set("else",
> > +                           node_emit_json (_t));
> > +              }
> > +            else
> > +              {
> > +              dummy->set("finally",
> > +                         node_emit_json(_t));
> > +              }
> > +          }
> > +      }
> > +      break;
> > +
> > +    case CATCH_EXPR:
> > +      dummy->set("catch_types", node_emit_json(CATCH_TYPES(t)));
> > +      dummy->set("catch_body", node_emit_json(CATCH_BODY(t)));
> > +      break;
> > +
> > +    case EH_FILTER_EXPR:
> > +      dummy->set("eh_filter_types", node_emit_json(EH_FILTER_TYPES(t)));
> > +      dummy->set("eh_filter_failure", node_emit_json(EH_FILTER_FAILURE(t)));
> > +      break;
> > +
> > +    case LABEL_EXPR:
> > +      decl_node_add_json (TREE_OPERAND (t, 0), dummy);
> > +      break;
> > +
> > +    case LOOP_EXPR:
> > +      dummy->set("while (1)", node_emit_json (LOOP_EXPR_BODY (t)));
> > +      break;
> > +
> > +    case PREDICT_EXPR:
> > +      if (PREDICT_EXPR_OUTCOME (t))
> > +        dummy->set_string("likely by",
> > +                          predictor_name (PREDICT_EXPR_PREDICTOR (t)));
> > +      else
> > +        dummy->set_string("unlikely by",
> > +                          predictor_name (PREDICT_EXPR_PREDICTOR (t)));
> > +      break;
> > +    case ANNOTATE_EXPR:
> > +      {
> > +      switch ((enum annot_expr_kind) TREE_INT_CST_LOW (TREE_OPERAND(t,1)))
> > +        { //Is this expensive? ask later
> > +          case annot_expr_ivdep_kind:
> > +            dummy->set("ivdep", node_emit_json (TREE_OPERAND (t, 0)));
> > +            break;
> > +          case annot_expr_unroll_kind:
> > +            dummy->set("unroll", node_emit_json (TREE_OPERAND (t, 0)));
> > +            break;
> > +          case annot_expr_no_vector_kind:
> > +            dummy->set("no-vector", node_emit_json (TREE_OPERAND (t, 0)));
> > +            break;
> > +          case annot_expr_vector_kind:
> > +            dummy->set("vector", node_emit_json (TREE_OPERAND (t, 0)));
> > +            break;
> > +          case annot_expr_parallel_kind:
> > +            dummy->set("parallel", node_emit_json (TREE_OPERAND (t, 0)));
> > +            break;
> > +          case annot_expr_maybe_infinite_kind:
> > +            dummy->set("maybe_infinite",
> > +                       node_emit_json (TREE_OPERAND (t, 0)));
> > +            break;
> > +          default:
> > +            gcc_unreachable();
> > +        }
> > +      }
> > +      break;
> > +
> > +    case RETURN_EXPR:
> > +      {
> > +        op0 = TREE_OPERAND(t, 0);
> > +        if (op0)
> > +          {
> > +            if (TREE_CODE(op0) == MODIFY_EXPR)
> > +              dummy->set("return_expr", node_emit_json(TREE_OPERAND(op0, 1)));
> > +            else
> > +              dummy->set("return_expr", node_emit_json(op0));
> > +          }
> > +      }
> > +      break;
> > +
> > +    case EXIT_EXPR:
> > +      dummy->set("exit_if", node_emit_json(TREE_OPERAND (t, 0)));
> > +      break;
> > +
> > +    case SWITCH_EXPR:
> > +      dummy->set("switch_cond", node_emit_json(SWITCH_COND(t)));
> > +      dummy->set("switch_body", node_emit_json(SWITCH_BODY(t)));
> > +      break;
> > +
> > +    case GOTO_EXPR:
> > +      op0 = GOTO_DESTINATION(t);
> > +      dummy->set("goto", node_emit_json(op0));
> > +      break;
> > +
> > +    case ASM_EXPR:
> > +      dummy->set("asm_string", node_emit_json (ASM_STRING (t)));
> > +      dummy->set("asm_outputs", node_emit_json (ASM_OUTPUTS (t)));
> > +      dummy->set("asm_inputs", node_emit_json (ASM_INPUTS (t)));
> > +      if (ASM_CLOBBERS (t))
> > +        dummy->set("asm_clobbers", node_emit_json (ASM_CLOBBERS (t)));
> > +      break;
> > +
> > +    case CASE_LABEL_EXPR:
> > +      if (CASE_LOW(t) && CASE_HIGH(t))
> > +        {
> > +          dummy->set ("case_low", node_emit_json (CASE_LOW(t)));
> > +          dummy->set ("case_high", node_emit_json (CASE_HIGH(t)));
> > +        }
> > +      else if (CASE_LOW(t))
> > +        dummy->set ("case", node_emit_json (CASE_LOW(t)));
> > +      else
> > +        dummy->set_string("case", "default");
> > +      break;
> > +
> > +    // check later - okay?
> > +    case OBJ_TYPE_REF:
> > +      dummy->set("obj_type_ref_expr",
> > +                 node_emit_json(OBJ_TYPE_REF_EXPR(t)));
> > +      dummy->set("obj_type_ref_object",
> > +                 node_emit_json(OBJ_TYPE_REF_OBJECT(t)));
> > +      dummy->set("obj_type_ref_token",
> > +                 node_emit_json(OBJ_TYPE_REF_TOKEN(t)));
> > +      break;
> > +
> > +    case SSA_NAME:
> > +      {
> > +      if (SSA_NAME_IDENTIFIER (t))
> > +        dummy->set("ssa_name_identifier",
> > +                   node_emit_json (SSA_NAME_IDENTIFIER (t)));
> > +      if (SSA_NAME_IS_DEFAULT_DEF (t))
> > +        dummy->set_bool("ssa_default_def", true);
> > +      if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (t))
> > +       dummy->set_bool("abnormal_phi", true);
> > +      }
> > +      break;
> > +
> > +    case WITH_SIZE_EXPR:
> > +      dummy->set("expr", node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("size", node_emit_json (TREE_OPERAND (t, 1)));
> > +      break;
> > +
> > +    case SCEV_KNOWN:
> > +    case SCEV_NOT_KNOWN:
> > +      break;
> > +
> > +    case POLYNOMIAL_CHREC:
> > +      dummy->set_integer("chrec_var", CHREC_VARIABLE(t));
> > +      dummy->set("chrec_left", node_emit_json (CHREC_LEFT(t)));
> > +      dummy->set("chrec_right", node_emit_json (CHREC_RIGHT(t)));
> > +      dummy->set_bool("chrec_nowrap", CHREC_NOWRAP(t));
> > +      break;
> > +
> > +    case REALIGN_LOAD_EXPR:
> > +      dummy->set("input_0", node_emit_json(TREE_OPERAND (t, 0)));
> > +      dummy->set("input_1", node_emit_json(TREE_OPERAND (t, 1)));
> > +      dummy->set("offset", node_emit_json(TREE_OPERAND (t, 2)));
> > +      break;
> > +
> > +    case VEC_COND_EXPR:
> > +      dummy->set("if",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("then",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      dummy->set("else",
> > +                 node_emit_json (TREE_OPERAND (t, 2)));
> > +      break;
> > +
> > +    case VEC_PERM_EXPR:
> > +      dummy->set("v0",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("v1",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      dummy->set("mask",
> > +                 node_emit_json (TREE_OPERAND (t, 2)));
> > +      break;
> > +
> > +    case DOT_PROD_EXPR: //check later
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("arg2",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      dummy->set("arg3",
> > +                 node_emit_json (TREE_OPERAND (t, 2)));
> > +      break;
> > +
> > +    case WIDEN_MULT_PLUS_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("arg2",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      dummy->set("arg3",
> > +                 node_emit_json (TREE_OPERAND (t, 2)));
> > +      break;
> > +
> > +    case WIDEN_MULT_MINUS_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("arg2",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      dummy->set("arg3",
> > +                 node_emit_json (TREE_OPERAND (t, 2)));
> > +      break;
> > +
> > +    case VEC_SERIES_EXPR:
> > +    case VEC_WIDEN_MULT_HI_EXPR:
> > +    case VEC_WIDEN_MULT_LO_EXPR:
> > +    case VEC_WIDEN_MULT_ODD_EXPR:
> > +    case VEC_WIDEN_LSHIFT_HI_EXPR:
> > +    case VEC_WIDEN_LSHIFT_LO_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("arg2",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      break;
> > +
> > +    case VEC_DUPLICATE_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      break;
> > +
> > +    case VEC_UNPACK_HI_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      break;
> > +
> > +    case VEC_UNPACK_LO_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      break;
> > +
> > +    case VEC_UNPACK_FLOAT_HI_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      break;
> > +
> > +    case VEC_UNPACK_FLOAT_LO_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      break;
> > +
> > +    case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      break;
> > +
> > +    case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      break;
> > +
> > +    case VEC_PACK_TRUNC_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("arg2",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      break;
> > +
> > +    case VEC_PACK_SAT_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("arg2",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      break;
> > +
> > +    case VEC_PACK_FIX_TRUNC_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("arg2",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      break;
> > +
> > +    case VEC_PACK_FLOAT_EXPR:
> > +      dummy->set("arg1",
> > +                 node_emit_json (TREE_OPERAND (t, 0)));
> > +      dummy->set("arg2",
> > +                 node_emit_json (TREE_OPERAND (t, 1)));
> > +      break;
> > +    /*OACC and OMP */
> > +    case OACC_PARALLEL:
> > +      goto dump_omp_clauses_body;
> > +
> > +    case OACC_KERNELS:
> > +      goto dump_omp_clauses_body;
> > +
> > +    case OACC_SERIAL:
> > +      goto dump_omp_clauses_body;
> > +
> > +    case OACC_DATA:
> > +      goto dump_omp_clauses_body;
> > +
> > +    case OACC_HOST_DATA:
> > +      dummy->set("oacc_host_data_clauses",
> > +                 omp_clause_emit_json (OACC_HOST_DATA_CLAUSES(t)));
> > +      dummy->set("oacc_host_data_body",
> > +                 omp_clause_emit_json (OACC_HOST_DATA_BODY(t)));
> > +      break;
> > +
> > +    case OACC_DECLARE:
> > +      dummy->set("oacc_declare_clauses",
> > +                 omp_clause_emit_json (OACC_DECLARE_CLAUSES(t)));
> > +      break;
> > +
> > +    case OACC_UPDATE:
> > +      dummy->set("oacc_update_clauses",
> > +                 omp_clause_emit_json (OACC_UPDATE_CLAUSES(t)));
> > +      break;
> > +
> > +    case OACC_ENTER_DATA:
> > +      dummy->set("oacc_enter_data_clauses",
> > +                 omp_clause_emit_json (OACC_ENTER_DATA_CLAUSES(t)));
> > +      break;
> > +
> > +    case OACC_EXIT_DATA:
> > +      dummy->set("oacc_exit_data_clauses",
> > +                 omp_clause_emit_json (OACC_EXIT_DATA_CLAUSES(t)));
> > +      break;
> > +
> > +    case OACC_CACHE:
> > +      dummy->set("oacc_cache_clauses",
> > +                 omp_clause_emit_json (OACC_CACHE_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_PARALLEL:
> > +      dummy->set("omp_parallel_body",
> > +                 node_emit_json (OMP_PARALLEL_BODY(t)));
> > +      dummy->set("omp_parallel_clauses",
> > +                 omp_clause_emit_json (OMP_PARALLEL_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_TASK:
> > +      {
> > +      if (OMP_TASK_BODY (t))
> > +        {
> > +          dummy->set_bool("omp_task", true);
> > +          dummy->set("omp_task_body",
> > +                     node_emit_json(OMP_TASK_BODY (t)));
> > +          dummy->set("omp_task_clauses",
> > +                     omp_clause_emit_json (OMP_TASK_CLAUSES(t)));
> > +        } else {
> > +          dummy->set_bool("omp_taskwait", true);
> > +          dummy->set("omp_taskwait_clauses",
> > +                     omp_clause_emit_json (OMP_TASK_CLAUSES(t)));
> > +        }
> > +        break;
> > +      }
> > +
> > +    dump_omp_clauses_body:
> > +      dummy->set("omp_clauses", omp_clause_emit_json (OMP_CLAUSES (t)));
> > +      goto dump_omp_body;
> > +
> > +    dump_omp_body:
> > +      dummy->set("omp_body", node_emit_json (OMP_BODY(t)));
> > +      dummy->set_bool("is_expr", false);
> > +      break;
> > +
> > +    case OMP_FOR:
> > +      goto dump_omp_loop;
> > +
> > +    case OMP_SIMD:
> > +      goto dump_omp_loop;
> > +
> > +    case OMP_DISTRIBUTE:
> > +      goto dump_omp_loop;
> > +
> > +    case OMP_TASKLOOP:
> > +      goto dump_omp_loop;
> > +
> > +    case OMP_LOOP:
> > +      goto dump_omp_loop;
> > +
> > +    case OMP_TILE:
> > +      goto dump_omp_loop;
> > +
> > +    case OMP_UNROLL:
> > +      goto dump_omp_loop;
> > +
> > +    case OACC_LOOP:
> > +      goto dump_omp_loop;
> > +
> > +    dump_omp_loop:
> > +      dummy->set("omp_for_body",
> > +                 node_emit_json(OMP_FOR_BODY (t)));
> > +      dummy->set("omp_for_clauses",
> > +                 omp_clause_emit_json (OMP_FOR_CLAUSES(t)));
> > +      dummy->set("omp_for_init",
> > +                 node_emit_json(OMP_FOR_INIT (t)));
> > +      dummy->set("omp_for_incr",
> > +                 node_emit_json(OMP_FOR_INCR (t)));
> > +      dummy->set("omp_for_pre_body",
> > +                 node_emit_json(OMP_FOR_PRE_BODY (t)));
> > +      dummy->set("omp_for_orig_decls",
> > +                 node_emit_json(OMP_FOR_ORIG_DECLS (t)));
> > +      break;
> > +
> > +    case OMP_TEAMS:
> > +      dummy->set("omp_teams_body",
> > +                 omp_clause_emit_json (OMP_TEAMS_BODY(t)));
> > +      dummy->set("omp_teams_clauses",
> > +                 omp_clause_emit_json (OMP_TEAMS_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_TARGET_DATA:
> > +      dummy->set("omp_target_data_body",
> > +                 omp_clause_emit_json (OMP_TARGET_DATA_BODY(t)));
> > +      dummy->set("omp_target_data_clauses",
> > +                 omp_clause_emit_json (OMP_TARGET_DATA_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_TARGET_ENTER_DATA:
> > +      dummy->set("omp_target_enter_data_clauses",
> > +                 omp_clause_emit_json (OMP_TARGET_ENTER_DATA_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_TARGET_EXIT_DATA:
> > +      dummy->set("omp_target_exit_data_clauses",
> > +                 omp_clause_emit_json (OMP_TARGET_EXIT_DATA_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_TARGET:
> > +      dummy->set("omp_target_body",
> > +                 omp_clause_emit_json (OMP_TARGET_BODY(t)));
> > +      dummy->set("omp_target_clauses",
> > +                 omp_clause_emit_json (OMP_TARGET_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_TARGET_UPDATE:
> > +      dummy->set("omp_target_update_clauses",
> > +                 omp_clause_emit_json (OMP_TARGET_UPDATE_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_SECTIONS:
> > +      dummy->set("omp_sections_body",
> > +                 omp_clause_emit_json (OMP_SECTIONS_BODY(t)));
> > +      dummy->set("omp_sections_clauses",
> > +                 omp_clause_emit_json (OMP_SECTIONS_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_SECTION:
> > +      dummy->set("omp_section_body",
> > +                 omp_clause_emit_json (OMP_SECTION_BODY(t)));
> > +      break;
> > +
> > +    case OMP_STRUCTURED_BLOCK:
> > +      dummy->set("omp_structured_block_body",
> > +                 omp_clause_emit_json (OMP_STRUCTURED_BLOCK_BODY(t)));
> > +      break;
> > +
> > +    case OMP_SCAN:
> > +      dummy->set("omp_scan_body",
> > +                 omp_clause_emit_json (OMP_SCAN_BODY(t)));
> > +      dummy->set("omp_scan_clauses",
> > +                 omp_clause_emit_json (OMP_SCAN_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_MASTER:
> > +      dummy->set("omp_master_body",
> > +                 omp_clause_emit_json (OMP_MASTER_BODY(t)));
> > +      break;
> > +
> > +    case OMP_MASKED:
> > +      dummy->set("omp_masked_body",
> > +                 omp_clause_emit_json (OMP_MASKED_BODY(t)));
> > +      dummy->set("omp_masked_clauses",
> > +                 omp_clause_emit_json (OMP_MASKED_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_TASKGROUP:
> > +      dummy->set("omp_taskgroup_body",
> > +                 omp_clause_emit_json (OMP_TASKGROUP_BODY(t)));
> > +      dummy->set("omp_taskgroup_clauses",
> > +                 omp_clause_emit_json (OMP_TASKGROUP_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_ORDERED:
> > +      dummy->set("omp_ordered_body",
> > +                 omp_clause_emit_json (OMP_ORDERED_BODY(t)));
> > +      dummy->set("omp_ordered_clauses",
> > +                 omp_clause_emit_json (OMP_ORDERED_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_CRITICAL:
> > +      dummy->set("omp_masked_body",
> > +                 omp_clause_emit_json (OMP_CRITICAL_BODY(t)));
> > +      dummy->set("omp_masked_clauses",
> > +                 omp_clause_emit_json (OMP_CRITICAL_CLAUSES(t)));
> > +      dummy->set("omp_masked_name",
> > +                 node_emit_json (OMP_CRITICAL_NAME(t)));
> > +      break;
> > +
> > +    case OMP_ATOMIC:
> > +      if (OMP_ATOMIC_WEAK (t))
> > +        dummy->set_bool("omp_atomic_weak", true);
> > +      else
> > +        dummy->set_bool("omp_atomic_weak", false);
> > +      dummy->set("omp_atomic_memory_order",
> > +                 omp_atomic_memory_order_emit_json(
> > +                     OMP_ATOMIC_MEMORY_ORDER(t)));
> > +      dummy->set("op0",
> > +                 node_emit_json (TREE_OPERAND(t, 0)));
> > +      dummy->set("op1",
> > +                 node_emit_json (TREE_OPERAND(t, 1)));
> > +      break;
> > +
> > +    case OMP_ATOMIC_READ:
> > +      dummy->set("omp_atomic_memory_order",
> > +                 omp_atomic_memory_order_emit_json(
> > +                     OMP_ATOMIC_MEMORY_ORDER(t)));
> > +      dummy->set("op0",
> > +                 node_emit_json(TREE_OPERAND(t, 0)));
> > +      break;
> > +
> > +    case OMP_ATOMIC_CAPTURE_OLD:
> > +    case OMP_ATOMIC_CAPTURE_NEW:
> > +      if (OMP_ATOMIC_WEAK (t))
> > +        dummy->set_bool("omp_atomic_capture_weak", true);
> > +      else
> > +        dummy->set_bool("omp_atomic_capture", true);
> > +      dummy->set("omp_atomic_memory_order",
> > +                 omp_atomic_memory_order_emit_json (OMP_ATOMIC_MEMORY_ORDER(t)));
> > +      dummy->set("op0",
> > +                 node_emit_json(TREE_OPERAND(t, 0)));
> > +      dummy->set("op1",
> > +                 node_emit_json(TREE_OPERAND(t, 1)));
> > +      break;
> > +
> > +    case OMP_SINGLE:
> > +      dummy->set("omp_single_body",
> > +                 omp_clause_emit_json (OMP_SINGLE_BODY(t)));
> > +      dummy->set("omp_single_clauses",
> > +                 omp_clause_emit_json (OMP_SINGLE_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_SCOPE:
> > +      dummy->set("omp_scope_body",
> > +                 omp_clause_emit_json (OMP_SCOPE_BODY(t)));
> > +      dummy->set("omp_scope_clauses",
> > +                 omp_clause_emit_json (OMP_SCOPE_CLAUSES(t)));
> > +      break;
> > +
> > +    case OMP_CLAUSE:
> > +      dummy->set("omp_clause",
> > +                 omp_clause_emit_json(t));
> > +      break;
> > +
> > +    case TRANSACTION_EXPR:
> > +      if (TRANSACTION_EXPR_OUTER (t))
> > +       dummy->set_bool ("transaction_expr_outer", true);
> > +      if (TRANSACTION_EXPR_RELAXED (t))
> > +       dummy->set_bool ("transaction_expr_relaxed", true);
> > +      dummy->set("omp_transaction_body",
> > +                 node_emit_json (TRANSACTION_EXPR_BODY(t)));
> > +      break;
> > +
> > +    case BLOCK:
> > +      {
> > +      tree iter;
> > +      json::array *subblock, *chain, *vars, *fragment_chain, *nlv_holder;
> > +      dummy->set_integer ("block #", BLOCK_NUMBER (t));
> > +      if (BLOCK_SUPERCONTEXT (t))
> > +        dummy->set("block_supercontext",
> > +                   node_emit_json(BLOCK_SUPERCONTEXT (t)));
> > +      if (BLOCK_SUBBLOCKS(t))
> > +        {
> > +          subblock = new json::array ();
> > +          for (iter = BLOCK_SUBBLOCKS (t); iter; iter = BLOCK_CHAIN (t))
> > +            subblock->append(node_emit_json(iter));
> > +          dummy->set("block_subblocks", subblock);
> > +        }
> > +      if (BLOCK_CHAIN (t))
> > +        {
> > +          chain = new json::array ();
> > +          for (iter = BLOCK_SUBBLOCKS (t); iter; iter = BLOCK_CHAIN (t))
> > +              chain->append(node_emit_json(iter));
> > +          dummy->set("block_chain", chain);
> > +
> > +        }
> > +      if (BLOCK_VARS (t))
> > +        {
> > +          vars = new json::array ();
> > +          for (iter = BLOCK_VARS (t); iter; iter = TREE_CHAIN (t))
> > +              vars->append(node_emit_json(iter));
> > +          dummy->set("block_vars", vars);
> > +        }
> > +      if (vec_safe_length (BLOCK_NONLOCALIZED_VARS (t)) > 0)
> > +        {
> > +          unsigned i;
> > +          vec<tree, va_gc> *nlv = BLOCK_NONLOCALIZED_VARS (t);
> > +
> > +          nlv_holder = new json::array ();
> > +
> > +          FOR_EACH_VEC_ELT (*nlv, i, t)
> > +            {
> > +              nlv_holder->append(node_emit_json(t));
> > +            }
> > +          dummy->set("block_nonlocalized_vars", nlv_holder);
> > +        }
> > +      if (BLOCK_ABSTRACT_ORIGIN (t))
> > +        dummy->set("block_abstract_origin",
> > +                   node_emit_json (BLOCK_ABSTRACT_ORIGIN (t)));
> > +      if (BLOCK_FRAGMENT_ORIGIN (t))
> > +        dummy->set("block_fragment_origin",
> > +                   node_emit_json (BLOCK_FRAGMENT_ORIGIN (t)));
> > +
> > +      if (BLOCK_FRAGMENT_CHAIN (t))
> > +        {
> > +          fragment_chain = new json::array ();
> > +          for( iter=BLOCK_FRAGMENT_CHAIN (t);
> > +               iter;
> > +               iter=BLOCK_FRAGMENT_CHAIN (t) )
> > +              fragment_chain->append(node_emit_json(iter));
> > +          dummy->set("block_fragment_chain", fragment_chain);
> > +        }
> > +      }
> > +      break;
> > +
> > +    case DEBUG_BEGIN_STMT:
> > +      dummy->set_bool("debug_begin", true);
> > +      break;
> > +    default:
> > +      dummy->set_bool("unsupported code", true);
> > +      dummy->set_string("fallthrough", get_tree_code_name(code));
> > +      break;
> > +  }
> > +  return dummy;
> > +}
> > +
> > +/* Dump the next node in the queue.  */
> > +
> > +static void
> > +dequeue_and_dump (dump_info_p di)
> > +{
> > +  dump_queue_p dq;
> > +  splay_tree_node stn;
> > +//  dump_node_info_p dni;
> > +  tree t;
> > +  json::object* dummy;
> > +
> > +  dummy = new json::object ();
> > +
> > +  /* Get the next node from the queue.  */
> > +  dq = di->queue;
> > +  stn = dq->node;
> > +  t = (tree) stn->key;
> > +//  dni = (dump_node_info_p) stn->value;
> > +
> > +  /* Remove the node from the queue, and put it on the free list.  */
> > +  di->queue = dq->next;
> > +  if (!di->queue)
> > +    di->queue_end = 0;
> > +  dq->next = di->free_list;
> > +  di->free_list = dq;
> > +
> > +  dummy = node_emit_json(t);
> > +  di->json_dump->append(dummy);
> > +}
> > +
> > +/* Dump T, and all its children, on STREAM.  */
> > +
> > +void
> > +dump_node_json (const_tree t, dump_flags_t flags, FILE *stream)
> > +{
> > +  struct dump_info di;
> > +  dump_queue_p dq;
> > +  dump_queue_p next_dq;
> > +  pretty_printer pp;
> > +  /* Initialize the dump-information structure.  */
> > +  di.stream = stream;
> > +  di.index = 0;
> > +  di.column = 0;
> > +  di.queue = 0;
> > +  di.queue_end = 0;
> > +  di.free_list = 0;
> > +  di.flags = flags;
> > +  di.node = t;
> > +  di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
> > +                            splay_tree_delete_pointers);
> > +  di.json_dump = new json::array ();
> > +  /* Queue up the first node.  */
> > +  queue (&di, t);
> > +
> > +  /* Until the queue is empty, keep dumping nodes.  */
> > +  while (di.queue)
> > +    dequeue_and_dump (&di);
> > +
> > +  di.json_dump->dump(stream, true);
> > +  fputs("\n", stream);
> > +  /* Now, clean up.  */
> > +  for (dq = di.free_list; dq; dq = next_dq)
> > +    {
> > +      next_dq = dq->next;
> > +      free (dq);
> > +    }
> > +  splay_tree_delete (di.nodes);
> > +}
> > +
> > +DEBUG_FUNCTION void
> > +debug_tree_json (tree t)
> > +{
> > +  json::object* _x = node_emit_json(t);
> > +  _x->dump(stderr, true);
> > +  fprintf(stderr, "\n");
> > +}
> > diff --git a/gcc/tree-emit-json.h b/gcc/tree-emit-json.h
> > new file mode 100644
> > index 00000000000..ea81466a940
> > --- /dev/null
> > +++ b/gcc/tree-emit-json.h
> > @@ -0,0 +1,82 @@
> > +/* Tree-dumping functionality for intermediate representation.
> > +   Copyright (C) 1999-2024 Free Software Foundation, Inc.
> > +   Written by Mark Mitchell <mark@codesourcery.com>
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +
> > +#ifndef GCC_TREE_JSON_H
> > +#define GCC_TREE_JSON_H
> > +
> > +#include "splay-tree.h"
> > +#include "dumpfile.h"
> > +#define INCLUDE_MEMORY
> > +#include "json.h"
> > +
> > +typedef struct dump_info *dump_info_p;
> > +
> > +/* Information about a node to be dumped.  */
> > +
> > +typedef struct dump_node_info
> > +{
> > +  /* The index for the node.  */
> > +  unsigned int index;
> > +  /* Nonzero if the node is a binfo.  */
> > +  unsigned int binfo_p : 1;
> > +} *dump_node_info_p;
> > +
> > +/* A dump_queue is a link in the queue of things to be dumped.  */
> > +
> > +typedef struct dump_queue
> > +{
> > +  /* The queued tree node.  */
> > +  splay_tree_node node;
> > +  /* The next node in the queue.  */
> > +  struct dump_queue *next;
> > +} *dump_queue_p;
> > +
> > +/* A dump_info gives information about how we should perform the dump
> > +   and about the current state of the dump.  */
> > +
> > +struct dump_info
> > +{
> > +  /* The stream on which to dump the information.  */
> > +  FILE *stream;
> > +  /* The original node.  */
> > +  const_tree node;
> > +  /* User flags.  */
> > +  dump_flags_t flags;
> > +  /* The next unused node index.  */
> > +  unsigned int index;
> > +  /* The next column.  */
> > +  unsigned int column;
> > +  /* The first node in the queue of nodes to be written out.  */
> > +  dump_queue_p queue;
> > +  /* The last node in the queue.  */
> > +  dump_queue_p queue_end;
> > +  /* Free queue nodes.  */
> > +  dump_queue_p free_list;
> > +  /* The tree nodes which we have already written out.  The
> > +     keys are the addresses of the nodes; the values are the integer
> > +     indices we assigned them.  */
> > +  splay_tree nodes;
> > +  /* JSON tree holder. Carries everything, each node is a sub-array */
> > +  json::array* json_dump;
> > +};
> > +
> > +extern json::object* node_emit_json(tree t);
> > +extern void dump_node_json (const_tree t, dump_flags_t flags, FILE *stream);
> > +#endif /* ! GCC_TREE_JSON_H */
> > --
> > 2.34.1
> >
Richard Biener Sept. 12, 2024, 12:14 p.m. UTC | #4
On Thu, Sep 12, 2024 at 12:51 PM David Malcolm <dmalcolm@redhat.com> wrote:
>
> On Wed, 2024-09-11 at 20:49 -0500, tcpreimesberger@gmail.com wrote:
> > From: Thor C Preimesberger <tcpreimesberger@gmail.com>
> >
> > This patch allows the compiler to dump GENERIC trees as JSON objects.
> >
> > The dump flag -fdump-tree-original-json dumps each fndecl node in the
> > C frontend's gimplifier as a JSON object and traverses related nodes
> > in an analagous manner as to raw-dumping.
>
> Thanks for posting this patch.
>
> Are you able to upload somewhere some examples of what the dumps look
> like?

I found https://renhongl.github.io/json-editor/ which seems to accept
the output of -fdump-tree-original-json visualizes the raw JSON structure
when the input is from a single function.

struct S { int i; int j; } s;
int bar ()
{
  return s.i + s.j;
}
int main()
{
  return bar ();
}

no longer recognizes it, I would guess we'd need to produce an outer
"file level" JSON node.  Simply wrapping the file in [{ ... }] didn't
work even with comma separating two functions.

The JSON for bar looks like (sorry for the long paste)

[{"addr": "0x7f8256bda3c0",
  "expr_loc": [{"file": "t.c",
                "line": 3,
                "column": 1}],
  "start_loc": [{"file": "t.c",
                 "line": 3,
                 "column": 1}],
  "finish_loc": [{"file": "t.c",
                  "line": 3,
                  "column": 1}],
  "tree code": "bind_expr",
  "bind_expr_body": {"addr": "0x7f8256bab860",
                     "expr_loc": [{"file": "t.c",
                                   "line": 4,
                                   "column": 14}],
                     "start_loc": [{"file": "t.c",
                                    "line": 4,
                                    "column": 10}],
                     "finish_loc": [{"file": "t.c",
                                     "line": 4,
                                     "column": 18}],
                     "tree code": "return_expr",
                     "return_expr": {"addr": "0x7f8256bb1b40",
                                     "expr_loc": [{"file": "t.c",
                                                   "line": 4,
                                                   "column": 14}],
                                     "start_loc": [{"file": "t.c",
                                                    "line": 4,
                                                    "column": 10}],
                                     "finish_loc": [{"file": "t.c",
                                                     "line": 4,
                                                     "column": 18}],
                                     "tree code": "plus_expr",
                                     "bin_operator": "+",
                                     "operands": [{"addr": "0x7f8256bda360",
                                                   "expr_loc": [{"file": "t.c",
                                                                 "line": 4,
                                                                 "column": 11}],
                                                   "start_loc": [{"file": "t.c",
                                                                  "line": 4,

"column": 10}],
                                                   "finish_loc":
[{"file": "t.c",
                                                                   "line": 4,

"column": 12}],
                                                   "tree code": "component_ref",
                                                   "expr": {"addr":
"0x7f8256a10c60",

"decl_loc": [{"file": "t.c",

   "line": 1,

   "column": 28}],
                                                            "tree
code": "var_decl",
                                                            "used": true,
                                                            "public": true,
                                                            " static": true,
                                                            "read": true,
                                                            "mode": "DI",

"defer-output": true,
                                                            "id_to_locale": "s",
                                                            "id_point": "s"},
                                                   "field": {"addr":
"0x7f8256a30688",

"decl_loc": [{"file": "t.c",

    "line": 1,

    "column": 16}],
                                                             "tree
code": "field_decl",
                                                             "mode": "SI",

"id_to_locale": "i",
                                                             "id_point": "i"}},
                                                  {"addr": "0x7f8256bda390",
                                                   "expr_loc": [{"file": "t.c",
                                                                 "line": 4,
                                                                 "column": 17}],
                                                   "start_loc": [{"file": "t.c",
                                                                  "line": 4,

"column": 16}],
                                                   "finish_loc":
[{"file": "t.c",
                                                                   "line": 4,

"column": 18}],
                                                   "tree code": "component_ref",
                                                   "expr": {"addr":
"0x7f8256a10c60",

"decl_loc": [{"file": "t.c",

   "line": 1,

   "column": 28}],
                                                            "tree
code": "var_decl",
                                                            "used": true,
                                                            "public": true,
                                                            " static": true,
                                                            "read": true,
                                                            "mode": "DI",

"defer-output": true,
                                                            "id_to_locale": "s",
                                                            "id_point": "s"},
                                                   "field": {"addr":
"0x7f8256a30720",

"decl_loc": [{"file": "t.c",

    "line": 1,

    "column": 23}],
                                                             "tree
code": "field_decl",
                                                             "mode": "SI",

"id_to_locale": "j",

"id_point": "j"}}]}}}]

There are three oddities I immediately notice:

The PLUS_EXPR operands are in a array "operands" while the RETURN_EXPR
"operand" or "child pointer" is refered to from "return_expr".  I think both are
tcc_expression trees and the operands are in exp.operands.  Ideally the
JSON would more closely reflect that rather than possibly following the "pretty"
printing logic.

While the tree_code of a tree node is the most important bit (maybe besides of
its address), the "tree code" attribute is after the locations (which
are also quite
verbose and distracting - at least when looking at raw JSON).  For locations
one could honor TDF_LINENO and only dump those when using
-fdump-tree-original-json-lineno.  I'd re-order "tree code" after "addr".

The third issue is that above the tree node with address 0x7f8256a10c60
(and its children) appear twice - while you maintain a splay tree and assign
unique numbers the duplicate nodes are not output by reference?  I would
suggest to use { "ref_addr" : "0x7f8256a10c60" } for the output of such
reference for example.

I'm not sure whether JSON allows different object kinds or if that's solely
done by having a special attribute if that's needed.  With the above
regular tree nodes would be "addr" and references be "ref_addr".  A recursive
JSON structure like above is OK to look at in RAW, I'm not sure whether
for automatic processing and for example translating to a graph a linear
collection of nodes with references would be easier to handle.


Few comments on the patch itself - the #include of tree-emit-json.h from
dumpfile.cc doesn't seem to be necessary.  Since you declare
dump_node_json in dumpfile.h it should be possible to elide the header
and put the contents into the tree-emit-json.cc file.

Another #include is duplicated (and also looks unnecessary).


I know you have some crude JSON -> html translation script written in
python - can you share that as well?  I'd suggest to post separate from
this main patch, adding it to contrib/.

Can we solve the multi-function issue somehow?  I know we have some
abstraction for a dump file, we'd need a hook that's invoked on opening
and closing to emit a something there - I guess it would be even OK to
hard-code this into dumpfile.cc for the -JSON dump variant.  It might
be possible to register dump specific data with that object and get
to the "current" dump file in dump_node_json so the splay-tree could
be kept live and the allocations released on dump-file close?  Again,
two hard-coded hooks from dumpfile.cc at open/close time into
the JSON dumping for this might be feasible and track the global state
with global variables.  That's to allow references to global objects and
types streamed in a previous function context.

Thanks,
Richard.


> Some high level thoughts:
>
> * the patch uses "dummy" throughout as a variable name.  To me the name
> "dummy" suggests something unimportant that we had to give a name to,
> or something that we'd prefer didn't exist but had to create.  However
> in most(all?) cases "dummy" seems to refer to the json object being
> created or having properties added to it, and thus the most interesting
> thing in the function.  I suspect that renaming "dummy" to "js_obj" or
> "json_obj" throughout would be an improvement in readability in terms
> of capturing the intent of the code (assuming that all of them are
> indeed json objects).
>
> * I think the code is leaking memory for all of the json values created
> - there are lots of uses of "naked new" in this code, but I don't see
> any uses of "delete".  For example, in
>
> > +void
> > +dump_node_json (const_tree t, dump_flags_t flags, FILE *stream)
> > +{
> > +  struct dump_info di;
> > +  dump_queue_p dq;
> > +  dump_queue_p next_dq;
> > +  pretty_printer pp;
> > +  /* Initialize the dump-information structure.  */
> > +  di.stream = stream;
> > +  di.index = 0;
> > +  di.column = 0;
> > +  di.queue = 0;
> > +  di.queue_end = 0;
> > +  di.free_list = 0;
> > +  di.flags = flags;
> > +  di.node = t;
> > +  di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
> > +                          splay_tree_delete_pointers);
> > +  di.json_dump = new json::array ();
>      ^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^
>      allocated with naked new here
>
> > +  /* Queue up the first node.  */
> > +  queue (&di, t);
> > +
> > +  /* Until the queue is empty, keep dumping nodes.  */
> > +  while (di.queue)
> > +    dequeue_and_dump (&di);
> > +
> > +  di.json_dump->dump(stream, true);
> > +  fputs("\n", stream);
> > +  /* Now, clean up.  */
> > +  for (dq = di.free_list; dq; dq = next_dq)
> > +    {
> > +      next_dq = dq->next;
> > +      free (dq);
> > +    }
> > +  splay_tree_delete (di.nodes);
>
> and di.json_dump goes out of scope here and is leaked, I think.  So I
> *think* all of the json values being created during dumping are being
> leaked.
>
> > +}
>
> Similarly, in:
>
> > +DEBUG_FUNCTION void
> > +debug_tree_json (tree t)
> > +{
> > +  json::object* _x = node_emit_json(t);
> > +  _x->dump(stderr, true);
> > +  fprintf(stderr, "\n");
> > +}
>
> if I'm reading things right, node_emit_json doesn't "emit" json so much
> as create a new json::object on the heap via "new", and when "_x" goes
> out of scope, it's leaked.
>
> The pattern in the code seems to be that node_emit_json creates a new
> json::object and populates it with properties (sometimes recursively).
>
> Given that, and that we can use C++11, I recommend using
> std::unique_ptr<json::object> for it, to capture the intent that this
> is a heap-allocated pointer with responsibility for being "delete"-d at
> some point.
>
> That way, rather that:
>
>   json::object*
>   node_emit_json(tree t)
>   {
>     tree op0, op1, type;
>     enum tree_code code;
>     expanded_location xloc;
>     json::object *dummy;
>     json::array* holder;
>     char address_buffer[sizeof(&t)] = {"\0"};
>
>     dummy = new json::object ();
>     holder = new json::array ();
>
>     [...snip...]
>
>     return dummy;
>   }
>
>
> we could have (perhaps renaming to "node_to_json"):
>
>   std::unique_ptr<json::object>
>   node_to_json(tree t)
>   {
>     tree op0, op1, type;
>     enum tree_code code;
>     expanded_location xloc;
>     char address_buffer[sizeof(&t)] = {"\0"};
>
>     auto js_obj = ::make_unique<json::object> (); // to implicitly use std::unique_ptr<json::object>
>     auto holder = ::make_unique<json::array> ();  // likewise std::unique_ptr<json::array>
>
>     [...snip...]
>
>     return js_obj;
>   }
>
> ...assuming that I'm correctly understanding the ownership of the json
> values in the patch.  Note that we have to use ::make_unique from our
> make-unique.h, rather than std::make_unique from <memory> since the
> latter was only added in C++14.
>
> Many of our data structures don't properly handle objects with
> destructors, and I suspect splay_tree is one of these.  You can use
> js_obj.release () to transfer ownership to such data structures, and
> will (probably) need to manually use "delete" on the pointers in the
> right places.
>
> What happens to "holder" in that function?  It seems to get populated
> with json objects for the various tree nodes found recursively, but
> then it seems to simply be leaked (or populated then auto-deleted, if
> we use std::unique_ptr>.  Or am I missing something?
>
> In case it's helpful, a couple of months ago I converted the SARIF
> output code from using "naked" json pointers to using std::unique_ptr
> in:
>   https://gcc.gnu.org/pipermail/gcc-patches/2024-July/658204.html
> and I found it helped a *lot* with documenting ownership and avoiding
> leaks.  You might find other things of interest in the first half of
> this patch kit:
>   https://gcc.gnu.org/pipermail/gcc-patches/2024-July/658194.html
> FWIW in that code I'm also using a class hierarchy of json::object
> subclasses to help with compliance with a JSON schema (sarif_object is
> a subclass of json::object), but given that there probably isn't a
> schema for the JSON in TDF_JSON dumps, that's probably not relevant to
> this case.
>
> FWIW you can test for leaks by running the compiler under valgrind by
> configuring with --enable-valgrind-annotations and appending "-wrapper
> valgrind" to the command line (or "-wrapper valgrind,--leak-check=full"
> IIRC).
>
> Thanks again for the patch; hope this is constructive.
> Dave
>
Thor Preimesberger Sept. 13, 2024, 6:32 a.m. UTC | #5
> There are three oddities I immediately notice:
>
> The PLUS_EXPR operands are in a array "operands" while the RETURN_EXPR
> "operand" or "child pointer" is refered to from "return_expr".  I think both are
> tcc_expression trees and the operands are in exp.operands.  Ideally the
> JSON would more closely reflect that rather than possibly following the "pretty"
> printing logic.

Ah - for the binary operator, operands may have been a poor choice of
words there.
There's an abstract nonsense definition that would not necessarily be
reasonable here.
Would it make more sense to dump it e.g. as
.....
   "bin_operator": "+",
   "op0": {"addr": "0x7f8256bda360"
               ...}
   "op1": {"addr": ...}
.....
I think there are some parts of the code that I wrote that don't have
the accessor used as their key when referring to a different node -
e.g. case PLACEHOLDER_EXPR. Would this be an issue?

> While the tree_code of a tree node is the most important bit (maybe besides of
> its address), the "tree code" attribute is after the locations (which
> are also quite
> verbose and distracting - at least when looking at raw JSON).  For locations
> one could honor TDF_LINENO and only dump those when using
> -fdump-tree-original-json-lineno.  I'd re-order "tree code" after "addr".

Sounds good - I'll implement dumping locs iff TDF_LINENO is enabled.

> The third issue is that above the tree node with address 0x7f8256a10c60
> (and its children) appear twice - while you maintain a splay tree and assign
> unique numbers the duplicate nodes are not output by reference?  I would
> suggest to use { "ref_addr" : "0x7f8256a10c60" } for the output of such
> reference for example.
>
> I'm not sure whether JSON allows different object kinds or if that's solely
> done by having a special attribute if that's needed.  With the above
> regular tree nodes would be "addr" and references be "ref_addr".  A recursive
> JSON structure like above is OK to look at in RAW, I'm not sure whether
> for automatic processing and for example translating to a graph a linear
> collection of nodes with references would be easier to handle.

I agree that it should be easier to process the JSON if the references have a
different key. Should be easy to implement.

> Few comments on the patch itself - the #include of tree-emit-json.h from
> dumpfile.cc doesn't seem to be necessary.  Since you declare
> dump_node_json in dumpfile.h it should be possible to elide the header
> and put the contents into the tree-emit-json.cc file.
>
> Another #include is duplicated (and also looks unnecessary).
>

All fixed now on my working tree.

> I know you have some crude JSON -> html translation script written in
> python - can you share that as well?  I'd suggest to post separate from
> this main patch, adding it to contrib/.

Sure - let me get the fixes suggested in this email done since it'll
change (and simplify) the logic a bit.

> Can we solve the multi-function issue somehow?  I know we have some
> abstraction for a dump file, we'd need a hook that's invoked on opening
> and closing to emit a something there - I guess it would be even OK to
> hard-code this into dumpfile.cc for the -JSON dump variant.  It might
> be possible to register dump specific data with that object and get
> to the "current" dump file in dump_node_json so the splay-tree could
> be kept live and the allocations released on dump-file close?  Again,
> two hard-coded hooks from dumpfile.cc at open/close time into
> the JSON dumping for this might be feasible and track the global state
> with global variables.  That's to allow references to global objects and
> types streamed in a previous function context.

If the multi-function issue is that the dump pass currently produces
a series of JSON objects rather than a single one - I think what you're
suggesting is essentially done by optrecord_json_writer, for
-fsave-optimization-record. One approach I have in my head
is for, let's call it a tree_json_writer, to hold a
json::array, append each node we traverse, and then
flush this array to the dumpfile at the end.

This would also enable a way to address what you brought
up at the very end.

(In the python script I have written up, I just call the bash command
I posted in the first email to turn the output into a single JSON object.
I don't expect that it's really possible to call sed from within gcc.)

Best,
Thor

On Thu, Sep 12, 2024 at 7:14 AM Richard Biener
<richard.guenther@gmail.com> wrote:
>
> On Thu, Sep 12, 2024 at 12:51 PM David Malcolm <dmalcolm@redhat.com> wrote:
> >
> > On Wed, 2024-09-11 at 20:49 -0500, tcpreimesberger@gmail.com wrote:
> > > From: Thor C Preimesberger <tcpreimesberger@gmail.com>
> > >
> > > This patch allows the compiler to dump GENERIC trees as JSON objects.
> > >
> > > The dump flag -fdump-tree-original-json dumps each fndecl node in the
> > > C frontend's gimplifier as a JSON object and traverses related nodes
> > > in an analagous manner as to raw-dumping.
> >
> > Thanks for posting this patch.
> >
> > Are you able to upload somewhere some examples of what the dumps look
> > like?
>
> I found https://renhongl.github.io/json-editor/ which seems to accept
> the output of -fdump-tree-original-json visualizes the raw JSON structure
> when the input is from a single function.
>
> struct S { int i; int j; } s;
> int bar ()
> {
>   return s.i + s.j;
> }
> int main()
> {
>   return bar ();
> }
>
> no longer recognizes it, I would guess we'd need to produce an outer
> "file level" JSON node.  Simply wrapping the file in [{ ... }] didn't
> work even with comma separating two functions.
>
> The JSON for bar looks like (sorry for the long paste)
>
> [{"addr": "0x7f8256bda3c0",
>   "expr_loc": [{"file": "t.c",
>                 "line": 3,
>                 "column": 1}],
>   "start_loc": [{"file": "t.c",
>                  "line": 3,
>                  "column": 1}],
>   "finish_loc": [{"file": "t.c",
>                   "line": 3,
>                   "column": 1}],
>   "tree code": "bind_expr",
>   "bind_expr_body": {"addr": "0x7f8256bab860",
>                      "expr_loc": [{"file": "t.c",
>                                    "line": 4,
>                                    "column": 14}],
>                      "start_loc": [{"file": "t.c",
>                                     "line": 4,
>                                     "column": 10}],
>                      "finish_loc": [{"file": "t.c",
>                                      "line": 4,
>                                      "column": 18}],
>                      "tree code": "return_expr",
>                      "return_expr": {"addr": "0x7f8256bb1b40",
>                                      "expr_loc": [{"file": "t.c",
>                                                    "line": 4,
>                                                    "column": 14}],
>                                      "start_loc": [{"file": "t.c",
>                                                     "line": 4,
>                                                     "column": 10}],
>                                      "finish_loc": [{"file": "t.c",
>                                                      "line": 4,
>                                                      "column": 18}],
>                                      "tree code": "plus_expr",
>                                      "bin_operator": "+",
>                                      "operands": [{"addr": "0x7f8256bda360",
>                                                    "expr_loc": [{"file": "t.c",
>                                                                  "line": 4,
>                                                                  "column": 11}],
>                                                    "start_loc": [{"file": "t.c",
>                                                                   "line": 4,
>
> "column": 10}],
>                                                    "finish_loc":
> [{"file": "t.c",
>                                                                    "line": 4,
>
> "column": 12}],
>                                                    "tree code": "component_ref",
>                                                    "expr": {"addr":
> "0x7f8256a10c60",
>
> "decl_loc": [{"file": "t.c",
>
>    "line": 1,
>
>    "column": 28}],
>                                                             "tree
> code": "var_decl",
>                                                             "used": true,
>                                                             "public": true,
>                                                             " static": true,
>                                                             "read": true,
>                                                             "mode": "DI",
>
> "defer-output": true,
>                                                             "id_to_locale": "s",
>                                                             "id_point": "s"},
>                                                    "field": {"addr":
> "0x7f8256a30688",
>
> "decl_loc": [{"file": "t.c",
>
>     "line": 1,
>
>     "column": 16}],
>                                                              "tree
> code": "field_decl",
>                                                              "mode": "SI",
>
> "id_to_locale": "i",
>                                                              "id_point": "i"}},
>                                                   {"addr": "0x7f8256bda390",
>                                                    "expr_loc": [{"file": "t.c",
>                                                                  "line": 4,
>                                                                  "column": 17}],
>                                                    "start_loc": [{"file": "t.c",
>                                                                   "line": 4,
>
> "column": 16}],
>                                                    "finish_loc":
> [{"file": "t.c",
>                                                                    "line": 4,
>
> "column": 18}],
>                                                    "tree code": "component_ref",
>                                                    "expr": {"addr":
> "0x7f8256a10c60",
>
> "decl_loc": [{"file": "t.c",
>
>    "line": 1,
>
>    "column": 28}],
>                                                             "tree
> code": "var_decl",
>                                                             "used": true,
>                                                             "public": true,
>                                                             " static": true,
>                                                             "read": true,
>                                                             "mode": "DI",
>
> "defer-output": true,
>                                                             "id_to_locale": "s",
>                                                             "id_point": "s"},
>                                                    "field": {"addr":
> "0x7f8256a30720",
>
> "decl_loc": [{"file": "t.c",
>
>     "line": 1,
>
>     "column": 23}],
>                                                              "tree
> code": "field_decl",
>                                                              "mode": "SI",
>
> "id_to_locale": "j",
>
> "id_point": "j"}}]}}}]
>
> There are three oddities I immediately notice:
>
> The PLUS_EXPR operands are in a array "operands" while the RETURN_EXPR
> "operand" or "child pointer" is refered to from "return_expr".  I think both are
> tcc_expression trees and the operands are in exp.operands.  Ideally the
> JSON would more closely reflect that rather than possibly following the "pretty"
> printing logic.
>
> While the tree_code of a tree node is the most important bit (maybe besides of
> its address), the "tree code" attribute is after the locations (which
> are also quite
> verbose and distracting - at least when looking at raw JSON).  For locations
> one could honor TDF_LINENO and only dump those when using
> -fdump-tree-original-json-lineno.  I'd re-order "tree code" after "addr".
>
> The third issue is that above the tree node with address 0x7f8256a10c60
> (and its children) appear twice - while you maintain a splay tree and assign
> unique numbers the duplicate nodes are not output by reference?  I would
> suggest to use { "ref_addr" : "0x7f8256a10c60" } for the output of such
> reference for example.
>
> I'm not sure whether JSON allows different object kinds or if that's solely
> done by having a special attribute if that's needed.  With the above
> regular tree nodes would be "addr" and references be "ref_addr".  A recursive
> JSON structure like above is OK to look at in RAW, I'm not sure whether
> for automatic processing and for example translating to a graph a linear
> collection of nodes with references would be easier to handle.
>
>
> Few comments on the patch itself - the #include of tree-emit-json.h from
> dumpfile.cc doesn't seem to be necessary.  Since you declare
> dump_node_json in dumpfile.h it should be possible to elide the header
> and put the contents into the tree-emit-json.cc file.
>
> Another #include is duplicated (and also looks unnecessary).
>
>
> I know you have some crude JSON -> html translation script written in
> python - can you share that as well?  I'd suggest to post separate from
> this main patch, adding it to contrib/.
>
> Can we solve the multi-function issue somehow?  I know we have some
> abstraction for a dump file, we'd need a hook that's invoked on opening
> and closing to emit a something there - I guess it would be even OK to
> hard-code this into dumpfile.cc for the -JSON dump variant.  It might
> be possible to register dump specific data with that object and get
> to the "current" dump file in dump_node_json so the splay-tree could
> be kept live and the allocations released on dump-file close?  Again,
> two hard-coded hooks from dumpfile.cc at open/close time into
> the JSON dumping for this might be feasible and track the global state
> with global variables.  That's to allow references to global objects and
> types streamed in a previous function context.
>
> Thanks,
> Richard.
>
>
> > Some high level thoughts:
> >
> > * the patch uses "dummy" throughout as a variable name.  To me the name
> > "dummy" suggests something unimportant that we had to give a name to,
> > or something that we'd prefer didn't exist but had to create.  However
> > in most(all?) cases "dummy" seems to refer to the json object being
> > created or having properties added to it, and thus the most interesting
> > thing in the function.  I suspect that renaming "dummy" to "js_obj" or
> > "json_obj" throughout would be an improvement in readability in terms
> > of capturing the intent of the code (assuming that all of them are
> > indeed json objects).
> >
> > * I think the code is leaking memory for all of the json values created
> > - there are lots of uses of "naked new" in this code, but I don't see
> > any uses of "delete".  For example, in
> >
> > > +void
> > > +dump_node_json (const_tree t, dump_flags_t flags, FILE *stream)
> > > +{
> > > +  struct dump_info di;
> > > +  dump_queue_p dq;
> > > +  dump_queue_p next_dq;
> > > +  pretty_printer pp;
> > > +  /* Initialize the dump-information structure.  */
> > > +  di.stream = stream;
> > > +  di.index = 0;
> > > +  di.column = 0;
> > > +  di.queue = 0;
> > > +  di.queue_end = 0;
> > > +  di.free_list = 0;
> > > +  di.flags = flags;
> > > +  di.node = t;
> > > +  di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
> > > +                          splay_tree_delete_pointers);
> > > +  di.json_dump = new json::array ();
> >      ^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^
> >      allocated with naked new here
> >
> > > +  /* Queue up the first node.  */
> > > +  queue (&di, t);
> > > +
> > > +  /* Until the queue is empty, keep dumping nodes.  */
> > > +  while (di.queue)
> > > +    dequeue_and_dump (&di);
> > > +
> > > +  di.json_dump->dump(stream, true);
> > > +  fputs("\n", stream);
> > > +  /* Now, clean up.  */
> > > +  for (dq = di.free_list; dq; dq = next_dq)
> > > +    {
> > > +      next_dq = dq->next;
> > > +      free (dq);
> > > +    }
> > > +  splay_tree_delete (di.nodes);
> >
> > and di.json_dump goes out of scope here and is leaked, I think.  So I
> > *think* all of the json values being created during dumping are being
> > leaked.
> >
> > > +}
> >
> > Similarly, in:
> >
> > > +DEBUG_FUNCTION void
> > > +debug_tree_json (tree t)
> > > +{
> > > +  json::object* _x = node_emit_json(t);
> > > +  _x->dump(stderr, true);
> > > +  fprintf(stderr, "\n");
> > > +}
> >
> > if I'm reading things right, node_emit_json doesn't "emit" json so much
> > as create a new json::object on the heap via "new", and when "_x" goes
> > out of scope, it's leaked.
> >
> > The pattern in the code seems to be that node_emit_json creates a new
> > json::object and populates it with properties (sometimes recursively).
> >
> > Given that, and that we can use C++11, I recommend using
> > std::unique_ptr<json::object> for it, to capture the intent that this
> > is a heap-allocated pointer with responsibility for being "delete"-d at
> > some point.
> >
> > That way, rather that:
> >
> >   json::object*
> >   node_emit_json(tree t)
> >   {
> >     tree op0, op1, type;
> >     enum tree_code code;
> >     expanded_location xloc;
> >     json::object *dummy;
> >     json::array* holder;
> >     char address_buffer[sizeof(&t)] = {"\0"};
> >
> >     dummy = new json::object ();
> >     holder = new json::array ();
> >
> >     [...snip...]
> >
> >     return dummy;
> >   }
> >
> >
> > we could have (perhaps renaming to "node_to_json"):
> >
> >   std::unique_ptr<json::object>
> >   node_to_json(tree t)
> >   {
> >     tree op0, op1, type;
> >     enum tree_code code;
> >     expanded_location xloc;
> >     char address_buffer[sizeof(&t)] = {"\0"};
> >
> >     auto js_obj = ::make_unique<json::object> (); // to implicitly use std::unique_ptr<json::object>
> >     auto holder = ::make_unique<json::array> ();  // likewise std::unique_ptr<json::array>
> >
> >     [...snip...]
> >
> >     return js_obj;
> >   }
> >
> > ...assuming that I'm correctly understanding the ownership of the json
> > values in the patch.  Note that we have to use ::make_unique from our
> > make-unique.h, rather than std::make_unique from <memory> since the
> > latter was only added in C++14.
> >
> > Many of our data structures don't properly handle objects with
> > destructors, and I suspect splay_tree is one of these.  You can use
> > js_obj.release () to transfer ownership to such data structures, and
> > will (probably) need to manually use "delete" on the pointers in the
> > right places.
> >
> > What happens to "holder" in that function?  It seems to get populated
> > with json objects for the various tree nodes found recursively, but
> > then it seems to simply be leaked (or populated then auto-deleted, if
> > we use std::unique_ptr>.  Or am I missing something?
> >
> > In case it's helpful, a couple of months ago I converted the SARIF
> > output code from using "naked" json pointers to using std::unique_ptr
> > in:
> >   https://gcc.gnu.org/pipermail/gcc-patches/2024-July/658204.html
> > and I found it helped a *lot* with documenting ownership and avoiding
> > leaks.  You might find other things of interest in the first half of
> > this patch kit:
> >   https://gcc.gnu.org/pipermail/gcc-patches/2024-July/658194.html
> > FWIW in that code I'm also using a class hierarchy of json::object
> > subclasses to help with compliance with a JSON schema (sarif_object is
> > a subclass of json::object), but given that there probably isn't a
> > schema for the JSON in TDF_JSON dumps, that's probably not relevant to
> > this case.
> >
> > FWIW you can test for leaks by running the compiler under valgrind by
> > configuring with --enable-valgrind-annotations and appending "-wrapper
> > valgrind" to the command line (or "-wrapper valgrind,--leak-check=full"
> > IIRC).
> >
> > Thanks again for the patch; hope this is constructive.
> > Dave
> >
Richard Biener Sept. 13, 2024, 8:02 a.m. UTC | #6
On Fri, Sep 13, 2024 at 8:32 AM Thor Preimesberger
<tcpreimesberger@gmail.com> wrote:
>
> > There are three oddities I immediately notice:
> >
> > The PLUS_EXPR operands are in a array "operands" while the RETURN_EXPR
> > "operand" or "child pointer" is refered to from "return_expr".  I think both are
> > tcc_expression trees and the operands are in exp.operands.  Ideally the
> > JSON would more closely reflect that rather than possibly following the "pretty"
> > printing logic.
>
> Ah - for the binary operator, operands may have been a poor choice of
> words there.
> There's an abstract nonsense definition that would not necessarily be
> reasonable here.
> Would it make more sense to dump it e.g. as
> .....
>    "bin_operator": "+",
>    "op0": {"addr": "0x7f8256bda360"
>                ...}
>    "op1": {"addr": ...}
> .....

I actually liked the array, so following using accessors it then would be

   "operand" : [ {...}, {...} ]

omitting tree_ (give we're dumping trees), if I got the idea right
that [] denotes an array of sub-objects in JSON.

That you have both

>                                      "tree code": "plus_expr",
>                                      "bin_operator": "+",

is a bit redundant, the 'bin_operator' would be something that's
the same for all nodes with 'tree code' : 'plus_expr'.  I would simply
omit that attribute.

> I think there are some parts of the code that I wrote that don't have
> the accessor used as their key when referring to a different node -
> e.g. case PLACEHOLDER_EXPR. Would this be an issue?

Well, it's just names - but yes, using the accessor is probably most useful
to developers as they are likely familiar with that.

> > While the tree_code of a tree node is the most important bit (maybe besides of
> > its address), the "tree code" attribute is after the locations (which
> > are also quite
> > verbose and distracting - at least when looking at raw JSON).  For locations
> > one could honor TDF_LINENO and only dump those when using
> > -fdump-tree-original-json-lineno.  I'd re-order "tree code" after "addr".
>
> Sounds good - I'll implement dumping locs iff TDF_LINENO is enabled.
>
> > The third issue is that above the tree node with address 0x7f8256a10c60
> > (and its children) appear twice - while you maintain a splay tree and assign
> > unique numbers the duplicate nodes are not output by reference?  I would
> > suggest to use { "ref_addr" : "0x7f8256a10c60" } for the output of such
> > reference for example.
> >
> > I'm not sure whether JSON allows different object kinds or if that's solely
> > done by having a special attribute if that's needed.  With the above
> > regular tree nodes would be "addr" and references be "ref_addr".  A recursive
> > JSON structure like above is OK to look at in RAW, I'm not sure whether
> > for automatic processing and for example translating to a graph a linear
> > collection of nodes with references would be easier to handle.
>
> I agree that it should be easier to process the JSON if the references have a
> different key. Should be easy to implement.

Yep, the important part is to avoid the duplicates in the JSON.

> > Few comments on the patch itself - the #include of tree-emit-json.h from
> > dumpfile.cc doesn't seem to be necessary.  Since you declare
> > dump_node_json in dumpfile.h it should be possible to elide the header
> > and put the contents into the tree-emit-json.cc file.
> >
> > Another #include is duplicated (and also looks unnecessary).
> >
>
> All fixed now on my working tree.
>
> > I know you have some crude JSON -> html translation script written in
> > python - can you share that as well?  I'd suggest to post separate from
> > this main patch, adding it to contrib/.
>
> Sure - let me get the fixes suggested in this email done since it'll
> change (and simplify) the logic a bit.
>
> > Can we solve the multi-function issue somehow?  I know we have some
> > abstraction for a dump file, we'd need a hook that's invoked on opening
> > and closing to emit a something there - I guess it would be even OK to
> > hard-code this into dumpfile.cc for the -JSON dump variant.  It might
> > be possible to register dump specific data with that object and get
> > to the "current" dump file in dump_node_json so the splay-tree could
> > be kept live and the allocations released on dump-file close?  Again,
> > two hard-coded hooks from dumpfile.cc at open/close time into
> > the JSON dumping for this might be feasible and track the global state
> > with global variables.  That's to allow references to global objects and
> > types streamed in a previous function context.
>
> If the multi-function issue is that the dump pass currently produces
> a series of JSON objects rather than a single one - I think what you're
> suggesting is essentially done by optrecord_json_writer, for
> -fsave-optimization-record. One approach I have in my head
> is for, let's call it a tree_json_writer, to hold a
> json::array, append each node we traverse, and then
> flush this array to the dumpfile at the end.

Yeah, that would work as well.

Thanks,
Richard.

> This would also enable a way to address what you brought
> up at the very end.
>
> (In the python script I have written up, I just call the bash command
> I posted in the first email to turn the output into a single JSON object.
> I don't expect that it's really possible to call sed from within gcc.)
>
> Best,
> Thor
>
> On Thu, Sep 12, 2024 at 7:14 AM Richard Biener
> <richard.guenther@gmail.com> wrote:
> >
> > On Thu, Sep 12, 2024 at 12:51 PM David Malcolm <dmalcolm@redhat.com> wrote:
> > >
> > > On Wed, 2024-09-11 at 20:49 -0500, tcpreimesberger@gmail.com wrote:
> > > > From: Thor C Preimesberger <tcpreimesberger@gmail.com>
> > > >
> > > > This patch allows the compiler to dump GENERIC trees as JSON objects.
> > > >
> > > > The dump flag -fdump-tree-original-json dumps each fndecl node in the
> > > > C frontend's gimplifier as a JSON object and traverses related nodes
> > > > in an analagous manner as to raw-dumping.
> > >
> > > Thanks for posting this patch.
> > >
> > > Are you able to upload somewhere some examples of what the dumps look
> > > like?
> >
> > I found https://renhongl.github.io/json-editor/ which seems to accept
> > the output of -fdump-tree-original-json visualizes the raw JSON structure
> > when the input is from a single function.
> >
> > struct S { int i; int j; } s;
> > int bar ()
> > {
> >   return s.i + s.j;
> > }
> > int main()
> > {
> >   return bar ();
> > }
> >
> > no longer recognizes it, I would guess we'd need to produce an outer
> > "file level" JSON node.  Simply wrapping the file in [{ ... }] didn't
> > work even with comma separating two functions.
> >
> > The JSON for bar looks like (sorry for the long paste)
> >
> > [{"addr": "0x7f8256bda3c0",
> >   "expr_loc": [{"file": "t.c",
> >                 "line": 3,
> >                 "column": 1}],
> >   "start_loc": [{"file": "t.c",
> >                  "line": 3,
> >                  "column": 1}],
> >   "finish_loc": [{"file": "t.c",
> >                   "line": 3,
> >                   "column": 1}],
> >   "tree code": "bind_expr",
> >   "bind_expr_body": {"addr": "0x7f8256bab860",
> >                      "expr_loc": [{"file": "t.c",
> >                                    "line": 4,
> >                                    "column": 14}],
> >                      "start_loc": [{"file": "t.c",
> >                                     "line": 4,
> >                                     "column": 10}],
> >                      "finish_loc": [{"file": "t.c",
> >                                      "line": 4,
> >                                      "column": 18}],
> >                      "tree code": "return_expr",
> >                      "return_expr": {"addr": "0x7f8256bb1b40",
> >                                      "expr_loc": [{"file": "t.c",
> >                                                    "line": 4,
> >                                                    "column": 14}],
> >                                      "start_loc": [{"file": "t.c",
> >                                                     "line": 4,
> >                                                     "column": 10}],
> >                                      "finish_loc": [{"file": "t.c",
> >                                                      "line": 4,
> >                                                      "column": 18}],
> >                                      "tree code": "plus_expr",
> >                                      "bin_operator": "+",
> >                                      "operands": [{"addr": "0x7f8256bda360",
> >                                                    "expr_loc": [{"file": "t.c",
> >                                                                  "line": 4,
> >                                                                  "column": 11}],
> >                                                    "start_loc": [{"file": "t.c",
> >                                                                   "line": 4,
> >
> > "column": 10}],
> >                                                    "finish_loc":
> > [{"file": "t.c",
> >                                                                    "line": 4,
> >
> > "column": 12}],
> >                                                    "tree code": "component_ref",
> >                                                    "expr": {"addr":
> > "0x7f8256a10c60",
> >
> > "decl_loc": [{"file": "t.c",
> >
> >    "line": 1,
> >
> >    "column": 28}],
> >                                                             "tree
> > code": "var_decl",
> >                                                             "used": true,
> >                                                             "public": true,
> >                                                             " static": true,
> >                                                             "read": true,
> >                                                             "mode": "DI",
> >
> > "defer-output": true,
> >                                                             "id_to_locale": "s",
> >                                                             "id_point": "s"},
> >                                                    "field": {"addr":
> > "0x7f8256a30688",
> >
> > "decl_loc": [{"file": "t.c",
> >
> >     "line": 1,
> >
> >     "column": 16}],
> >                                                              "tree
> > code": "field_decl",
> >                                                              "mode": "SI",
> >
> > "id_to_locale": "i",
> >                                                              "id_point": "i"}},
> >                                                   {"addr": "0x7f8256bda390",
> >                                                    "expr_loc": [{"file": "t.c",
> >                                                                  "line": 4,
> >                                                                  "column": 17}],
> >                                                    "start_loc": [{"file": "t.c",
> >                                                                   "line": 4,
> >
> > "column": 16}],
> >                                                    "finish_loc":
> > [{"file": "t.c",
> >                                                                    "line": 4,
> >
> > "column": 18}],
> >                                                    "tree code": "component_ref",
> >                                                    "expr": {"addr":
> > "0x7f8256a10c60",
> >
> > "decl_loc": [{"file": "t.c",
> >
> >    "line": 1,
> >
> >    "column": 28}],
> >                                                             "tree
> > code": "var_decl",
> >                                                             "used": true,
> >                                                             "public": true,
> >                                                             " static": true,
> >                                                             "read": true,
> >                                                             "mode": "DI",
> >
> > "defer-output": true,
> >                                                             "id_to_locale": "s",
> >                                                             "id_point": "s"},
> >                                                    "field": {"addr":
> > "0x7f8256a30720",
> >
> > "decl_loc": [{"file": "t.c",
> >
> >     "line": 1,
> >
> >     "column": 23}],
> >                                                              "tree
> > code": "field_decl",
> >                                                              "mode": "SI",
> >
> > "id_to_locale": "j",
> >
> > "id_point": "j"}}]}}}]
> >
> > There are three oddities I immediately notice:
> >
> > The PLUS_EXPR operands are in a array "operands" while the RETURN_EXPR
> > "operand" or "child pointer" is refered to from "return_expr".  I think both are
> > tcc_expression trees and the operands are in exp.operands.  Ideally the
> > JSON would more closely reflect that rather than possibly following the "pretty"
> > printing logic.
> >
> > While the tree_code of a tree node is the most important bit (maybe besides of
> > its address), the "tree code" attribute is after the locations (which
> > are also quite
> > verbose and distracting - at least when looking at raw JSON).  For locations
> > one could honor TDF_LINENO and only dump those when using
> > -fdump-tree-original-json-lineno.  I'd re-order "tree code" after "addr".
> >
> > The third issue is that above the tree node with address 0x7f8256a10c60
> > (and its children) appear twice - while you maintain a splay tree and assign
> > unique numbers the duplicate nodes are not output by reference?  I would
> > suggest to use { "ref_addr" : "0x7f8256a10c60" } for the output of such
> > reference for example.
> >
> > I'm not sure whether JSON allows different object kinds or if that's solely
> > done by having a special attribute if that's needed.  With the above
> > regular tree nodes would be "addr" and references be "ref_addr".  A recursive
> > JSON structure like above is OK to look at in RAW, I'm not sure whether
> > for automatic processing and for example translating to a graph a linear
> > collection of nodes with references would be easier to handle.
> >
> >
> > Few comments on the patch itself - the #include of tree-emit-json.h from
> > dumpfile.cc doesn't seem to be necessary.  Since you declare
> > dump_node_json in dumpfile.h it should be possible to elide the header
> > and put the contents into the tree-emit-json.cc file.
> >
> > Another #include is duplicated (and also looks unnecessary).
> >
> >
> > I know you have some crude JSON -> html translation script written in
> > python - can you share that as well?  I'd suggest to post separate from
> > this main patch, adding it to contrib/.
> >
> > Can we solve the multi-function issue somehow?  I know we have some
> > abstraction for a dump file, we'd need a hook that's invoked on opening
> > and closing to emit a something there - I guess it would be even OK to
> > hard-code this into dumpfile.cc for the -JSON dump variant.  It might
> > be possible to register dump specific data with that object and get
> > to the "current" dump file in dump_node_json so the splay-tree could
> > be kept live and the allocations released on dump-file close?  Again,
> > two hard-coded hooks from dumpfile.cc at open/close time into
> > the JSON dumping for this might be feasible and track the global state
> > with global variables.  That's to allow references to global objects and
> > types streamed in a previous function context.
> >
> > Thanks,
> > Richard.
> >
> >
> > > Some high level thoughts:
> > >
> > > * the patch uses "dummy" throughout as a variable name.  To me the name
> > > "dummy" suggests something unimportant that we had to give a name to,
> > > or something that we'd prefer didn't exist but had to create.  However
> > > in most(all?) cases "dummy" seems to refer to the json object being
> > > created or having properties added to it, and thus the most interesting
> > > thing in the function.  I suspect that renaming "dummy" to "js_obj" or
> > > "json_obj" throughout would be an improvement in readability in terms
> > > of capturing the intent of the code (assuming that all of them are
> > > indeed json objects).
> > >
> > > * I think the code is leaking memory for all of the json values created
> > > - there are lots of uses of "naked new" in this code, but I don't see
> > > any uses of "delete".  For example, in
> > >
> > > > +void
> > > > +dump_node_json (const_tree t, dump_flags_t flags, FILE *stream)
> > > > +{
> > > > +  struct dump_info di;
> > > > +  dump_queue_p dq;
> > > > +  dump_queue_p next_dq;
> > > > +  pretty_printer pp;
> > > > +  /* Initialize the dump-information structure.  */
> > > > +  di.stream = stream;
> > > > +  di.index = 0;
> > > > +  di.column = 0;
> > > > +  di.queue = 0;
> > > > +  di.queue_end = 0;
> > > > +  di.free_list = 0;
> > > > +  di.flags = flags;
> > > > +  di.node = t;
> > > > +  di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
> > > > +                          splay_tree_delete_pointers);
> > > > +  di.json_dump = new json::array ();
> > >      ^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^
> > >      allocated with naked new here
> > >
> > > > +  /* Queue up the first node.  */
> > > > +  queue (&di, t);
> > > > +
> > > > +  /* Until the queue is empty, keep dumping nodes.  */
> > > > +  while (di.queue)
> > > > +    dequeue_and_dump (&di);
> > > > +
> > > > +  di.json_dump->dump(stream, true);
> > > > +  fputs("\n", stream);
> > > > +  /* Now, clean up.  */
> > > > +  for (dq = di.free_list; dq; dq = next_dq)
> > > > +    {
> > > > +      next_dq = dq->next;
> > > > +      free (dq);
> > > > +    }
> > > > +  splay_tree_delete (di.nodes);
> > >
> > > and di.json_dump goes out of scope here and is leaked, I think.  So I
> > > *think* all of the json values being created during dumping are being
> > > leaked.
> > >
> > > > +}
> > >
> > > Similarly, in:
> > >
> > > > +DEBUG_FUNCTION void
> > > > +debug_tree_json (tree t)
> > > > +{
> > > > +  json::object* _x = node_emit_json(t);
> > > > +  _x->dump(stderr, true);
> > > > +  fprintf(stderr, "\n");
> > > > +}
> > >
> > > if I'm reading things right, node_emit_json doesn't "emit" json so much
> > > as create a new json::object on the heap via "new", and when "_x" goes
> > > out of scope, it's leaked.
> > >
> > > The pattern in the code seems to be that node_emit_json creates a new
> > > json::object and populates it with properties (sometimes recursively).
> > >
> > > Given that, and that we can use C++11, I recommend using
> > > std::unique_ptr<json::object> for it, to capture the intent that this
> > > is a heap-allocated pointer with responsibility for being "delete"-d at
> > > some point.
> > >
> > > That way, rather that:
> > >
> > >   json::object*
> > >   node_emit_json(tree t)
> > >   {
> > >     tree op0, op1, type;
> > >     enum tree_code code;
> > >     expanded_location xloc;
> > >     json::object *dummy;
> > >     json::array* holder;
> > >     char address_buffer[sizeof(&t)] = {"\0"};
> > >
> > >     dummy = new json::object ();
> > >     holder = new json::array ();
> > >
> > >     [...snip...]
> > >
> > >     return dummy;
> > >   }
> > >
> > >
> > > we could have (perhaps renaming to "node_to_json"):
> > >
> > >   std::unique_ptr<json::object>
> > >   node_to_json(tree t)
> > >   {
> > >     tree op0, op1, type;
> > >     enum tree_code code;
> > >     expanded_location xloc;
> > >     char address_buffer[sizeof(&t)] = {"\0"};
> > >
> > >     auto js_obj = ::make_unique<json::object> (); // to implicitly use std::unique_ptr<json::object>
> > >     auto holder = ::make_unique<json::array> ();  // likewise std::unique_ptr<json::array>
> > >
> > >     [...snip...]
> > >
> > >     return js_obj;
> > >   }
> > >
> > > ...assuming that I'm correctly understanding the ownership of the json
> > > values in the patch.  Note that we have to use ::make_unique from our
> > > make-unique.h, rather than std::make_unique from <memory> since the
> > > latter was only added in C++14.
> > >
> > > Many of our data structures don't properly handle objects with
> > > destructors, and I suspect splay_tree is one of these.  You can use
> > > js_obj.release () to transfer ownership to such data structures, and
> > > will (probably) need to manually use "delete" on the pointers in the
> > > right places.
> > >
> > > What happens to "holder" in that function?  It seems to get populated
> > > with json objects for the various tree nodes found recursively, but
> > > then it seems to simply be leaked (or populated then auto-deleted, if
> > > we use std::unique_ptr>.  Or am I missing something?
> > >
> > > In case it's helpful, a couple of months ago I converted the SARIF
> > > output code from using "naked" json pointers to using std::unique_ptr
> > > in:
> > >   https://gcc.gnu.org/pipermail/gcc-patches/2024-July/658204.html
> > > and I found it helped a *lot* with documenting ownership and avoiding
> > > leaks.  You might find other things of interest in the first half of
> > > this patch kit:
> > >   https://gcc.gnu.org/pipermail/gcc-patches/2024-July/658194.html
> > > FWIW in that code I'm also using a class hierarchy of json::object
> > > subclasses to help with compliance with a JSON schema (sarif_object is
> > > a subclass of json::object), but given that there probably isn't a
> > > schema for the JSON in TDF_JSON dumps, that's probably not relevant to
> > > this case.
> > >
> > > FWIW you can test for leaks by running the compiler under valgrind by
> > > configuring with --enable-valgrind-annotations and appending "-wrapper
> > > valgrind" to the command line (or "-wrapper valgrind,--leak-check=full"
> > > IIRC).
> > >
> > > Thanks again for the patch; hope this is constructive.
> > > Dave
> > >
diff mbox series

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 68fda1a7591..b65cc7f0ad5 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1042,6 +1042,7 @@  OPTS_H = $(INPUT_H) $(VEC_H) opts.h $(OBSTACK_H)
 SYMTAB_H = $(srcdir)/../libcpp/include/symtab.h $(OBSTACK_H)
 CPP_INTERNAL_H = $(srcdir)/../libcpp/internal.h
 TREE_DUMP_H = tree-dump.h $(SPLAY_TREE_H) $(DUMPFILE_H)
+TREE_EMIT_JSON_H = tree-emit-json.h $(SPLAY_TREE_H) $(DUMPFILE_H) json.h
 TREE_PASS_H = tree-pass.h $(TIMEVAR_H) $(DUMPFILE_H)
 TREE_SSA_H = tree-ssa.h tree-ssa-operands.h \
 		$(BITMAP_H) sbitmap.h $(BASIC_BLOCK_H) $(GIMPLE_H) \
@@ -1709,6 +1710,7 @@  OBJS = \
 	tree-diagnostic.o \
 	tree-diagnostic-client-data-hooks.o \
 	tree-dump.o \
+	tree-emit-json.o \
 	tree-eh.o \
 	tree-emutls.o \
 	tree-if-conv.o \
diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc
index 3e29766e092..8b0c80f4f75 100644
--- a/gcc/c-family/c-gimplify.cc
+++ b/gcc/c-family/c-gimplify.cc
@@ -24,6 +24,7 @@  along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
+#define INCLUDE_MEMORY
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
@@ -43,6 +44,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "context.h"
 #include "tree-pass.h"
 #include "internal-fn.h"
+#include "tree-emit-json.h"
 
 /*  The gimplification pass converts the language-dependent trees
     (ld-trees) emitted by the parser into language-independent trees
@@ -629,20 +631,26 @@  c_genericize (tree fndecl)
   local_dump_flags = dfi->pflags;
   if (dump_orig)
     {
-      fprintf (dump_orig, "\n;; Function %s",
-	       lang_hooks.decl_printable_name (fndecl, 2));
-      fprintf (dump_orig, " (%s)\n",
-	       (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null"
-		: IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))));
-      fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original));
-      fprintf (dump_orig, "\n");
-
-      if (local_dump_flags & TDF_RAW)
-	dump_node (DECL_SAVED_TREE (fndecl),
+      if (local_dump_flags & TDF_JSON)
+	dump_node_json (DECL_SAVED_TREE (fndecl),
 		   TDF_SLIM | local_dump_flags, dump_orig);
       else
-	print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl));
+      {
+	fprintf (dump_orig, "\n;; Function %s",
+		 lang_hooks.decl_printable_name (fndecl, 2));
+	fprintf (dump_orig, " (%s)\n",
+		(!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null"
+		 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))));
+	fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original));
+	fprintf (dump_orig, "\n");
+	if (local_dump_flags & TDF_RAW)
+	  dump_node (DECL_SAVED_TREE (fndecl),
+		     TDF_SLIM | local_dump_flags, dump_orig);
+	else
+	  print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl));
+      
       fprintf (dump_orig, "\n");
+      }
     }
 
   /* Dump all nested functions now.  */
diff --git a/gcc/cp/dump.cc b/gcc/cp/dump.cc
index aafb62ffaa0..b1083de5f46 100644
--- a/gcc/cp/dump.cc
+++ b/gcc/cp/dump.cc
@@ -22,6 +22,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "cp-tree.h"
+#define INCLUDE_MEMORY
 #include "tree-dump.h"
 
 /* Dump a representation of the accessibility information associated
diff --git a/gcc/dumpfile.cc b/gcc/dumpfile.cc
index 074da7df216..44d9451cf7c 100644
--- a/gcc/dumpfile.cc
+++ b/gcc/dumpfile.cc
@@ -43,6 +43,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "spellcheck.h"
 #include "make-unique.h"
 #include "pretty-print-format-impl.h"
+#include "tree-emit-json.h"
+#include "tree-emit-json.h"
 
 /* If non-NULL, return one past-the-end of the matching SUBPART of
    the WHOLE string.  */
@@ -148,6 +150,7 @@  static const kv_pair<dump_flags_t> dump_options[] =
   {"missed", MSG_MISSED_OPTIMIZATION},
   {"note", MSG_NOTE},
   {"optall", MSG_ALL_KINDS},
+  {"json", TDF_JSON},
   {"all", dump_flags_t (TDF_ALL_VALUES
 			& ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_GRAPH
 			    | TDF_STMTADDR | TDF_RHS_ONLY | TDF_NOUID
diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h
index 877d444ce00..a116df5096f 100644
--- a/gcc/dumpfile.h
+++ b/gcc/dumpfile.h
@@ -202,6 +202,9 @@  enum dump_flag : uint32_t
 
   /* For error.  */
   TDF_ERROR = ((uint32_t)1 << 30),
+
+  /* Tree JSON dumping */
+  TDF_JSON = ((uint32_t)1 << 31),
 };
 
 /* Dump flags type.  */
@@ -652,6 +655,9 @@  extern bool enable_rtl_dump_file (void);
 /* In tree-dump.cc  */
 extern void dump_node (const_tree, dump_flags_t, FILE *);
 
+/* In tree-emit-json.cc */
+extern void dump_node_json(const_tree, dump_flags_t, FILE *);
+
 /* In cfghooks.cc  */
 extern void dump_bb (FILE *, basic_block, int, dump_flags_t);
 
diff --git a/gcc/tree-emit-json.cc b/gcc/tree-emit-json.cc
new file mode 100644
index 00000000000..e6de2029265
--- /dev/null
+++ b/gcc/tree-emit-json.cc
@@ -0,0 +1,3180 @@ 
+/* Dumping functionality for GENERIC Trees as JSON. Both for
+   the dump -fdump-tree-original-json and a new debug
+   function.
+   Copyright (C) 2024 Thor Preimesberger <tcpreimesberger@gmail.com>
+   Adapted from tree-pretty-print.cc, tree-dump.cc, and
+   print-tree.cc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#define INCLUDE_STRING
+#define INCLUDE_MEMORY
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tree-pretty-print.h"
+#include "tree-emit-json.h"
+#include "langhooks.h"
+#include "tree-iterator.h"
+#include "dumpfile.h"
+#include "json.h"
+#include "tm.h"
+#include "wide-int-print.h"
+#include "real.h" //for real printing
+#include "poly-int.h"
+#include "gomp-constants.h"
+#include "internal-fn.h"
+#include "cgraph.h"
+#include "predict.h"
+#include "fold-const.h"
+#include "vec.h"
+
+static unsigned int queue (dump_info_p, const_tree);
+static void dequeue_and_dump (dump_info_p);
+static json::array* function_decl_emit_json (tree);
+static void identifier_node_add_json (tree, json::object*);
+static void decl_node_add_json (tree, json::object*);
+static void function_name_add_json (tree, json::object*);
+static void omp_iterator_add_json (tree, json::object*);
+static void omp_clause_add_json(tree, json::object*);
+static void omp_atomic_memory_order_add_json (json::object*,
+                                              enum omp_memory_order);
+static json::object* omp_atomic_memory_order_emit_json(omp_memory_order mo);
+static json::object* omp_clause_emit_json (tree);
+static json::array* loc_emit_json(expanded_location);
+
+/* Add T to the end of the queue of nodes to dump.  Returns the index
+   assigned to T.  */
+
+static unsigned int
+queue (dump_info_p di, const_tree t)
+{
+  dump_queue_p dq;
+  dump_node_info_p dni;
+  unsigned int index;
+
+  /* Assign the next available index to T.  */
+  index = ++di->index;
+
+  /* Obtain a new queue node.  */
+  if (di->free_list)
+    {
+      dq = di->free_list;
+      di->free_list = dq->next;
+    }
+  else
+    dq = XNEW (struct dump_queue);
+
+  /* Create a new entry in the splay-tree.  */
+  dni = XNEW (struct dump_node_info);
+  dni->index = index;
+  dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
+				(splay_tree_value) dni);
+
+  /* Add it to the end of the queue.  */
+  dq->next = 0;
+  if (!di->queue_end)
+    di->queue = dq;
+  else
+    di->queue_end->next = dq;
+  di->queue_end = dq;
+
+  /* Return the index.  */
+  return index;
+}
+
+void
+address_add_json (const void* t, json::object* dummy, char* address_buffer)
+{
+  sprintf(address_buffer, HOST_PTR_PRINTF, t);
+  dummy->set_string("addr", address_buffer);
+}
+
+/* Return args of a function declaration */
+
+json::array*
+function_decl_emit_json (tree t)
+{
+  bool wrote_arg = false;
+  tree arg;
+  json::array* arg_holder;
+  json::object* arg_json;
+
+  arg_json = new json::object ();
+  arg_holder = new json::array ();
+
+  arg = TYPE_ARG_TYPES (t);
+
+  while (arg && arg != void_list_node && arg != error_mark_node)
+    {
+      wrote_arg = true;
+      arg_json = node_emit_json(TREE_VALUE (arg));
+      arg_holder->append(arg_json);
+      arg = TREE_CHAIN (arg);
+    }
+
+  if (arg == void_list_node && !wrote_arg)
+{
+      arg_json->set_bool("void_list_node", true);
+      arg_holder->append(arg_json);
+    }
+
+  return arg_holder;
+}
+
+/* Adds Identifier information to JSON object */
+
+void
+identifier_node_add_json (tree t, json::object* dummy)
+  {
+    const char* buff = IDENTIFIER_POINTER (t);
+    dummy->set_string("id_to_locale", identifier_to_locale(buff));
+    buff = IDENTIFIER_POINTER (t);
+    dummy->set_string("id_point", buff);
+  }
+
+void
+decl_node_add_json (tree t, json::object* dummy)
+{
+  tree name = DECL_NAME (t);
+    
+  if (name)
+      {
+        if (HAS_DECL_ASSEMBLER_NAME_P(t)
+            && DECL_ASSEMBLER_NAME_SET_P(t))
+          identifier_node_add_json(DECL_ASSEMBLER_NAME_RAW(t), dummy);
+        else if (DECL_NAMELESS(t)
+                 && DECL_IGNORED_P(t))
+          name = NULL_TREE;
+        else 
+          identifier_node_add_json(name, dummy);
+      }
+    if (name == NULL_TREE)
+      {
+        if (TREE_CODE (t) == LABEL_DECL && LABEL_DECL_UID (t) != -1)
+          {
+            dummy->set_integer("Label_UID", LABEL_DECL_UID(t));
+          }
+        else if (TREE_CODE (t) == DEBUG_EXPR_DECL)
+          {
+            dummy->set_integer("Debug_UID", DEBUG_TEMP_UID (t));
+          }
+        else 
+          {
+            const char* c = TREE_CODE (t) == CONST_DECL ? "Const_UID"
+                                                        : "Decl_UID";
+            dummy->set_integer(c, DECL_UID(t));
+          }
+      }
+    if (DECL_PT_UID (t) != DECL_UID (t))
+      {
+        dummy->set_integer("ptDecl", DECL_PT_UID(t));
+      }
+}
+
+/* Function call */
+
+void
+function_name_add_json (tree t, json::object* dummy)
+{
+  if (CONVERT_EXPR_P (t))
+    t = TREE_OPERAND (t, 0);
+  if (DECL_NAME (t))
+    {
+      dummy->set_string("decl_name", lang_hooks.decl_printable_name (t, 1));
+      dummy->set_integer("uid", DECL_UID(t));
+    }
+  else
+    decl_node_add_json(t, dummy);
+}
+
+/* Adds the name of a call. Enter iff t is CALL_EXPR_FN */
+
+void
+call_name_add_json (tree t, json::object* dummy)
+{
+  tree op0 = t;
+
+  if (TREE_CODE (op0) == NON_LVALUE_EXPR)
+    op0 = TREE_OPERAND (op0, 0);
+  again:
+    switch (TREE_CODE (op0))
+      {
+      case VAR_DECL:
+      case PARM_DECL:
+      case FUNCTION_DECL:
+        function_name_add_json (op0, dummy);
+        break;
+  
+      case ADDR_EXPR:
+      case INDIRECT_REF:
+      CASE_CONVERT:
+        op0 = TREE_OPERAND (op0, 0);
+        goto again;
+  
+      case COND_EXPR:
+        {
+          json::object *_x;
+          _x = new json::object ();
+          _x->set("if", node_emit_json(TREE_OPERAND(op0, 0)));
+          _x->set("then", node_emit_json(TREE_OPERAND(op0, 1)));
+          _x->set("else", node_emit_json(TREE_OPERAND(op0, 2)));
+          dummy->set("call_name", _x);
+        }
+        break;
+  
+      case ARRAY_REF:
+        if (VAR_P (TREE_OPERAND (op0, 0)))
+  	function_name_add_json (TREE_OPERAND (op0, 0), dummy);
+        else
+  	dummy->set("call_name", node_emit_json (op0));
+        break;
+  
+      case MEM_REF:
+        if (integer_zerop (TREE_OPERAND (op0, 1)))
+  	{
+  	  op0 = TREE_OPERAND (op0, 0);
+  	  goto again;
+  	}
+        /* Fallthrough  */
+      case COMPONENT_REF:
+      case SSA_NAME:
+      case OBJ_TYPE_REF:
+        dummy->set("call_name", node_emit_json (op0));
+        break;
+      default:
+        break;
+    }
+}
+
+/* OMP helper. */
+void
+omp_iterator_add_json(tree iter, json::object* dummy)
+{
+  json::array* iter_holder;
+  iter_holder = new json::array ();
+
+  for (tree it = iter; it; it = TREE_CHAIN (it))
+    {
+      for (int i = 0; i < 4; i++)
+        {
+          if (TREE_VEC_ELT (it, 0) != NULL_TREE)
+            iter_holder->append (node_emit_json (TREE_VEC_ELT (it, 0)));
+        }
+    }
+  dummy->set("omp_iter", iter_holder);
+}
+/* Omp helper. */
+void
+omp_clause_add_json(tree clause, json::object* dummy)
+{
+  char buffer[100] = {'\0'};
+  const char* name;
+  const char* modifier = NULL;
+  switch (OMP_CLAUSE_CODE (clause))
+    {
+    case OMP_CLAUSE_PRIVATE:
+      name = "private";
+      goto print_remap;
+    case OMP_CLAUSE_SHARED:
+      name = "shared";
+      goto print_remap;
+    case OMP_CLAUSE_FIRSTPRIVATE:
+      name = "firstprivate";
+      goto print_remap;
+    case OMP_CLAUSE_LASTPRIVATE:
+      name = "lastprivate";
+      if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (clause))
+	modifier = "conditional:";
+      goto print_remap;
+    case OMP_CLAUSE_COPYIN:
+      name = "copyin";
+      goto print_remap;
+    case OMP_CLAUSE_COPYPRIVATE:
+      name = "copyprivate";
+      goto print_remap;
+    case OMP_CLAUSE_UNIFORM:
+      name = "uniform";
+      goto print_remap;
+    case OMP_CLAUSE_USE_DEVICE_PTR:
+      name = "use_device_ptr";
+      if (OMP_CLAUSE_USE_DEVICE_PTR_IF_PRESENT (clause))
+	modifier = "if_present:";
+      goto print_remap;
+    case OMP_CLAUSE_USE_DEVICE_ADDR:
+      name = "use_device_addr";
+      goto print_remap;
+    case OMP_CLAUSE_HAS_DEVICE_ADDR:
+      name = "has_device_addr";
+      goto print_remap;
+    case OMP_CLAUSE_IS_DEVICE_PTR:
+      name = "is_device_ptr";
+      goto print_remap;
+    case OMP_CLAUSE_INCLUSIVE:
+      name = "inclusive";
+      goto print_remap;
+    case OMP_CLAUSE_EXCLUSIVE:
+      name = "exclusive";
+      goto print_remap;
+    case OMP_CLAUSE__LOOPTEMP_:
+      name = "_looptemp_";
+      goto print_remap;
+    case OMP_CLAUSE__REDUCTEMP_:
+      name = "_reductemp_";
+      goto print_remap;
+    case OMP_CLAUSE__CONDTEMP_:
+      name = "_condtemp_";
+      goto print_remap;
+    case OMP_CLAUSE__SCANTEMP_:
+      name = "_scantemp_";
+      goto print_remap;
+    case OMP_CLAUSE_ENTER:
+      if (OMP_CLAUSE_ENTER_TO (clause))
+	name = "to";
+      else
+	name = "enter";
+      goto print_remap;
+    case OMP_CLAUSE_LINK:
+      name = "link";
+      goto print_remap;
+    case OMP_CLAUSE_NONTEMPORAL:
+      name = "nontemporal";
+      goto print_remap;
+  print_remap: //FIX LATER
+      strcpy(buffer, name);
+      if (modifier)
+        strcat(buffer, modifier);
+      dummy->set (buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
+      break;
+
+    case OMP_CLAUSE_TASK_REDUCTION:
+    case OMP_CLAUSE_IN_REDUCTION:
+    case OMP_CLAUSE_REDUCTION:
+      break;
+
+    case OMP_CLAUSE_IF:
+      strcpy(buffer, "omp_clause_if");
+      switch (OMP_CLAUSE_IF_MODIFIER (clause))
+        {
+        case ERROR_MARK: break;
+        case VOID_CST: strcat(buffer, "_cancel"); break;
+        case OMP_PARALLEL: strcat(buffer, "_parallel"); break;
+        case OMP_SIMD: strcat(buffer, "_simd"); break; 
+        case OMP_TASK: strcat(buffer, "_task"); break;
+        case OMP_TASKLOOP: strcat(buffer, "_taskloop"); break;
+        case OMP_TARGET_DATA: strcat(buffer, "_target_data"); break;
+        case OMP_TARGET: strcat(buffer, "_target"); break;
+        case OMP_TARGET_UPDATE: strcat(buffer, "_target_update"); break;
+        case OMP_TARGET_ENTER_DATA: strcat(buffer, "_target_enter_data");
+	   break;
+        case OMP_TARGET_EXIT_DATA: strcat(buffer, "_target_exit_data"); break;
+        default: gcc_unreachable ();
+        }
+      dummy->set(buffer, node_emit_json (OMP_CLAUSE_IF_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_SELF:
+      dummy->set("omp_self", node_emit_json (OMP_CLAUSE_SELF_EXPR(clause)));
+      break;
+
+    case OMP_CLAUSE_NUM_THREADS:
+      dummy->set("omp_num_threads",
+                 node_emit_json (OMP_CLAUSE_NUM_THREADS_EXPR(clause)));
+      break;
+
+    case OMP_CLAUSE_NOWAIT:
+      break;
+
+    case OMP_CLAUSE_ORDERED:
+      dummy->set("omp_ordered",
+                 node_emit_json (OMP_CLAUSE_ORDERED_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_DEFAULT:
+      strcpy(buffer, "omp_default");
+      switch (OMP_CLAUSE_DEFAULT_KIND (clause))
+        {
+	case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
+	  break;
+	case OMP_CLAUSE_DEFAULT_SHARED:
+	  strcat (buffer, "_shared");
+	  break;
+	case OMP_CLAUSE_DEFAULT_NONE:
+	  strcat (buffer, "_none");
+	  break;
+	case OMP_CLAUSE_DEFAULT_PRIVATE:
+	  strcat (buffer, "_private");
+	  break;
+	case OMP_CLAUSE_DEFAULT_FIRSTPRIVATE:
+	  strcat (buffer, "_firstprivate");
+	  break;
+	case OMP_CLAUSE_DEFAULT_PRESENT:
+	  strcat (buffer, "_present");
+	  break;
+	default:
+	  gcc_unreachable ();
+        }
+      dummy->set_bool(buffer, true);
+      break;
+
+    case OMP_CLAUSE_SCHEDULE:
+      strcpy (buffer, "schedule");
+      if (OMP_CLAUSE_SCHEDULE_KIND (clause)
+	  & (OMP_CLAUSE_SCHEDULE_MONOTONIC
+	     | OMP_CLAUSE_SCHEDULE_NONMONOTONIC))
+	{
+	  if (OMP_CLAUSE_SCHEDULE_KIND (clause)
+	      & OMP_CLAUSE_SCHEDULE_MONOTONIC)
+	    strcat (buffer, "_monotonic");
+	  else
+	    strcat (buffer, "_nonmonotonic");
+	}
+      if (OMP_CLAUSE_SCHEDULE_SIMD (clause))
+	strcat (buffer, "_simd");
+
+      switch (OMP_CLAUSE_SCHEDULE_KIND (clause) & OMP_CLAUSE_SCHEDULE_MASK)
+	{
+	case OMP_CLAUSE_SCHEDULE_STATIC:
+	  strcat (buffer, "_static");
+	  break;
+	case OMP_CLAUSE_SCHEDULE_DYNAMIC:
+	  strcat (buffer, "_dynamic");
+	  break;
+	case OMP_CLAUSE_SCHEDULE_GUIDED:
+	  strcat (buffer, "_guided");
+	  break;
+	case OMP_CLAUSE_SCHEDULE_RUNTIME:
+	  strcat (buffer, "_runtime");
+	  break;
+	case OMP_CLAUSE_SCHEDULE_AUTO:
+	  strcat (buffer, "_auto");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      dummy->set(buffer,
+                 node_emit_json(OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(clause)));
+      break;
+
+    case OMP_CLAUSE_UNTIED:
+      dummy->set_bool("omp_clause_untied", true);
+      break;
+
+    case OMP_CLAUSE_COLLAPSE:
+      dummy->set("omp_collapse_collapse",
+                 node_emit_json (OMP_CLAUSE_COLLAPSE_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_FINAL:
+      dummy->set("omp_final", 
+		  node_emit_json (OMP_CLAUSE_FINAL_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_MERGEABLE:
+      dummy->set_bool("omp_clause_mergeable", true);
+      break;
+
+    case OMP_CLAUSE_LINEAR:
+      strcpy (buffer, "omp_linear");
+      if (OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause))
+	switch (OMP_CLAUSE_LINEAR_KIND (clause))
+	  {
+	  case OMP_CLAUSE_LINEAR_DEFAULT:
+	    break;
+	  case OMP_CLAUSE_LINEAR_REF:
+	    strcat (buffer, "_ref");
+	    break;
+	  case OMP_CLAUSE_LINEAR_VAL:
+	    strcat (buffer, "_val");
+	    break;
+	  case OMP_CLAUSE_LINEAR_UVAL:
+	    strcat (buffer, "_uval");
+	    break;
+	  default:
+	    gcc_unreachable ();
+	  }
+      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
+      if (!OMP_CLAUSE_LINEAR_OLD_LINEAR_MODIFIER (clause)
+	  && OMP_CLAUSE_LINEAR_KIND (clause) != OMP_CLAUSE_LINEAR_DEFAULT)
+	switch (OMP_CLAUSE_LINEAR_KIND (clause))
+	  {
+	    case OMP_CLAUSE_LINEAR_REF:
+	      strcpy (buffer, "_ref,step");
+	      break;
+	    case OMP_CLAUSE_LINEAR_VAL:
+	      strcpy (buffer, "_val,step");
+	      break;
+	    case OMP_CLAUSE_LINEAR_UVAL:
+	      strcpy (buffer, "_uval,step");
+	      break;
+	    default:
+	      gcc_unreachable ();
+	  }
+      dummy->set(buffer, node_emit_json (OMP_CLAUSE_LINEAR_STEP (clause)));
+      break;
+
+    case OMP_CLAUSE_ALIGNED:
+      dummy->set("omp_aligned", node_emit_json (OMP_CLAUSE_DECL(clause)));
+      if (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause))
+	{
+          dummy->set("omp_aligned_alignment",
+                     node_emit_json (OMP_CLAUSE_ALIGNED_ALIGNMENT (clause)));
+	}
+      break;
+
+    case OMP_CLAUSE_ALLOCATE:
+      if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause))
+          dummy->set("omp_allocator",
+                     node_emit_json (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause)));
+      if (OMP_CLAUSE_ALLOCATE_ALIGN (clause))
+          dummy->set("omp_allocate_align",
+                     node_emit_json (OMP_CLAUSE_ALLOCATE_ALIGN (clause)));
+      dummy->set("omp_allocate",
+                 node_emit_json (OMP_CLAUSE_DECL (clause)));
+      break;
+
+    case OMP_CLAUSE_AFFINITY:
+      {
+	tree t = OMP_CLAUSE_DECL (clause);
+	if (TREE_CODE (t) == TREE_LIST
+	    && TREE_PURPOSE (t)
+	    && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
+	  {
+            omp_iterator_add_json(TREE_PURPOSE (t), dummy);
+	    t = TREE_VALUE (t);
+	  }
+        dummy->set("omp_affinity", node_emit_json(t));
+      }
+      break;
+
+    case OMP_CLAUSE_DEPEND:
+      strcpy (buffer, "omp_depend");
+      switch (OMP_CLAUSE_DEPEND_KIND (clause))
+	{
+	case OMP_CLAUSE_DEPEND_DEPOBJ:
+	  strcat (buffer, "_depobj");
+	  break;
+	case OMP_CLAUSE_DEPEND_IN:
+	  strcat (buffer, "_in");
+	  break;
+	case OMP_CLAUSE_DEPEND_OUT:
+	  strcat (buffer, "_out");
+	  break;
+	case OMP_CLAUSE_DEPEND_INOUT:
+	  strcat (buffer, "_inout");
+	  break;
+	case OMP_CLAUSE_DEPEND_MUTEXINOUTSET:
+	  strcat (buffer, "_mutexinoutset");
+	  break;
+	case OMP_CLAUSE_DEPEND_INOUTSET:
+	  strcat (buffer, "_inoutset");
+	  break;
+	case OMP_CLAUSE_DEPEND_LAST:
+	  strcat (buffer, "__internal__");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      {
+	tree t = OMP_CLAUSE_DECL (clause);
+	if (TREE_CODE (t) == TREE_LIST
+	    && TREE_PURPOSE (t)
+	    && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
+	  {
+	    omp_iterator_add_json(TREE_PURPOSE (t), dummy);
+	    t = TREE_VALUE (t);
+	  }
+	if (t == null_pointer_node)
+	  dummy->set_bool("omp_all_memory", true);
+	else
+          dummy->set(buffer, node_emit_json(t));
+      }
+      break;
+
+    case OMP_CLAUSE_DOACROSS:
+      strcpy (buffer, OMP_CLAUSE_DOACROSS_DEPEND (clause)
+		     ? "omp_depend" : "omp_doacross");
+      switch (OMP_CLAUSE_DOACROSS_KIND (clause))
+	{
+	case OMP_CLAUSE_DOACROSS_SOURCE:
+	  if (OMP_CLAUSE_DOACROSS_DEPEND (clause))
+	    strcat (buffer, "_source");
+	  else
+	    strcat (buffer, "_source:");
+          dummy->set_bool(buffer, true);
+	  break;
+        
+	case OMP_CLAUSE_DOACROSS_SINK:
+          json::array* iter_holder;
+          iter_holder = new json::array ();
+	  strcat (buffer, "_sink:");
+	  if (OMP_CLAUSE_DECL (clause) == NULL_TREE)
+	    {
+	      strcat (buffer, "_omp_cur_iteration-1");
+              dummy->set_bool(buffer, true);
+	      break;
+	    }
+	  for (tree t = OMP_CLAUSE_DECL (clause); t; t = TREE_CHAIN (t))
+	    if (TREE_CODE (t) == TREE_LIST)
+	      {
+		iter_holder->append(node_emit_json(TREE_VALUE (t)));
+		if (TREE_PURPOSE (t) != integer_zero_node)
+		  {
+                    json::object *_x;
+                    _x = new json::object ();
+		    if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (t))
+                      _x->set("-", node_emit_json(TREE_PURPOSE (t)));
+		    else
+                      _x->set("+", node_emit_json(TREE_PURPOSE (t)));
+                    iter_holder->append(_x);
+		  }
+	      }
+	    else
+	      gcc_unreachable ();
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      break;
+    case OMP_CLAUSE_MAP:
+      strcat (buffer, "omp_map");
+      if (OMP_CLAUSE_MAP_READONLY (clause))
+	strcat (buffer, "_readonly,");
+      switch (OMP_CLAUSE_MAP_KIND (clause))
+	{
+	case GOMP_MAP_ALLOC:
+	case GOMP_MAP_POINTER:
+	case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
+	  strcat (buffer, "_alloc");
+	  break;
+	case GOMP_MAP_IF_PRESENT:
+	  strcat (buffer, "_no_alloc");
+	  break;
+	case GOMP_MAP_TO:
+	case GOMP_MAP_TO_PSET:
+	  strcat (buffer, "_to");
+	  break;
+	case GOMP_MAP_FROM:
+	  strcat (buffer, "_from");
+	  break;
+	case GOMP_MAP_TOFROM:
+	  strcat (buffer, "_tofrom");
+	  break;
+	case GOMP_MAP_FORCE_ALLOC:
+	  strcat (buffer, "_force_alloc");
+	  break;
+	case GOMP_MAP_FORCE_TO:
+	  strcat (buffer, "_force_to");
+	  break;
+	case GOMP_MAP_FORCE_FROM:
+	  strcat (buffer, "_force_from");
+	  break;
+	case GOMP_MAP_FORCE_TOFROM:
+	  strcat (buffer, "_force_tofrom");
+	  break;
+	case GOMP_MAP_FORCE_PRESENT:
+	  strcat (buffer, "_force_present");
+	  break;
+	case GOMP_MAP_DELETE:
+	  strcat (buffer, "_delete");
+	  break;
+	case GOMP_MAP_FORCE_DEVICEPTR:
+	  strcat (buffer, "_force_deviceptr");
+	  break;
+	case GOMP_MAP_ALWAYS_TO:
+	  strcat (buffer, "_always,to");
+	  break;
+	case GOMP_MAP_ALWAYS_FROM:
+	  strcat (buffer, "_always,from");
+	  break;
+	case GOMP_MAP_ALWAYS_TOFROM:
+	  strcat (buffer, "_always,tofrom");
+	  break;
+	case GOMP_MAP_RELEASE:
+	  strcat (buffer, "_release");
+	  break;
+	case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	  strcat (buffer, "_firstprivate");
+	  break;
+	case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
+	  strcat (buffer, "_firstprivate ref");
+	  break;
+	case GOMP_MAP_STRUCT:
+	  strcat (buffer, "_struct");
+	  break;
+	case GOMP_MAP_STRUCT_UNORD:
+	  strcat (buffer, "_struct_unord");
+	  break;
+	case GOMP_MAP_ALWAYS_POINTER:
+	  strcat (buffer, "_always_pointer");
+	  break;
+	case GOMP_MAP_DEVICE_RESIDENT:
+	  strcat (buffer, "_device_resident");
+	  break;
+	case GOMP_MAP_LINK:
+	  strcat (buffer, "_link");
+	  break;
+	case GOMP_MAP_ATTACH:
+	  strcat (buffer, "_attach");
+	  break;
+	case GOMP_MAP_DETACH:
+	  strcat (buffer, "_detach");
+	  break;
+	case GOMP_MAP_FORCE_DETACH:
+	  strcat (buffer, "_force_detach");
+	  break;
+	case GOMP_MAP_ATTACH_DETACH:
+	  strcat (buffer, "_attach_detach");
+	  break;
+	case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
+	  strcat (buffer, "_attach_zero_length_array_section");
+	  break;
+	case GOMP_MAP_PRESENT_ALLOC:
+	  strcat (buffer, "_present,alloc");
+	  break;
+	case GOMP_MAP_PRESENT_TO:
+	  strcat (buffer, "_present,to");
+	  break;
+	case GOMP_MAP_PRESENT_FROM:
+	  strcat (buffer, "_present,from");
+	  break;
+	case GOMP_MAP_PRESENT_TOFROM:
+	  strcat (buffer, "_present,tofrom");
+	  break;
+	case GOMP_MAP_ALWAYS_PRESENT_TO:
+	  strcat (buffer, "_always,present,to");
+	  break;
+	case GOMP_MAP_ALWAYS_PRESENT_FROM:
+	  strcat (buffer, "_always,present,from");
+	  break;
+	case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+	  strcat (buffer, "_always,present,tofrom");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      dummy->set (buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
+     print_clause_size:
+      if (OMP_CLAUSE_SIZE (clause))
+	{
+	  switch (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
+		  ? OMP_CLAUSE_MAP_KIND (clause) : GOMP_MAP_TO)
+	    {
+	    case GOMP_MAP_POINTER:
+	    case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
+	    case GOMP_MAP_ALWAYS_POINTER:
+	      strcpy (buffer, "pointer assign, bias");
+	      break;
+	    case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
+	      strcpy (buffer,
+		      "pointer assign, zero-length array section, bias");
+	      break;
+	    case GOMP_MAP_TO_PSET:
+	      strcpy (buffer, "pointer set, len");
+	      break;
+	    case GOMP_MAP_ATTACH:
+	    case GOMP_MAP_DETACH:
+	    case GOMP_MAP_FORCE_DETACH:
+	    case GOMP_MAP_ATTACH_DETACH:
+	    case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
+	      strcpy (buffer, "bias");
+	      break;
+	    case GOMP_MAP_RELEASE:
+	    case GOMP_MAP_DELETE:
+	      if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
+		  && OMP_CLAUSE_RELEASE_DESCRIPTOR (clause))
+		{
+		  strcpy (buffer, "pointer set, len");
+		  break;
+		}
+	      /* Fallthrough.  */
+	    default:
+	      strcpy (buffer, "len");
+	      break;
+	    }
+          dummy->set (buffer, node_emit_json (OMP_CLAUSE_SIZE (clause)));
+	}
+      if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
+	  && OMP_CLAUSE_MAP_RUNTIME_IMPLICIT_P (clause))
+        dummy->set_bool("implicit", true);
+      break;
+
+    case OMP_CLAUSE_FROM:
+      strcat (buffer, "omp_from");
+      if (OMP_CLAUSE_MOTION_PRESENT (clause))
+	strcat (buffer, "_present");
+      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
+      goto print_clause_size;
+
+    case OMP_CLAUSE_TO:
+      strcpy (buffer, "omp_to");
+      if (OMP_CLAUSE_MOTION_PRESENT (clause))
+	strcat (buffer, "_present");
+      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
+      goto print_clause_size;
+
+    case OMP_CLAUSE__CACHE_:
+      strcat (buffer, "omp__cache__");
+      if (OMP_CLAUSE__CACHE__READONLY (clause))
+	strcat (buffer, "_readonly");
+      dummy->set(buffer, node_emit_json (OMP_CLAUSE_DECL (clause)));
+      goto print_clause_size;
+
+    case OMP_CLAUSE_NUM_TEAMS:
+      strcat (buffer, "omp_num_teams");
+      if (OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (clause))
+	{
+          dummy->set("omp_num_teams_lower",
+                     node_emit_json (
+		          OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (clause)));
+          strcat (buffer, "_upper");
+	}
+      else
+        dummy->set(buffer,
+                   node_emit_json (OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_THREAD_LIMIT:
+      dummy->set("omp_thread_limit",
+                 node_emit_json (OMP_CLAUSE_THREAD_LIMIT_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_DEVICE:
+      strcpy (buffer, "omp_device(");
+      if (OMP_CLAUSE_DEVICE_ANCESTOR (clause))
+	strcat (buffer, "_ancestor:");
+      dummy->set(buffer,
+                 node_emit_json (OMP_CLAUSE_DEVICE_ID (clause)));
+      break;
+
+    case OMP_CLAUSE_DIST_SCHEDULE:
+      strcat (buffer, "omp_dist_schedule(static)");
+      if (OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause))
+	{
+         dummy->set(buffer,
+                    node_emit_json (
+		         OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (clause)));
+	}
+      else
+        dummy->set_bool(buffer, true);
+      break;
+
+    case OMP_CLAUSE_PROC_BIND:
+      strcpy (buffer, "omp_proc_bind(");
+      switch (OMP_CLAUSE_PROC_BIND_KIND (clause))
+	{
+	case OMP_CLAUSE_PROC_BIND_MASTER:
+	  strcat (buffer, "_master");
+	  break;
+	case OMP_CLAUSE_PROC_BIND_CLOSE:
+	  strcat (buffer, "_close");
+	  break;
+	case OMP_CLAUSE_PROC_BIND_SPREAD:
+	  strcat (buffer, "_spread");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      dummy->set_bool(buffer, true);
+      break;
+
+    case OMP_CLAUSE_DEVICE_TYPE:
+    strcpy (buffer, "omp_device_type");
+      switch (OMP_CLAUSE_DEVICE_TYPE_KIND (clause))
+	{
+	case OMP_CLAUSE_DEVICE_TYPE_HOST:
+	  strcat (buffer, "_host");
+	  break;
+	case OMP_CLAUSE_DEVICE_TYPE_NOHOST:
+	  strcat (buffer, "_nohost");
+	  break;
+	case OMP_CLAUSE_DEVICE_TYPE_ANY:
+	  strcat (buffer, "_any");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      dummy->set_bool(buffer, true);
+      break;
+
+    case OMP_CLAUSE_SAFELEN:
+      dummy->set("omp_safelen",
+                 node_emit_json (OMP_CLAUSE_SAFELEN_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_SIMDLEN:
+      dummy->set("omp_simdlen",
+                 node_emit_json (OMP_CLAUSE_SIMDLEN_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_PRIORITY:
+      dummy->set("omp_priority",
+                 node_emit_json (OMP_CLAUSE_PRIORITY_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_GRAINSIZE:
+      strcpy (buffer, "omp_grainsize");
+      if (OMP_CLAUSE_GRAINSIZE_STRICT (clause))
+        strcat (buffer, "_strict");
+      dummy->set(buffer,
+                 node_emit_json (OMP_CLAUSE_GRAINSIZE_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_NUM_TASKS:
+      strcpy (buffer, "omp_num_tasks");
+      if (OMP_CLAUSE_NUM_TASKS_STRICT (clause))
+	strcat (buffer, "_strict");
+      dummy->set(buffer,
+                 node_emit_json (OMP_CLAUSE_NUM_TASKS_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_HINT:
+      dummy->set("omp_hint",
+                 node_emit_json (OMP_CLAUSE_HINT_EXPR(clause)));
+      break;
+
+    case OMP_CLAUSE_FILTER:
+      dummy->set("omp_filter",
+                 node_emit_json (OMP_CLAUSE_FILTER_EXPR(clause)));
+      break;
+
+    case OMP_CLAUSE_DEFAULTMAP:
+      strcat (buffer, "omp_defaultmap");
+      switch (OMP_CLAUSE_DEFAULTMAP_BEHAVIOR (clause))
+	{
+	case OMP_CLAUSE_DEFAULTMAP_ALLOC:
+	  strcat (buffer, "_alloc");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_TO:
+	  strcat (buffer, "_to");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_FROM:
+	  strcat (buffer, "_from");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_TOFROM:
+	  strcat (buffer, "_tofrom");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE:
+	  strcat (buffer, "_firstprivate");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_NONE:
+	  strcat (buffer, "_none");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_PRESENT:
+	  strcat (buffer, "_present");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_DEFAULT:
+	  strcat (buffer, "_default");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      //Check later if we're happy with this
+      switch (OMP_CLAUSE_DEFAULTMAP_CATEGORY (clause))
+	{
+	case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED:
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALL:
+	  strcat (buffer, ":all");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR:
+	  strcat (buffer, ":scalar");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE:
+	  strcat (buffer, ":aggregate");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALLOCATABLE:
+	  strcat (buffer, ":allocatable");
+	  break;
+	case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER:
+	  strcat (buffer, ":pointer");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      dummy->set_bool(buffer, true);
+      break;
+
+    case OMP_CLAUSE_ORDER:
+      strcpy (buffer, "omp_order_");
+      if (OMP_CLAUSE_ORDER_UNCONSTRAINED (clause))
+	strcat (buffer, "unconstrained:");
+      else if (OMP_CLAUSE_ORDER_REPRODUCIBLE (clause))
+	strcat (buffer, "reproducible:");
+      strcat (buffer, "concurrent)");
+      dummy->set_bool(buffer, true);
+      break;
+
+    case OMP_CLAUSE_BIND:
+      strcpy (buffer, "omp_bind");
+      switch (OMP_CLAUSE_BIND_KIND (clause))
+	{
+	case OMP_CLAUSE_BIND_TEAMS:
+	  strcat (buffer, "_teams");
+	  break;
+	case OMP_CLAUSE_BIND_PARALLEL:
+	  strcat (buffer, "_parallel");
+	  break;
+	case OMP_CLAUSE_BIND_THREAD:
+	  strcat (buffer, "_thread");
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      dummy->set_bool(buffer, true);
+      break;
+
+    case OMP_CLAUSE__SIMDUID_:
+      dummy->set("omp__simduid__", 
+                 node_emit_json(OMP_CLAUSE__SIMDUID__DECL (clause)));
+      break;
+
+    case OMP_CLAUSE__SIMT_:
+      dummy->set_bool("omp__simt__", true);
+      break;
+
+    //In our current implementation, we dump exprs etc even if not NULL.
+    case OMP_CLAUSE_GANG: 
+      dummy->set_bool ("omp_gang", true);
+      if (OMP_CLAUSE_GANG_EXPR (clause) != NULL_TREE)
+          dummy->set("num", node_emit_json (OMP_CLAUSE_GANG_EXPR (clause)));
+      if (OMP_CLAUSE_GANG_STATIC_EXPR (clause) != NULL_TREE)
+	{
+	  strcpy (buffer, "static");
+	  if (OMP_CLAUSE_GANG_STATIC_EXPR (clause)
+	      == integer_minus_one_node)
+	    strcat (buffer, "*"); 
+          dummy->set(buffer,
+                     node_emit_json (OMP_CLAUSE_GANG_STATIC_EXPR (clause)));
+	}
+      break;
+
+    case OMP_CLAUSE_ASYNC:
+      dummy->set("omp_async", 
+                 node_emit_json (OMP_CLAUSE_ASYNC_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_AUTO:
+    case OMP_CLAUSE_SEQ:
+      strcpy (buffer, omp_clause_code_name[OMP_CLAUSE_CODE (clause)]);
+      dummy->set_bool(buffer, true);
+      break;
+
+    case OMP_CLAUSE_WAIT:
+      dummy->set("omp_wait",
+                 node_emit_json (OMP_CLAUSE_WAIT_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_WORKER:
+      dummy->set("omp_worker",
+                 node_emit_json (OMP_CLAUSE_WORKER_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_VECTOR:
+      dummy->set("omp_vector",
+                 node_emit_json (OMP_CLAUSE_VECTOR_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_NUM_GANGS:
+      dummy->set("omp_num_gangs",
+                 node_emit_json (OMP_CLAUSE_NUM_GANGS_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_NUM_WORKERS:
+      dummy->set("omp_num_workers",
+                 node_emit_json (OMP_CLAUSE_NUM_WORKERS_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_VECTOR_LENGTH:
+      dummy->set("omp_vector_length",
+                 node_emit_json (OMP_CLAUSE_VECTOR_LENGTH_EXPR (clause)));
+      break;
+
+    case OMP_CLAUSE_INBRANCH:
+      dummy->set_bool ("inbranch", true);
+      break;
+    case OMP_CLAUSE_NOTINBRANCH:
+      dummy->set_bool ("notinbranch", true);
+      break;
+    case OMP_CLAUSE_FOR:
+      dummy->set_bool ("for", true);
+      break;
+    case OMP_CLAUSE_PARALLEL:
+      dummy->set_bool ("parallel", true);
+      break;
+    case OMP_CLAUSE_SECTIONS:
+      dummy->set_bool ("sections", true);
+      break;
+    case OMP_CLAUSE_TASKGROUP:
+      dummy->set_bool ("taskgroup", true);
+      break;
+    case OMP_CLAUSE_NOGROUP:
+      dummy->set_bool ("nogroup", true);
+      break;
+    case OMP_CLAUSE_THREADS:
+      dummy->set_bool ("threads", true);
+      break;
+    case OMP_CLAUSE_SIMD:
+      dummy->set_bool ("simd", true);
+      break;
+    case OMP_CLAUSE_INDEPENDENT:
+      dummy->set_bool ("independent", true);
+      break;
+    case OMP_CLAUSE_TILE:
+      dummy->set ("omp_tile", node_emit_json (OMP_CLAUSE_TILE_LIST (clause)));
+      break;
+    case OMP_CLAUSE_PARTIAL:
+      dummy->set ("omp_partial",
+                  node_emit_json (OMP_CLAUSE_PARTIAL_EXPR (clause)));
+      break;
+    case OMP_CLAUSE_FULL:
+      dummy->set_bool("full", true);
+      break;
+    case OMP_CLAUSE_SIZES:
+      dummy->set("omp_sizes", node_emit_json (
+	          OMP_CLAUSE_SIZES_LIST (clause)));
+      break;
+    case OMP_CLAUSE_IF_PRESENT:
+      dummy->set_bool("if_present", true);
+      break;
+    case OMP_CLAUSE_FINALIZE:
+      dummy->set_bool("finalize", true);
+      break;
+    case OMP_CLAUSE_NOHOST:
+      dummy->set_bool("nohost", true);
+      break;
+    case OMP_CLAUSE_DETACH:
+      dummy->set("omp_detach", node_emit_json (OMP_CLAUSE_DECL (clause)));
+      break;
+    default:
+      gcc_unreachable();
+    }
+}
+
+void
+omp_atomic_memory_order_add_json (json::object* dummy, 
+                                  enum omp_memory_order mo)
+{
+  switch (mo & OMP_MEMORY_ORDER_MASK)
+    {
+    case OMP_MEMORY_ORDER_RELAXED:
+      dummy->set_string ("omp_memory_order", "relaxed");
+      break;
+    case OMP_MEMORY_ORDER_SEQ_CST:
+      dummy->set_string ("omp_memory_order", "seq_cst");
+      break;
+    case OMP_MEMORY_ORDER_ACQ_REL:
+      dummy->set_string ("omp_memory_order", "acq_rel");
+      break;
+    case OMP_MEMORY_ORDER_ACQUIRE:
+      dummy->set_string ("omp_memory_order", "acquire");
+      break;
+    case OMP_MEMORY_ORDER_RELEASE:
+      dummy->set_string ("omp_memory_order", "release");
+      break;
+    case OMP_MEMORY_ORDER_UNSPECIFIED:
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  switch (mo & OMP_FAIL_MEMORY_ORDER_MASK)
+    {
+    case OMP_FAIL_MEMORY_ORDER_RELAXED:
+      dummy->set_string ("omp_memory_order", "fail(relaxed)");
+      break;
+    case OMP_FAIL_MEMORY_ORDER_SEQ_CST:
+      dummy->set_string ("omp_memory_order", "fail(seq_cst)");
+      break;
+    case OMP_FAIL_MEMORY_ORDER_ACQUIRE:
+      dummy->set_string ("omp_memory_order", "fail(acquire)");
+      break;
+    case OMP_FAIL_MEMORY_ORDER_UNSPECIFIED:
+      dummy->set_string ("omp_memory_order", "fail(unspecified)");
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+json::object*
+omp_atomic_memory_order_emit_json(omp_memory_order mo)
+{
+  json::object* _x;
+  _x = new json::object ();
+  omp_atomic_memory_order_add_json(_x, mo);
+  return _x;
+}
+
+json::object*
+omp_clause_emit_json(tree t)
+{
+  json::object* _x;
+  _x = new json::object ();
+  omp_clause_add_json(t, _x);
+  return _x;
+}
+
+json::array*
+loc_emit_json (expanded_location xloc)
+{
+  json::array *loc_holder;
+  json::object *loc_info;
+  loc_info = new json::object ();
+  loc_info->set_string("file", xloc.file);
+  loc_info->set_integer("line", xloc.line);
+  loc_info->set_integer("column", xloc.column);
+  loc_holder = new json::array ();
+  loc_holder->append(loc_info);
+  return loc_holder;
+}
+
+/* Here we emit JSON data for a GENERIC node and children. 
+ * c.f. dump_generic_node and print-tree's debug_tree().   */
+
+json::object* 
+node_emit_json(tree t)
+{
+  tree op0, op1, type;
+  enum tree_code code;
+  expanded_location xloc;
+  json::object *dummy;
+  json::array* holder;
+  char address_buffer[sizeof(&t)] = {"\0"};
+
+  dummy = new json::object ();
+  holder = new json::array ();
+
+  code = TREE_CODE (t);
+
+  address_add_json(t, dummy, address_buffer);
+
+  if (TREE_CODE_CLASS (code) == tcc_declaration
+      && code != TRANSLATION_UNIT_DECL)
+    {
+    xloc = expand_location (DECL_SOURCE_LOCATION (t));
+    dummy->set("decl_loc", loc_emit_json(xloc));
+    }
+  if (EXPR_HAS_LOCATION(t))
+    {
+      xloc = expand_location (EXPR_LOCATION (t));
+      dummy->set("expr_loc", loc_emit_json(xloc));
+    }
+  if (EXPR_HAS_RANGE (t))
+    {
+      source_range r = EXPR_LOCATION_RANGE (t);
+      if (r.m_start)
+      {
+        xloc = expand_location (r.m_start);
+        dummy->set("start_loc", loc_emit_json(xloc));
+      } else {
+        dummy->set_string("start_loc", "unknown");
+      }
+      if (r.m_finish)
+      {
+        xloc = expand_location (r.m_finish);
+        dummy->set("finish_loc", loc_emit_json(xloc));
+      } else {
+        dummy->set_string("finish_loc", "unknown");
+      }
+    }
+  dummy->set_string("tree code", get_tree_code_name(TREE_CODE (t)));
+  //Flag handling
+  if (TREE_ADDRESSABLE (t))
+    dummy->set_bool ("addressable", true);
+  if (TREE_THIS_VOLATILE (t))
+    dummy->set_bool ("volatile", true);
+  if (TREE_ASM_WRITTEN (t))
+    dummy->set_bool ("asm_written", true);
+  if (TREE_USED (t))
+    dummy->set_bool ("used", true);
+  if (TREE_NOTHROW (t))
+    dummy->set_bool ("nothrow", true);
+  if (TREE_PUBLIC (t))
+    dummy->set_bool ("public", true);
+  if (TREE_PRIVATE (t))
+    dummy->set_bool ("private", true);
+  if (TREE_PROTECTED (t))
+    dummy->set_bool ("protected", true);
+  if (TREE_STATIC (t))
+    dummy->set_bool (code == CALL_EXPR ? " must-tail-call"
+                                       : " static", true);
+  if (TREE_DEPRECATED (t))
+    dummy->set_bool ("deprecated", true);
+  if (TREE_VISITED (t))
+    dummy->set_bool ("visited", true);
+
+  if (code != TREE_VEC && code != SSA_NAME && code != INTEGER_CST)
+    {
+      if (TREE_UNAVAILABLE (t))
+	dummy->set_bool ("unavailable", true);
+      if (TREE_LANG_FLAG_0 (t))
+	dummy->set_bool ("tree_0", true);
+      if (TREE_LANG_FLAG_1 (t))
+        dummy->set_bool ("tree_1", true);
+      if (TREE_LANG_FLAG_2 (t))
+	dummy->set_bool ("tree_2", true);
+      if (TREE_LANG_FLAG_3 (t))
+	dummy->set_bool ("tree_3", true);
+      if (TREE_LANG_FLAG_4 (t))
+	dummy->set_bool ("tree_4", true);
+      if (TREE_LANG_FLAG_5 (t))
+	dummy->set_bool ("tree_5", true);
+      if (TREE_LANG_FLAG_6 (t))
+	dummy->set_bool ("tree_6", true);
+    }
+
+  if (TREE_CODE_CLASS(code) == tcc_declaration)
+    {
+      if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
+        {
+          if (DECL_UNSIGNED (t))
+            dummy->set_bool ("unsigned", true);
+          if (DECL_IGNORED_P (t))
+            dummy->set_bool ("ignored", true);
+          if (DECL_ABSTRACT_P (t))
+            dummy->set_bool ("abstract", true);
+          if (DECL_EXTERNAL (t))
+            dummy->set_bool ("external", true);
+	  if (DECL_NONLOCAL (t))
+	    dummy->set_bool ("nonlocal", true);
+	}
+      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
+        {
+	  if (DECL_WEAK (t))
+	    dummy->set_bool ("weak", true);
+	  if (DECL_IN_SYSTEM_HEADER (t))
+	    dummy->set_bool ("in_system_header", true);
+	 }
+      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)
+	  && code != LABEL_DECL
+	  && code != FUNCTION_DECL
+	  && DECL_REGISTER (t))
+	dummy->set_bool ("regdecl", true);
+
+      if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (t))
+	dummy->set_bool ("suppress-debug", true);
+
+      if (code == FUNCTION_DECL
+	  && DECL_FUNCTION_SPECIFIC_TARGET (t))
+	dummy->set_bool ("function-specific-target", true);
+      if (code == FUNCTION_DECL
+	  && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (t))
+	dummy->set_bool ("function-specific-opt", true);
+      if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (t))
+	dummy->set_bool ("autoinline", true);
+      if (code == FUNCTION_DECL && DECL_UNINLINABLE (t))
+	dummy->set_bool ("uninlinable", true);
+      if (code == FUNCTION_DECL && fndecl_built_in_p (t))
+	dummy->set_bool ("built-in", true);
+      if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (t))
+	dummy->set_bool ("static-chain", true);
+      if (TREE_CODE (t) == FUNCTION_DECL && decl_is_tm_clone (t))
+	dummy->set_bool ("tm-clone", true);
+
+      if (code == FIELD_DECL && DECL_PACKED (t))
+	dummy->set_bool ("packed", true);
+      if (code == FIELD_DECL && DECL_BIT_FIELD (t))
+	dummy->set_bool ("bit-field", true);
+      if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (t))
+	dummy->set_bool ("nonaddressable", true);
+
+      if (code == LABEL_DECL && EH_LANDING_PAD_NR (t))
+        dummy->set_integer("landing_pad", EH_LANDING_PAD_NR(t));
+
+      if (code == VAR_DECL && DECL_IN_TEXT_SECTION (t))
+	dummy->set_bool ("in-text-section", true);
+      if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (t))
+	dummy->set_bool ("in-constant-pool", true);
+      if (code == VAR_DECL && DECL_COMMON (t))
+	dummy->set_bool ("common", true);
+      if ((code == VAR_DECL || code == PARM_DECL) && DECL_READ_P (t))
+	dummy->set_bool ("read", true);
+      if (code == VAR_DECL && DECL_THREAD_LOCAL_P (t))
+	  dummy->set_bool (tls_model_names[DECL_TLS_MODEL (t)], true);
+
+      if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
+	{
+	  if (DECL_VIRTUAL_P (t))
+	    dummy->set_bool ("virtual", true);
+	  if (DECL_PRESERVE_P (t))
+	    dummy->set_bool ("preserve", true);
+	  if (DECL_LANG_FLAG_0 (t))
+	    dummy->set_bool ("decl_0", true);
+	  if (DECL_LANG_FLAG_1 (t))
+	    dummy->set_bool ("decl_1", true);
+	  if (DECL_LANG_FLAG_2 (t))
+	    dummy->set_bool ("decl_2", true);
+	  if (DECL_LANG_FLAG_3 (t))
+	    dummy->set_bool ("decl_3", true);
+	  if (DECL_LANG_FLAG_4 (t))
+	    dummy->set_bool ("decl_4", true);
+	  if (DECL_LANG_FLAG_5 (t))
+	    dummy->set_bool ("decl_5", true);
+	  if (DECL_LANG_FLAG_6 (t))
+	    dummy->set_bool ("decl_6", true);
+	  if (DECL_LANG_FLAG_7 (t))
+	    dummy->set_bool ("decl_7", true);
+	  if (DECL_LANG_FLAG_8 (t))
+	    dummy->set_bool ("decl_8", true);
+
+	  dummy->set_string("mode", GET_MODE_NAME (DECL_MODE (t)));
+	}
+
+
+      if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
+	  && DECL_BY_REFERENCE (t))
+	dummy->set_bool ("passed-by-reference", true);
+
+      if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)
+                                && DECL_DEFER_OUTPUT (t))
+	dummy->set_bool ("defer-output", true);
+
+    } //end tcc_decl flags
+
+    if (TREE_CODE_CLASS(code) == tcc_type)
+      {
+      if (TYPE_UNSIGNED (t))
+	dummy->set_bool ("unsigned", true);
+
+      if (TYPE_NO_FORCE_BLK (t))
+	dummy->set_bool ("no-force-blk", true);
+
+      if (code == ARRAY_TYPE && TYPE_STRING_FLAG (t))
+	dummy->set_bool ("string-flag", true);
+
+      if (TYPE_NEEDS_CONSTRUCTING (t))
+	dummy->set_bool ("needs-constructing", true);
+
+      if ((code == RECORD_TYPE
+	   || code == UNION_TYPE
+	   || code == QUAL_UNION_TYPE
+	   || code == ARRAY_TYPE)
+	  && TYPE_REVERSE_STORAGE_ORDER (t))
+	dummy->set_bool ("reverse-storage-order", true);
+
+      if ((code == RECORD_TYPE
+	   || code == UNION_TYPE)
+	  && TYPE_CXX_ODR_P (t))
+	dummy->set_bool ("cxx-odr-p", true);
+
+      if ((code == RECORD_TYPE
+	   || code == UNION_TYPE)
+	  && TYPE_CXX_ODR_P (t))
+	dummy->set_bool ("cxx-odr-p", true);
+
+      if ((code == RECORD_TYPE
+	   || code == UNION_TYPE)
+	  && TYPE_INCLUDES_FLEXARRAY (t))
+	dummy->set_bool ("includes-flexarray", true);
+
+      if ((code == UNION_TYPE || code == RECORD_TYPE)
+	  && TYPE_TRANSPARENT_AGGR (t))
+	dummy->set_bool ("transparent-aggr", true);
+      else if (code == ARRAY_TYPE
+	       && TYPE_NONALIASED_COMPONENT (t))
+	dummy->set_bool ("nonaliased-component", true);
+
+      if (TYPE_PACKED (t))
+	dummy->set_bool ("packed", true);
+
+      if (TYPE_RESTRICT (t))
+	dummy->set_bool ("restrict", true);
+
+      if (TYPE_LANG_FLAG_0 (t))
+	dummy->set_bool ("type_0", true);
+      if (TYPE_LANG_FLAG_1 (t))
+	dummy->set_bool ("type_1", true);
+      if (TYPE_LANG_FLAG_2 (t))
+	dummy->set_bool ("type_2", true);
+      if (TYPE_LANG_FLAG_3 (t))
+	dummy->set_bool ("type_3", true);
+      if (TYPE_LANG_FLAG_4 (t))
+	dummy->set_bool ("type_4", true);
+      if (TYPE_LANG_FLAG_5 (t))
+	dummy->set_bool ("type_5", true);
+      if (TYPE_LANG_FLAG_6 (t))
+	dummy->set_bool ("type_6", true);
+      if (TYPE_LANG_FLAG_7 (t))
+	dummy->set_bool ("type_7", true);
+      } //end tcc_type flags
+
+  // Accessors
+  switch (code)
+  {
+    case IDENTIFIER_NODE:
+      dummy->set_string("identifier", 
+                        identifier_to_locale ((IDENTIFIER_POINTER(t))));
+      break;
+    case TREE_LIST:
+      while (t && t != error_mark_node)
+      {
+        if (TREE_PURPOSE (t))
+	{
+          holder->append(node_emit_json(TREE_PURPOSE(t)));
+	}
+	holder->append(node_emit_json(TREE_VALUE(t)));
+        t = TREE_CHAIN(t);
+      }
+      break;
+    case TREE_BINFO:
+      holder->append(node_emit_json(BINFO_TYPE(t)));
+      break;
+    case TREE_VEC:
+      {
+        size_t i;
+        if (TREE_VEC_LENGTH(t) > 0)
+	  {
+            size_t len = TREE_VEC_LENGTH (t);
+	    for (i = 0; i < len ; i++)
+	    {
+	      holder->append(node_emit_json(TREE_VEC_ELT(t, i)));
+	    }
+	  }
+      }
+      break;
+
+    case VOID_TYPE:
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case FIXED_POINT_TYPE:
+    case COMPLEX_TYPE:
+    case VECTOR_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case BITINT_TYPE:
+    case OPAQUE_TYPE:
+      {
+	unsigned int quals = TYPE_QUALS (t);
+	enum tree_code_class tclass;
+        json::object* _x;
+
+        _x = new json::object ();
+
+	if (quals & TYPE_QUAL_ATOMIC)
+	  _x->set_bool("atomic", true);
+	if (quals & TYPE_QUAL_CONST)
+	  _x->set_bool("const", true);
+	if (quals & TYPE_QUAL_VOLATILE)
+	  _x->set_bool("volatile", true);
+	if (quals & TYPE_QUAL_RESTRICT)
+	  _x->set_bool("restrict", true);
+
+        dummy->set("quals", _x);
+
+	if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t)))
+	    dummy->set_integer("address space", TYPE_ADDR_SPACE(t));
+	
+	tclass = TREE_CODE_CLASS (TREE_CODE(t));
+
+	if (tclass == tcc_declaration)
+	  {
+	  if (DECL_NAME (t))
+            decl_node_add_json(t, dummy);
+	  else
+	    dummy->set_string("decl", "<unnamed type decl>");
+	  }
+	else if (tclass == tcc_type)
+	  {
+	    if (TYPE_NAME (t))
+	    {  
+	      if (TREE_CODE(TYPE_NAME (t)) == IDENTIFIER_NODE)
+                dummy->set("identifier", node_emit_json(TYPE_NAME(t)));
+	      else if (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
+	               && DECL_NAME (TYPE_NAME (t)))
+                decl_node_add_json( TYPE_NAME (t), dummy);
+	      else 
+                dummy->set_string("type_name", "unnamed");
+	    }
+            else if (TREE_CODE (t) == VECTOR_TYPE)
+    	      {
+              for (long unsigned int i = 0; i < NUM_POLY_INT_COEFFS; i++)
+                {
+                  auto _poly_int = TYPE_VECTOR_SUBPARTS(t);
+                  dummy->set_integer("foo", _poly_int.coeffs[i]);
+                }
+              dummy->set("vector_subparts", holder);
+    	      }
+            else if (TREE_CODE (t) == INTEGER_TYPE)
+    	      {
+    	        if (TYPE_PRECISION (t) == CHAR_TYPE_SIZE)
+    	          dummy->set_string("type precision", (TYPE_UNSIGNED(t)
+    	          				   ? "unsigned char"
+    	          				   : "signed char"));
+    	        else if (TYPE_PRECISION (t) == SHORT_TYPE_SIZE)
+    	          dummy->set_string("type precision", (TYPE_UNSIGNED(t)
+    	          				   ? "unsigned short"
+    	          				   : "signed short"));
+    	        else if (TYPE_PRECISION (t) == INT_TYPE_SIZE)
+    	          dummy->set_string("type precision", (TYPE_UNSIGNED(t)
+    	          				   ? "unsigned int"
+    	          				   : "signed int"));
+    	        else if (TYPE_PRECISION (t) == LONG_TYPE_SIZE)
+    	          dummy->set_string("type precision", (TYPE_UNSIGNED(t)
+    	          				   ? "unsigned long"
+    	          				   : "signed long"));
+    	        else if (TYPE_PRECISION (t) == LONG_LONG_TYPE_SIZE)
+    	          dummy->set_string("type precision", (TYPE_UNSIGNED(t)
+    	          				   ? "unsigned long long"
+    	          				   : "signed long long"));
+    	        else if (TYPE_PRECISION (t) == CHAR_TYPE_SIZE
+ && pow2p_hwi (TYPE_PRECISION (t)))
+    	            dummy->set_integer(TYPE_UNSIGNED(t) ? "uint": "int",
+	                               TYPE_PRECISION(t));
+	        else
+		    dummy->set_integer(TYPE_UNSIGNED(t)
+				      ? "unnamed-unsigned"
+				      : "unnamed-signed", TYPE_PRECISION(t));
+  	      }
+	    else if (TREE_CODE (t) == COMPLEX_TYPE)
+	      {
+	        holder->append(node_emit_json(TREE_TYPE(t)));
+                dummy->set("complex", holder);
+	      }
+	    else if (TREE_CODE (t) == REAL_TYPE)
+	      {
+		dummy->set_integer("float", TYPE_PRECISION(t));
+	      }
+	    else if (TREE_CODE (t) == FIXED_POINT_TYPE)
+	      {
+		dummy->set_integer("fixed point", TYPE_PRECISION(t));
+	      }
+	    else if (TREE_CODE (t) == BOOLEAN_TYPE)
+	      {
+		dummy->set_integer(TYPE_UNSIGNED(t) 
+		                   ? "unsigned boolean"
+				   : "signed boolean", TYPE_PRECISION(t));
+	      }
+	    else if (TREE_CODE (t) == BITINT_TYPE)
+	      {
+		dummy->set_integer(TYPE_UNSIGNED (t)
+		                   ? "unsigned_BitInt"
+				   : "_BitInt", TYPE_PRECISION(t));
+	      }
+	    else if (TREE_CODE (t) == VOID_TYPE)
+	      dummy->set_bool("float", true);
+	    else
+	      dummy->set_bool("unnamed type", true);
+          }
+      }
+      break;
+
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+      {
+        if (TREE_TYPE (t) == NULL)
+   	  dummy->set_bool("null type", true);
+        else if (TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
+          {
+            tree function_node = TREE_TYPE(t);
+   	    tree arg_node = TYPE_ARG_TYPES(function_node);
+   	    json::array* args_holder;
+	    json::object* it_args;
+   	    json::object* _id;
+
+	    args_holder = new json::array ();
+	    _id = new json::object ();
+	    
+            dummy->set("fnode", node_emit_json(function_node));
+   
+   	    if (TYPE_IDENTIFIER (t))
+   	      _id->set("type identifier", node_emit_json(TYPE_NAME(t)));
+            else 
+              {
+                char* buff;
+                buff = new char ();
+                print_hex(TYPE_UID(t), buff);
+   	        _id->set_string("uid", buff);
+              }
+            dummy->set("function decl",
+                       function_decl_emit_json(function_node));
+            if (arg_node && arg_node != void_list_node
+                && arg_node != error_mark_node)
+	      it_args = new json::object();
+            while (arg_node && arg_node != void_list_node
+                   && arg_node != error_mark_node)
+   	      {
+	        it_args = node_emit_json(arg_node);
+	        args_holder->append(it_args);
+   	        arg_node = TREE_CHAIN (arg_node);
+   	      }
+   	    dummy->set("type_uid", _id);
+   	    dummy->set("args", args_holder);
+          }
+        else
+          {
+   	  unsigned int quals = TYPE_QUALS (t);
+   	  dummy->set("tree_type", node_emit_json(TREE_TYPE(t)));
+   	  json::object *_x; 
+
+          _x = new json::object ();
+  
+  	  if (quals & TYPE_QUAL_ATOMIC)
+  	    _x->set_bool("atomic", true);
+  	  if (quals & TYPE_QUAL_CONST)
+  	    _x->set_bool("const", true);
+  	  if (quals & TYPE_QUAL_VOLATILE)
+  	    _x->set_bool("volatile", true);
+  	  if (quals & TYPE_QUAL_RESTRICT)
+  	    _x->set_bool("restrict", true);
+        
+          dummy->set("quals", _x);
+   	  if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t)))
+   	    dummy->set_integer("address space", TYPE_ADDR_SPACE (t));
+   	  if (TYPE_REF_CAN_ALIAS_ALL (t))
+   	    dummy->set_bool("ref can alias all", true);
+          }
+      }
+      break;
+
+    case OFFSET_TYPE:
+      break;
+
+    case MEM_REF:
+    case TARGET_MEM_REF:
+      {
+        if (TREE_CODE (t) == MEM_REF
+            && integer_zerop (TREE_OPERAND (t, 1))
+            && TREE_CODE (TREE_OPERAND (t, 0)) != INTEGER_CST
+            && TREE_TYPE (TREE_OPERAND (t, 0)) != NULL_TREE
+            && (TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)))
+             	 == TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 1))))
+            && (TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0)))
+             	 == TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 1))))
+            && (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (t, 0)))
+             	 == TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (t, 1))))
+            && (TYPE_MAIN_VARIANT (TREE_TYPE (t))
+                == TYPE_MAIN_VARIANT (
+		        TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 1))))))
+          {
+            if (TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR)
+              {
+                dummy->set("base", node_emit_json(TREE_OPERAND (t, 0)));
+              }
+            else
+              dummy->set("base", node_emit_json(
+				      TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
+          }
+        else
+          { //Check later
+            tree type = TREE_TYPE(t);
+            tree op1 = TREE_OPERAND(t, 1);
+            tree op1type = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
+
+            tree op0size = TYPE_SIZE(type);
+            tree op1size = TYPE_SIZE (TREE_TYPE(op1type));
+
+            if (!op0size || !op1size 
+                || ! operand_equal_p(op0size, op1size, 0))
+            {
+              dummy->set("tree_type_size", node_emit_json(type));
+            }
+            dummy->set("op1_type_size", node_emit_json(op1type));
+
+            if (!integer_zerop (op1))
+              dummy->set("offset", node_emit_json(op1));
+            if (TREE_CODE(t) == TARGET_MEM_REF)
+              {
+                tree temp = TMR_INDEX2 (t);
+                if (temp)
+                  dummy->set("tmr_index2", node_emit_json(temp));
+                temp = TMR_INDEX (t);
+                if (temp)
+                  {
+                    dummy->set("tmr_index", node_emit_json(temp));
+                    temp = TMR_STEP(t);
+                    if (temp)
+                      dummy->set("tmr_step", node_emit_json(temp));
+                  }
+              }
+          }
+        if (MR_DEPENDENCE_CLIQUE (t) != 0)
+          {
+            dummy->set_integer("clique", MR_DEPENDENCE_CLIQUE(t));
+            dummy->set_integer("base", MR_DEPENDENCE_BASE(t));
+          }
+      }
+    break;
+
+    /* FIXME : As in tree-pretty-print.cc, the following four codes are
+     *         incomplete. See print_struct_decl therein the above. */
+    case ARRAY_TYPE:
+      {
+        unsigned int quals = TYPE_QUALS (t);
+	if (quals & TYPE_QUAL_ATOMIC)
+	  dummy->set_bool("atomic", true);
+	if (quals & TYPE_QUAL_CONST)
+	  dummy->set_bool("const", true);
+	if (quals & TYPE_QUAL_VOLATILE)
+	  dummy->set_bool("volatile", true);
+      }
+      break;
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+        unsigned int quals = TYPE_QUALS (t);
+        json::object *_x;
+
+        _x = new json::object ();
+
+        if (quals & TYPE_QUAL_ATOMIC)
+          _x->set_bool("atomic", true);
+        if (quals & TYPE_QUAL_CONST)
+          _x->set_bool("const", true);
+        if (quals & TYPE_QUAL_VOLATILE)
+          _x->set_bool("volatile", true);
+        
+        dummy->set("type_quals", _x);
+
+        if (TYPE_NAME(t))
+          dummy->set("type_name", node_emit_json(TYPE_NAME(t)));
+      }
+      break;
+    case LANG_TYPE:
+      break;
+    case INTEGER_CST:
+      {
+        dummy->set_bool("integer_cst", true);
+
+        if ((POINTER_TYPE_P (TREE_TYPE (t))) 
+            || (TYPE_PRECISION (TREE_TYPE (t))
+                < TYPE_PRECISION (integer_type_node))
+            || exact_log2 (TYPE_PRECISION (TREE_TYPE (t))) == -1
+            || tree_int_cst_sgn (t) < 0)
+          {
+            holder->append( node_emit_json (TREE_TYPE(t)));
+            dummy->set("_Literal", holder);
+          }
+        if (TREE_CODE (TREE_TYPE(t)) == POINTER_TYPE) 
+          {
+            // In bytes
+            dummy->set_bool("pointer", true);
+            dummy->set_integer("val", TREE_INT_CST_LOW(t));
+          }
+        else if (tree_fits_shwi_p(t))
+          dummy->set_integer("val", tree_to_shwi (t));
+        else if (tree_fits_uhwi_p(t))
+          dummy->set_integer("val", tree_to_uhwi (t));
+        else
+          {
+            wide_int val = wi::to_wide (t);
+            char buff[WIDE_INT_PRINT_BUFFER_SIZE];
+        
+            print_dec(wi::to_wide (t), buff, TYPE_SIGN (TREE_TYPE (t)));
+            dummy->set_string("val", buff);
+        }
+      if (TREE_OVERFLOW (t))
+        dummy->set_bool("overflow", true);
+      }
+      break;
+
+    case POLY_INT_CST:
+      for (unsigned int i = 1; i < NUM_POLY_INT_COEFFS; i++)
+        holder->append(node_emit_json(POLY_INT_CST_COEFF(t, i)));
+      dummy->set("poly_int_cst", holder);
+      break;
+
+    case REAL_CST:
+      {
+        REAL_VALUE_TYPE d;
+
+        d = TREE_REAL_CST (t);
+
+        if (TREE_OVERFLOW (t))
+          dummy->set_bool("overflow", true);
+
+        if (REAL_VALUE_ISINF (d))
+          dummy->set_string("value", REAL_VALUE_NEGATIVE(d) ? "-Inf" : "Inf");
+        else if (REAL_VALUE_ISNAN(d))
+          dummy->set_string("value", "NaN");
+        else
+          {
+            char string[100];
+            real_to_decimal(string, &d, sizeof (string), 0, 1);
+            dummy->set_string("real_value", string);
+          }
+      }
+      break;
+
+    case FIXED_CST:
+      {
+        char string[100];
+        fixed_to_decimal(string, TREE_FIXED_CST_PTR(t), sizeof (string));
+        dummy->set_string("fixed_cst", string);
+      }
+      break;
+
+    case STRING_CST:
+        dummy->set_string("string_cst", TREE_STRING_POINTER(t));
+        break;
+
+    case VECTOR_CST:
+      {
+        unsigned int i;
+        unsigned HOST_WIDE_INT nunits;
+
+        if (!VECTOR_CST_NELTS (t).is_constant (&nunits))
+          nunits = vector_cst_encoded_nelts (t);
+        for (i = 0; i < nunits; i++)
+          {
+            holder->append(node_emit_json(VECTOR_CST_ELT (t, i)));
+          }
+        dummy->set("vector_cst", holder);
+      }
+      break;
+
+    case FUNCTION_TYPE:
+    case METHOD_TYPE:
+      dummy->set("type_data", node_emit_json(TREE_TYPE (t)));
+
+      if (TREE_CODE (t) == METHOD_TYPE)
+        {
+          dummy->set_bool("method_type", true);
+          if (TYPE_METHOD_BASETYPE (t))
+            dummy->set("basetype", node_emit_json (
+				        TYPE_NAME (TYPE_METHOD_BASETYPE(t))));
+          else 
+            dummy->set_string("basetype", "null method basetype");
+        }
+      if (TYPE_IDENTIFIER (t))
+        dummy->set("type_identifier", node_emit_json (TYPE_NAME(t)));
+      else if ( TYPE_NAME (t) && DECL_NAME (TYPE_NAME (t)) )
+        decl_node_add_json( TYPE_NAME(t), dummy);
+      else //TDF_NOUID
+        {
+          char* buff;
+          buff = new char ();
+          print_hex(TYPE_UID(t), buff);
+   	  dummy->set_string("uid", buff);
+        }
+      dummy->set("function_decl", function_decl_emit_json(t));
+      break;
+
+
+    case FUNCTION_DECL:
+    case CONST_DECL:
+      decl_node_add_json(t, dummy);
+      break;
+    case LABEL_DECL:
+      if (DECL_NAME (t))
+        decl_node_add_json(t, dummy);
+      else if (LABEL_DECL_UID (t) != -1)
+        dummy->set_integer("LabelDeclUID", LABEL_DECL_UID (t));
+      else 
+        dummy->set_integer("DeclUID", DECL_UID(t));
+      break;
+
+    case TYPE_DECL:
+      if (DECL_IS_UNDECLARED_BUILTIN (t)) //parity w/ dump_generic_node
+        break;
+      if (DECL_NAME (t))
+        decl_node_add_json(t, dummy);
+      else if (TYPE_NAME (TREE_TYPE (t)) != t)
+        {
+          dummy->set(TREE_CODE (TREE_TYPE (t)) == UNION_TYPE ? "union"
+                                                             : "struct",
+                     node_emit_json( TREE_TYPE (t)));
+        }
+      else
+        dummy->set_bool("anon_type_decl", true);
+      break;
+
+    case VAR_DECL:
+    case PARM_DECL:
+    case FIELD_DECL:
+    case DEBUG_EXPR_DECL:
+    case NAMESPACE_DECL:
+    case NAMELIST_DECL:
+      decl_node_add_json(t, dummy);
+      break;
+      
+    case RESULT_DECL:
+      dummy->set_bool("retval", true);
+      break;
+
+    case COMPONENT_REF:
+      op0 = TREE_OPERAND (t, 0);
+      op1 = TREE_OPERAND (t, 1);
+      if (op0
+          && (TREE_CODE (op0) == INDIRECT_REF
+              || (TREE_CODE (op0) == MEM_REF
+                  && TREE_CODE (TREE_OPERAND (op0, 0)) != ADDR_EXPR
+                  && integer_zerop (TREE_OPERAND (op0, 1))
+                  //We want to be explicit about Integer_CSTs
+                  && TREE_CODE (TREE_OPERAND (op0, 0)) != INTEGER_CST
+                  // To play nice with SSA
+                  && TREE_TYPE (TREE_OPERAND (op0, 0)) != NULL_TREE
+                  // I don't understand what the qualm is here
+                  && (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0)))
+                      == (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
+                  && (TYPE_MODE (TREE_TYPE (TREE_OPERAND (op0, 0)))
+                      == (TYPE_MODE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
+                  && (TYPE_REF_CAN_ALIAS_ALL (
+		           TREE_TYPE (TREE_OPERAND (op0, 0)))
+                      == (TYPE_REF_CAN_ALIAS_ALL (
+			       TREE_TYPE (TREE_OPERAND (op0, 1)))))
+                  // Understand this later too
+                  && (TYPE_MAIN_VARIANT (TREE_TYPE (op0))
+                      == TYPE_MAIN_VARIANT (
+			      TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 1)))))
+                  && MR_DEPENDENCE_CLIQUE (op0) == 0)))
+        {
+          //
+          op0 = TREE_OPERAND (op0, 0);
+        }
+      dummy->set("expr", node_emit_json(op0));
+      dummy->set("field", node_emit_json(op1));
+      if (DECL_P (op1))
+        if (tree off = component_ref_field_offset(t))
+          if (TREE_CODE (off) != INTEGER_CST)
+            {
+              dummy->set("offset", node_emit_json(off));
+            }
+    break;
+
+    case BIT_FIELD_REF:
+      dummy->set_string("tree_code", "bit_field_ref");
+      dummy->set("expr",
+                 node_emit_json( TREE_OPERAND (t, 0)));
+      dummy->set("bits_ref",
+                 node_emit_json( TREE_OPERAND (t, 1)));
+      dummy->set("bits_first_pos",
+                 node_emit_json( TREE_OPERAND (t, 2)));
+      break;
+
+    case BIT_INSERT_EXPR:
+      dummy->set_string("tree_code", "bit_insert_expr");
+      dummy->set("container",
+                 node_emit_json( TREE_OPERAND (t, 0)));
+      dummy->set("replacement",
+                 node_emit_json( TREE_OPERAND (t, 1)));
+      dummy->set("constant_bit_pos",
+                 node_emit_json( TREE_OPERAND (t, 2)));
+      break;
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+      op0 = TREE_OPERAND (t, 0);
+      dummy->set("array",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("index",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      if (TREE_OPERAND(t, 2))
+        dummy->set("type_min_val", 
+                   node_emit_json (TREE_OPERAND (t, 2)));
+      if (TREE_OPERAND(t, 3))
+        dummy->set("element_size", 
+                   node_emit_json (TREE_OPERAND (t, 3)));
+      break;
+  
+    case OMP_ARRAY_SECTION:
+      dummy->set("op0",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("op1",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      dummy->set("op2",
+                 node_emit_json (TREE_OPERAND (t, 2)));
+      break;
+
+    case CONSTRUCTOR:
+      {
+        unsigned HOST_WIDE_INT ix;
+        tree field, val;
+        bool is_struct_init = false;
+        bool is_array_init = false;
+        widest_int curidx;
+
+        if (TREE_CLOBBER_P (t))
+          switch (CLOBBER_KIND(t))
+            {
+          case CLOBBER_STORAGE_BEGIN:
+              dummy->set_string("CLOBBER", "storage_begin");
+              break;
+            case CLOBBER_STORAGE_END:
+              dummy->set_bool("CLOBBER", "storage_end");
+              break;
+            case CLOBBER_OBJECT_BEGIN:
+              dummy->set_bool("CLOBBER", "object_begin");
+              break;
+            case CLOBBER_OBJECT_END:
+              dummy->set_bool("CLOBBER", "object_end");
+              break;
+            default:
+              break;
+          }
+        else if (TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE
+                 || TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
+          is_struct_init = true;
+        else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE
+                 && TYPE_DOMAIN (TREE_TYPE (t))
+                 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t))))
+                    == INTEGER_CST)
+          {
+            tree minv = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
+            is_array_init = true;
+            curidx = wi::to_widest (minv);
+          }
+        FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), ix, field, val)
+          {
+            json::object* cst_elt;
+            json::object* _val_json;
+            cst_elt = new json::object ();
+            cst_elt->set_integer("", ix); //fix
+            if (field)
+              {
+                if (is_struct_init)
+                  cst_elt->set("field", node_emit_json(field));
+                else if (is_array_init 
+                         && (TREE_CODE (field) != INTEGER_CST
+                             || curidx != wi::to_widest (field)))
+                  {
+                    json::array* _array_init_json;
+                    if (TREE_CODE (field) == RANGE_EXPR)
+                      {
+                        _array_init_json = new json::array ();
+                        _array_init_json->append(node_emit_json(
+						      TREE_OPERAND(field, 0)));
+                        _array_init_json->append(node_emit_json(
+                                                     TREE_OPERAND(field, 1)));
+                        cst_elt->set("field", _array_init_json);
+                      }
+                    else 
+                      cst_elt->set ("field", node_emit_json (field));
+                  }
+              }
+            if (is_array_init)
+              curidx += 1;
+            if (val && TREE_CODE (val) == ADDR_EXPR)
+              if (TREE_CODE (TREE_OPERAND (val, 0)) == FUNCTION_DECL)
+                val = TREE_OPERAND (val, 0);
+            if (val && TREE_CODE (val) == FUNCTION_DECL)
+              {
+                _val_json = new json::object ();
+                decl_node_add_json (val, _val_json);
+                cst_elt->set("val", _val_json);
+              }
+            else
+              cst_elt->set("val", node_emit_json(val));
+
+            if (TREE_CODE (field) == INTEGER_CST)
+              curidx = wi::to_widest (field);
+            holder->append(cst_elt);
+          }
+        dummy->set("ctor_elts", holder);
+      }
+    break;
+
+   case COMPOUND_EXPR:
+     {
+        tree *tp;
+        holder->append( node_emit_json( TREE_OPERAND (t, 0)));
+
+        for (tp = &TREE_OPERAND (t, 1);
+             TREE_CODE (*tp) == COMPOUND_EXPR;
+             tp = &TREE_OPERAND (*tp, 1))
+          {
+          holder->append( node_emit_json ( TREE_OPERAND (*tp, 0)));
+          }
+
+        dummy->set("compound_expr", holder);
+      }
+      break;
+
+    case STATEMENT_LIST:
+      {
+        tree_stmt_iterator si;
+
+        for (si =  tsi_start (t); !tsi_end_p (si); tsi_next (&si))
+          {
+            holder->append( node_emit_json (tsi_stmt (si)));
+          }
+        dummy->set("statement_list", holder);
+      }
+      break;
+
+    case MODIFY_EXPR:
+    case INIT_EXPR:
+      dummy->set("op0",
+                 node_emit_json( TREE_OPERAND (t, 0)));
+      dummy->set("op1",
+                 node_emit_json( TREE_OPERAND (t, 1)));
+      break;
+
+    case TARGET_EXPR:
+      dummy->set("slot", node_emit_json (TARGET_EXPR_SLOT(t)));
+      dummy->set("initial", node_emit_json (TARGET_EXPR_INITIAL(t)));
+      break;
+
+    case DECL_EXPR:
+      decl_node_add_json(DECL_EXPR_DECL(t), dummy);
+      break;
+
+    case COND_EXPR:
+      dummy->set("if",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      if (COND_EXPR_THEN(t))
+      {
+        dummy->set("then",
+                   node_emit_json (TREE_OPERAND (t, 1)));
+      }
+      if (COND_EXPR_ELSE(t))
+      {
+        dummy->set("else",
+                 node_emit_json (TREE_OPERAND (t, 2)));
+      }
+      break;
+
+    case BIND_EXPR:
+      if (BIND_EXPR_VARS (t))
+        {
+          for (op0 = BIND_EXPR_VARS (t); op0; op0 = DECL_CHAIN (op0))
+            {
+              holder->append(node_emit_json (op0));
+            }
+          dummy->set("bind_expr_vars", holder);
+        }
+      dummy->set("bind_expr_body", 
+                 node_emit_json(BIND_EXPR_BODY(t)));
+      break;
+
+    case CALL_EXPR:
+      {
+        if (CALL_EXPR_FN (t) != NULL_TREE)
+          call_name_add_json (CALL_EXPR_FN(t), dummy);
+        else
+          dummy->set_string("internal_fn",
+			     internal_fn_name (CALL_EXPR_IFN (t)));
+        dummy->set_bool("return_slot_optimization",
+			 CALL_EXPR_RETURN_SLOT_OPT(t));
+        dummy->set_bool("tail_call", CALL_EXPR_TAILCALL(t));
+
+        tree arg;
+        call_expr_arg_iterator iter;
+        bool call;
+        FOR_EACH_CALL_EXPR_ARG(arg, iter, t)
+          {
+            call = true;
+            holder->append(node_emit_json(arg));
+          }
+        if (call)
+          dummy->set("call_expr_arg", holder);
+
+        if (CALL_EXPR_VA_ARG_PACK (t))
+          dummy->set_bool("__builtin_va_arg_pack", true);
+        
+        op1 = CALL_EXPR_STATIC_CHAIN (t);
+        if (op1)
+          dummy->set("static_chain", node_emit_json(op1));
+      }
+      break;
+    case WITH_CLEANUP_EXPR:
+      break;
+    case CLEANUP_POINT_EXPR:
+      dummy->set("cleanup_point", node_emit_json (TREE_OPERAND(t, 0)));
+      break;
+    case PLACEHOLDER_EXPR:
+      dummy->set("placeholder_expr", node_emit_json (TREE_OPERAND(t, 0)));
+      break;
+
+    /* Binary operations */
+    case WIDEN_SUM_EXPR:
+    case WIDEN_MULT_EXPR:
+    case MULT_EXPR:
+    case MULT_HIGHPART_EXPR:
+    case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
+    case MINUS_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+    case WIDEN_LSHIFT_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case LTGT_EXPR:
+    case ORDERED_EXPR:
+    case UNORDERED_EXPR:
+      {
+        const char* c = op_symbol_code(TREE_CODE(t), TDF_NONE);
+        op0 = TREE_OPERAND(t, 0);
+        op1 = TREE_OPERAND(t, 1);
+        
+        dummy->set_string("bin_operator", c);
+        holder->append(node_emit_json(op0));
+        holder->append(node_emit_json(op1));
+        dummy->set("operands", holder);
+      }
+      break;
+
+    case ADDR_EXPR:
+      //TDF_GIMPLE_VAL
+      dummy->set("_Literal", node_emit_json( TREE_TYPE (t)));
+      /* FALLTHROUGH */
+    case NEGATE_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case INDIRECT_REF:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+      {
+        const char * c = op_symbol_code(code, TDF_NONE);
+        dummy->set(c, node_emit_json (TREE_OPERAND (t, 0)));
+      }
+      break;
+
+    case MIN_EXPR:
+      holder->append (node_emit_json (TREE_OPERAND (t,0)));
+      holder->append (node_emit_json (TREE_OPERAND (t,1)));
+      dummy->set("min_expr", holder);
+      break;
+
+    case MAX_EXPR:
+      holder->append (node_emit_json (TREE_OPERAND (t,0)));
+      holder->append (node_emit_json (TREE_OPERAND (t,1)));
+      dummy->set("max_expr", holder);
+      break;
+
+    case ABS_EXPR:
+      holder->append (node_emit_json (TREE_OPERAND (t,0)));
+      dummy->set("abs_expr", holder);
+      break;
+
+    case ABSU_EXPR:
+      holder->append (node_emit_json (TREE_OPERAND (t,0)));
+      dummy->set("absu_expr", holder);
+      break;
+
+    case RANGE_EXPR:
+      break;
+
+    case ADDR_SPACE_CONVERT_EXPR:
+    case FIXED_CONVERT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    CASE_CONVERT: 
+      type = TREE_TYPE (t);
+      op0 = TREE_OPERAND (t, 0);
+      if (type != TREE_TYPE(op0))
+        {
+          dummy->set ("type", node_emit_json (type));
+        }
+      dummy->set ("operand", node_emit_json (op0));
+      break;
+
+    case VIEW_CONVERT_EXPR:
+      holder->append (node_emit_json (TREE_TYPE(t)));
+      holder->append (node_emit_json (TREE_OPERAND(t, 0)));
+      dummy->set("view_convert_expr", holder);
+      break;
+
+    case PAREN_EXPR:
+      dummy->set("paren_expr",
+                 node_emit_json (TREE_OPERAND (t,0)));
+      break;
+
+    case NON_LVALUE_EXPR:
+      dummy->set("non_lvalue_expr",
+                 node_emit_json (TREE_OPERAND (t,0)));
+      break;
+
+    case SAVE_EXPR:
+      dummy->set("save_expr",
+                 node_emit_json (TREE_OPERAND (t,0)));
+      break;
+
+    case COMPLEX_EXPR:
+      holder->append (node_emit_json (TREE_OPERAND (t,0)));
+      holder->append (node_emit_json (TREE_OPERAND (t,1)));
+      dummy->set("complex_expr", holder);
+      break;
+
+    case CONJ_EXPR:
+      dummy->set("conj_expr",
+                 node_emit_json (TREE_OPERAND (t,0)));
+      break;
+
+    case REALPART_EXPR:
+      dummy->set("realpart_expr",
+                 node_emit_json (TREE_OPERAND (t,0)));
+      break;
+
+    case IMAGPART_EXPR:
+      dummy->set("imagpart_expr",
+                 node_emit_json (TREE_OPERAND (t,0)));
+      break;
+
+    case VA_ARG_EXPR:
+      dummy->set("va_arg_expr",
+                 node_emit_json (TREE_OPERAND (t,0)));
+      break;
+
+    case TRY_FINALLY_EXPR:
+    case TRY_CATCH_EXPR:
+      {
+        tree _t;
+        dummy->set("try",
+                   node_emit_json (TREE_OPERAND (t, 0)));
+        if (TREE_CODE (t) == TRY_CATCH_EXPR)
+          {
+            _t = TREE_OPERAND(t, 1);
+            dummy->set("catch",
+                        node_emit_json (_t));
+          }
+        else
+          {
+            gcc_assert(TREE_CODE (t) == TRY_FINALLY_EXPR);
+            _t = TREE_OPERAND(t, 1);
+            if (TREE_CODE (t) == EH_ELSE_EXPR)
+              {
+                _t = TREE_OPERAND (_t, 0);
+                dummy->set("finally",
+                           node_emit_json (_t));
+                _t = TREE_OPERAND(_t, 1);
+                dummy->set("else",
+                           node_emit_json (_t));
+              }
+            else
+              {
+              dummy->set("finally",
+                         node_emit_json(_t));
+              }
+          }
+      }
+      break;
+
+    case CATCH_EXPR:
+      dummy->set("catch_types", node_emit_json(CATCH_TYPES(t)));
+      dummy->set("catch_body", node_emit_json(CATCH_BODY(t)));
+      break;
+
+    case EH_FILTER_EXPR:
+      dummy->set("eh_filter_types", node_emit_json(EH_FILTER_TYPES(t)));
+      dummy->set("eh_filter_failure", node_emit_json(EH_FILTER_FAILURE(t)));
+      break;
+
+    case LABEL_EXPR:
+      decl_node_add_json (TREE_OPERAND (t, 0), dummy);
+      break;
+
+    case LOOP_EXPR:
+      dummy->set("while (1)", node_emit_json (LOOP_EXPR_BODY (t)));
+      break;
+
+    case PREDICT_EXPR:
+      if (PREDICT_EXPR_OUTCOME (t))
+        dummy->set_string("likely by",
+                          predictor_name (PREDICT_EXPR_PREDICTOR (t)));
+      else
+        dummy->set_string("unlikely by",
+                          predictor_name (PREDICT_EXPR_PREDICTOR (t)));
+      break;
+    case ANNOTATE_EXPR:
+      {
+      switch ((enum annot_expr_kind) TREE_INT_CST_LOW (TREE_OPERAND(t,1)))
+        { //Is this expensive? ask later
+          case annot_expr_ivdep_kind:
+            dummy->set("ivdep", node_emit_json (TREE_OPERAND (t, 0)));
+            break;
+          case annot_expr_unroll_kind:
+            dummy->set("unroll", node_emit_json (TREE_OPERAND (t, 0)));
+            break;
+          case annot_expr_no_vector_kind:
+            dummy->set("no-vector", node_emit_json (TREE_OPERAND (t, 0)));
+            break;
+          case annot_expr_vector_kind:
+            dummy->set("vector", node_emit_json (TREE_OPERAND (t, 0)));
+            break;
+          case annot_expr_parallel_kind:
+            dummy->set("parallel", node_emit_json (TREE_OPERAND (t, 0)));
+            break;
+          case annot_expr_maybe_infinite_kind:
+            dummy->set("maybe_infinite",
+			node_emit_json (TREE_OPERAND (t, 0)));
+            break;
+          default:
+            gcc_unreachable();
+        }
+      }
+      break;
+
+    case RETURN_EXPR:
+      {
+        op0 = TREE_OPERAND(t, 0);
+        if (op0)
+          {
+            if (TREE_CODE(op0) == MODIFY_EXPR)
+              dummy->set("return_expr", node_emit_json(TREE_OPERAND(op0, 1)));
+            else
+              dummy->set("return_expr", node_emit_json(op0));
+          }
+      }
+      break;
+
+    case EXIT_EXPR:
+      dummy->set("exit_if", node_emit_json(TREE_OPERAND (t, 0)));
+      break;
+
+    case SWITCH_EXPR:
+      dummy->set("switch_cond", node_emit_json(SWITCH_COND(t)));
+      dummy->set("switch_body", node_emit_json(SWITCH_BODY(t)));
+      break;
+
+    case GOTO_EXPR:
+      op0 = GOTO_DESTINATION(t);
+      dummy->set("goto", node_emit_json(op0));
+      break;
+
+    case ASM_EXPR:
+      dummy->set("asm_string", node_emit_json (ASM_STRING (t)));
+      dummy->set("asm_outputs", node_emit_json (ASM_OUTPUTS (t)));
+      dummy->set("asm_inputs", node_emit_json (ASM_INPUTS (t)));
+      if (ASM_CLOBBERS (t))
+        dummy->set("asm_clobbers", node_emit_json (ASM_CLOBBERS (t)));
+      break;
+
+    case CASE_LABEL_EXPR:
+      if (CASE_LOW(t) && CASE_HIGH(t))
+        {
+          dummy->set ("case_low", node_emit_json (CASE_LOW(t)));
+          dummy->set ("case_high", node_emit_json (CASE_HIGH(t)));
+        }
+      else if (CASE_LOW(t))
+        dummy->set ("case", node_emit_json (CASE_LOW(t)));
+      else
+        dummy->set_string("case", "default");
+      break;
+
+    // check later - okay?
+    case OBJ_TYPE_REF:
+      dummy->set("obj_type_ref_expr",
+                 node_emit_json(OBJ_TYPE_REF_EXPR(t)));
+      dummy->set("obj_type_ref_object",
+                 node_emit_json(OBJ_TYPE_REF_OBJECT(t)));
+      dummy->set("obj_type_ref_token",
+                 node_emit_json(OBJ_TYPE_REF_TOKEN(t)));
+      break;
+
+    case SSA_NAME:
+      {
+      if (SSA_NAME_IDENTIFIER (t))
+        dummy->set("ssa_name_identifier",
+                   node_emit_json (SSA_NAME_IDENTIFIER (t)));
+      if (SSA_NAME_IS_DEFAULT_DEF (t))
+        dummy->set_bool("ssa_default_def", true);
+      if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (t))
+	dummy->set_bool("abnormal_phi", true);
+      }
+      break;
+
+    case WITH_SIZE_EXPR:
+      dummy->set("expr", node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("size", node_emit_json (TREE_OPERAND (t, 1)));
+      break;
+
+    case SCEV_KNOWN:
+    case SCEV_NOT_KNOWN:
+      break;
+
+    case POLYNOMIAL_CHREC:
+      dummy->set_integer("chrec_var", CHREC_VARIABLE(t));
+      dummy->set("chrec_left", node_emit_json (CHREC_LEFT(t)));
+      dummy->set("chrec_right", node_emit_json (CHREC_RIGHT(t)));
+      dummy->set_bool("chrec_nowrap", CHREC_NOWRAP(t));
+      break;
+
+    case REALIGN_LOAD_EXPR:
+      dummy->set("input_0", node_emit_json(TREE_OPERAND (t, 0)));
+      dummy->set("input_1", node_emit_json(TREE_OPERAND (t, 1)));
+      dummy->set("offset", node_emit_json(TREE_OPERAND (t, 2)));
+      break;
+
+    case VEC_COND_EXPR:
+      dummy->set("if",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("then",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      dummy->set("else",
+                 node_emit_json (TREE_OPERAND (t, 2)));
+      break;
+
+    case VEC_PERM_EXPR:
+      dummy->set("v0",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("v1",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      dummy->set("mask",
+                 node_emit_json (TREE_OPERAND (t, 2)));
+      break;
+
+    case DOT_PROD_EXPR: //check later
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("arg2",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      dummy->set("arg3",
+                 node_emit_json (TREE_OPERAND (t, 2)));
+      break;
+
+    case WIDEN_MULT_PLUS_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("arg2",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      dummy->set("arg3",
+                 node_emit_json (TREE_OPERAND (t, 2)));
+      break;
+
+    case WIDEN_MULT_MINUS_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("arg2",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      dummy->set("arg3",
+                 node_emit_json (TREE_OPERAND (t, 2)));
+      break;
+
+    case VEC_SERIES_EXPR:
+    case VEC_WIDEN_MULT_HI_EXPR:
+    case VEC_WIDEN_MULT_LO_EXPR:
+    case VEC_WIDEN_MULT_ODD_EXPR:
+    case VEC_WIDEN_LSHIFT_HI_EXPR:
+    case VEC_WIDEN_LSHIFT_LO_EXPR:
+      dummy->set("arg1", 
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("arg2",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      break;
+
+    case VEC_DUPLICATE_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      break;
+
+    case VEC_UNPACK_HI_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      break;
+
+    case VEC_UNPACK_LO_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      break;
+
+    case VEC_UNPACK_FLOAT_HI_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      break;
+
+    case VEC_UNPACK_FLOAT_LO_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      break;
+
+    case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      break;
+
+    case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      break;
+
+    case VEC_PACK_TRUNC_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("arg2",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      break;
+
+    case VEC_PACK_SAT_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("arg2",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      break;
+
+    case VEC_PACK_FIX_TRUNC_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("arg2",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      break;
+
+    case VEC_PACK_FLOAT_EXPR:
+      dummy->set("arg1",
+                 node_emit_json (TREE_OPERAND (t, 0)));
+      dummy->set("arg2",
+                 node_emit_json (TREE_OPERAND (t, 1)));
+      break;
+    /*OACC and OMP */
+    case OACC_PARALLEL:
+      goto dump_omp_clauses_body;
+
+    case OACC_KERNELS:
+      goto dump_omp_clauses_body;
+
+    case OACC_SERIAL:
+      goto dump_omp_clauses_body;
+
+    case OACC_DATA:
+      goto dump_omp_clauses_body;
+
+    case OACC_HOST_DATA:
+      dummy->set("oacc_host_data_clauses", 
+                 omp_clause_emit_json (OACC_HOST_DATA_CLAUSES(t)));
+      dummy->set("oacc_host_data_body", 
+                 omp_clause_emit_json (OACC_HOST_DATA_BODY(t)));
+      break;
+
+    case OACC_DECLARE:
+      dummy->set("oacc_declare_clauses", 
+                 omp_clause_emit_json (OACC_DECLARE_CLAUSES(t)));
+      break;
+
+    case OACC_UPDATE:
+      dummy->set("oacc_update_clauses",
+                 omp_clause_emit_json (OACC_UPDATE_CLAUSES(t)));
+      break;
+
+    case OACC_ENTER_DATA:
+      dummy->set("oacc_enter_data_clauses",
+                 omp_clause_emit_json (OACC_ENTER_DATA_CLAUSES(t)));
+      break;
+      
+    case OACC_EXIT_DATA:
+      dummy->set("oacc_exit_data_clauses",
+                 omp_clause_emit_json (OACC_EXIT_DATA_CLAUSES(t)));
+      break;
+
+    case OACC_CACHE:
+      dummy->set("oacc_cache_clauses",
+                 omp_clause_emit_json (OACC_CACHE_CLAUSES(t)));
+      break;
+
+    case OMP_PARALLEL:
+      dummy->set("omp_parallel_body",
+                 node_emit_json (OMP_PARALLEL_BODY(t)));
+      dummy->set("omp_parallel_clauses",
+                 omp_clause_emit_json (OMP_PARALLEL_CLAUSES(t)));
+      break;
+
+    case OMP_TASK:
+      {
+      if (OMP_TASK_BODY (t))
+        {
+          dummy->set_bool("omp_task", true);
+          dummy->set("omp_task_body",
+                     node_emit_json(OMP_TASK_BODY (t)));
+          dummy->set("omp_task_clauses",
+                     omp_clause_emit_json (OMP_TASK_CLAUSES(t)));
+        } else {
+          dummy->set_bool("omp_taskwait", true);
+          dummy->set("omp_taskwait_clauses",
+                     omp_clause_emit_json (OMP_TASK_CLAUSES(t)));
+        }
+        break;
+      }
+
+    dump_omp_clauses_body:
+      dummy->set("omp_clauses", omp_clause_emit_json (OMP_CLAUSES (t)));
+      goto dump_omp_body;
+
+    dump_omp_body:
+      dummy->set("omp_body", node_emit_json (OMP_BODY(t)));
+      dummy->set_bool("is_expr", false);
+      break;
+
+    case OMP_FOR:
+      goto dump_omp_loop;
+      
+    case OMP_SIMD:
+      goto dump_omp_loop;
+
+    case OMP_DISTRIBUTE:
+      goto dump_omp_loop;
+
+    case OMP_TASKLOOP:
+      goto dump_omp_loop;
+
+    case OMP_LOOP:
+      goto dump_omp_loop;
+
+    case OMP_TILE:
+      goto dump_omp_loop;
+
+    case OMP_UNROLL:
+      goto dump_omp_loop;
+
+    case OACC_LOOP:
+      goto dump_omp_loop;
+      
+    dump_omp_loop:
+      dummy->set("omp_for_body",
+                 node_emit_json(OMP_FOR_BODY (t)));
+      dummy->set("omp_for_clauses",
+                 omp_clause_emit_json (OMP_FOR_CLAUSES(t)));
+      dummy->set("omp_for_init",
+                 node_emit_json(OMP_FOR_INIT (t)));
+      dummy->set("omp_for_incr",
+                 node_emit_json(OMP_FOR_INCR (t)));
+      dummy->set("omp_for_pre_body",
+                 node_emit_json(OMP_FOR_PRE_BODY (t)));
+      dummy->set("omp_for_orig_decls",
+                 node_emit_json(OMP_FOR_ORIG_DECLS (t)));
+      break;
+
+    case OMP_TEAMS:
+      dummy->set("omp_teams_body",
+                 omp_clause_emit_json (OMP_TEAMS_BODY(t)));
+      dummy->set("omp_teams_clauses",
+                 omp_clause_emit_json (OMP_TEAMS_CLAUSES(t)));
+      break;
+
+    case OMP_TARGET_DATA:
+      dummy->set("omp_target_data_body",
+                 omp_clause_emit_json (OMP_TARGET_DATA_BODY(t)));
+      dummy->set("omp_target_data_clauses",
+                 omp_clause_emit_json (OMP_TARGET_DATA_CLAUSES(t)));
+      break;
+
+    case OMP_TARGET_ENTER_DATA:
+      dummy->set("omp_target_enter_data_clauses",
+                 omp_clause_emit_json (OMP_TARGET_ENTER_DATA_CLAUSES(t)));
+      break;
+
+    case OMP_TARGET_EXIT_DATA:
+      dummy->set("omp_target_exit_data_clauses",
+                 omp_clause_emit_json (OMP_TARGET_EXIT_DATA_CLAUSES(t)));
+      break;
+
+    case OMP_TARGET:
+      dummy->set("omp_target_body",
+                 omp_clause_emit_json (OMP_TARGET_BODY(t)));
+      dummy->set("omp_target_clauses",
+                 omp_clause_emit_json (OMP_TARGET_CLAUSES(t)));
+      break;
+
+    case OMP_TARGET_UPDATE:
+      dummy->set("omp_target_update_clauses",
+                 omp_clause_emit_json (OMP_TARGET_UPDATE_CLAUSES(t)));
+      break;
+
+    case OMP_SECTIONS:
+      dummy->set("omp_sections_body",
+                 omp_clause_emit_json (OMP_SECTIONS_BODY(t)));
+      dummy->set("omp_sections_clauses",
+                 omp_clause_emit_json (OMP_SECTIONS_CLAUSES(t)));
+      break;
+
+    case OMP_SECTION:
+      dummy->set("omp_section_body",
+                 omp_clause_emit_json (OMP_SECTION_BODY(t)));
+      break;
+
+    case OMP_STRUCTURED_BLOCK:
+      dummy->set("omp_structured_block_body",
+                 omp_clause_emit_json (OMP_STRUCTURED_BLOCK_BODY(t)));
+      break;
+
+    case OMP_SCAN:
+      dummy->set("omp_scan_body",
+                 omp_clause_emit_json (OMP_SCAN_BODY(t)));
+      dummy->set("omp_scan_clauses",
+                 omp_clause_emit_json (OMP_SCAN_CLAUSES(t)));
+      break;
+
+    case OMP_MASTER:
+      dummy->set("omp_master_body",
+                 omp_clause_emit_json (OMP_MASTER_BODY(t)));
+      break;
+
+    case OMP_MASKED:
+      dummy->set("omp_masked_body",
+                 omp_clause_emit_json (OMP_MASKED_BODY(t)));
+      dummy->set("omp_masked_clauses",
+                 omp_clause_emit_json (OMP_MASKED_CLAUSES(t)));
+      break;
+
+    case OMP_TASKGROUP:
+      dummy->set("omp_taskgroup_body",
+                 omp_clause_emit_json (OMP_TASKGROUP_BODY(t)));
+      dummy->set("omp_taskgroup_clauses",
+                 omp_clause_emit_json (OMP_TASKGROUP_CLAUSES(t)));
+      break;
+
+    case OMP_ORDERED:
+      dummy->set("omp_ordered_body",
+                 omp_clause_emit_json (OMP_ORDERED_BODY(t)));
+      dummy->set("omp_ordered_clauses",
+                 omp_clause_emit_json (OMP_ORDERED_CLAUSES(t)));
+      break;
+
+    case OMP_CRITICAL:
+      dummy->set("omp_masked_body",
+                 omp_clause_emit_json (OMP_CRITICAL_BODY(t)));
+      dummy->set("omp_masked_clauses",
+                 omp_clause_emit_json (OMP_CRITICAL_CLAUSES(t)));
+      dummy->set("omp_masked_name",
+                 node_emit_json (OMP_CRITICAL_NAME(t)));
+      break;
+
+    case OMP_ATOMIC:
+      if (OMP_ATOMIC_WEAK (t))
+        dummy->set_bool("omp_atomic_weak", true);
+      else
+        dummy->set_bool("omp_atomic_weak", false);
+      dummy->set("omp_atomic_memory_order",
+                 omp_atomic_memory_order_emit_json(
+		      OMP_ATOMIC_MEMORY_ORDER(t)));
+      dummy->set("op0",
+                 node_emit_json (TREE_OPERAND(t, 0)));
+      dummy->set("op1",
+                 node_emit_json (TREE_OPERAND(t, 1)));
+      break;
+
+    case OMP_ATOMIC_READ:
+      dummy->set("omp_atomic_memory_order",
+                 omp_atomic_memory_order_emit_json(
+		      OMP_ATOMIC_MEMORY_ORDER(t)));
+      dummy->set("op0",
+                 node_emit_json(TREE_OPERAND(t, 0)));
+      break;
+
+    case OMP_ATOMIC_CAPTURE_OLD:
+    case OMP_ATOMIC_CAPTURE_NEW:
+      if (OMP_ATOMIC_WEAK (t))
+        dummy->set_bool("omp_atomic_capture_weak", true);
+      else
+        dummy->set_bool("omp_atomic_capture", true);
+      dummy->set("omp_atomic_memory_order",
+                 omp_atomic_memory_order_emit_json (OMP_ATOMIC_MEMORY_ORDER(t)));
+      dummy->set("op0",
+                 node_emit_json(TREE_OPERAND(t, 0)));
+      dummy->set("op1",
+                 node_emit_json(TREE_OPERAND(t, 1)));
+      break;
+
+    case OMP_SINGLE:
+      dummy->set("omp_single_body",
+                 omp_clause_emit_json (OMP_SINGLE_BODY(t)));
+      dummy->set("omp_single_clauses",
+                 omp_clause_emit_json (OMP_SINGLE_CLAUSES(t)));
+      break;
+
+    case OMP_SCOPE:
+      dummy->set("omp_scope_body",
+                 omp_clause_emit_json (OMP_SCOPE_BODY(t)));
+      dummy->set("omp_scope_clauses",
+                 omp_clause_emit_json (OMP_SCOPE_CLAUSES(t)));
+      break;
+
+    case OMP_CLAUSE:
+      dummy->set("omp_clause",
+                 omp_clause_emit_json(t));
+      break;
+
+    case TRANSACTION_EXPR:
+      if (TRANSACTION_EXPR_OUTER (t))
+	dummy->set_bool ("transaction_expr_outer", true);
+      if (TRANSACTION_EXPR_RELAXED (t))
+	dummy->set_bool ("transaction_expr_relaxed", true);
+      dummy->set("omp_transaction_body", 
+                 node_emit_json (TRANSACTION_EXPR_BODY(t)));
+      break;
+
+    case BLOCK:
+      {
+      tree iter;
+      json::array *subblock, *chain, *vars, *fragment_chain, *nlv_holder;
+      dummy->set_integer ("block #", BLOCK_NUMBER (t));
+      if (BLOCK_SUPERCONTEXT (t))
+        dummy->set("block_supercontext",
+                   node_emit_json(BLOCK_SUPERCONTEXT (t)));
+      if (BLOCK_SUBBLOCKS(t))
+        {
+          subblock = new json::array ();
+          for (iter = BLOCK_SUBBLOCKS (t); iter; iter = BLOCK_CHAIN (t))
+            subblock->append(node_emit_json(iter));
+          dummy->set("block_subblocks", subblock);
+        }
+      if (BLOCK_CHAIN (t))
+        {
+          chain = new json::array ();
+          for (iter = BLOCK_SUBBLOCKS (t); iter; iter = BLOCK_CHAIN (t))
+              chain->append(node_emit_json(iter));
+          dummy->set("block_chain", chain);
+        
+        }
+      if (BLOCK_VARS (t))
+        {
+          vars = new json::array ();
+          for (iter = BLOCK_VARS (t); iter; iter = TREE_CHAIN (t))
+              vars->append(node_emit_json(iter));
+          dummy->set("block_vars", vars);
+        }
+      if (vec_safe_length (BLOCK_NONLOCALIZED_VARS (t)) > 0)
+        {
+          unsigned i;
+          vec<tree, va_gc> *nlv = BLOCK_NONLOCALIZED_VARS (t);
+
+          nlv_holder = new json::array ();
+
+          FOR_EACH_VEC_ELT (*nlv, i, t)
+            {
+              nlv_holder->append(node_emit_json(t));
+            }
+          dummy->set("block_nonlocalized_vars", nlv_holder);
+        }
+      if (BLOCK_ABSTRACT_ORIGIN (t))
+        dummy->set("block_abstract_origin",
+                   node_emit_json (BLOCK_ABSTRACT_ORIGIN (t)));
+      if (BLOCK_FRAGMENT_ORIGIN (t))
+        dummy->set("block_fragment_origin",
+                   node_emit_json (BLOCK_FRAGMENT_ORIGIN (t)));
+
+      if (BLOCK_FRAGMENT_CHAIN (t))
+        {
+          fragment_chain = new json::array ();
+          for( iter=BLOCK_FRAGMENT_CHAIN (t);
+	        iter;
+	        iter=BLOCK_FRAGMENT_CHAIN (t) )
+              fragment_chain->append(node_emit_json(iter));
+          dummy->set("block_fragment_chain", fragment_chain);
+        }
+      }
+      break;
+
+    case DEBUG_BEGIN_STMT:
+      dummy->set_bool("debug_begin", true);
+      break;
+    default:
+      dummy->set_bool("unsupported code", true);
+      dummy->set_string("fallthrough", get_tree_code_name(code));
+      break;
+  }
+  return dummy;
+}
+
+/* Dump the next node in the queue.  */
+
+static void
+dequeue_and_dump (dump_info_p di)
+{
+  dump_queue_p dq;
+  splay_tree_node stn;
+//  dump_node_info_p dni;
+  tree t;
+  json::object* dummy;
+
+  dummy = new json::object ();
+
+  /* Get the next node from the queue.  */
+  dq = di->queue;
+  stn = dq->node;
+  t = (tree) stn->key;
+//  dni = (dump_node_info_p) stn->value;
+
+  /* Remove the node from the queue, and put it on the free list.  */
+  di->queue = dq->next;
+  if (!di->queue)
+    di->queue_end = 0;
+  dq->next = di->free_list;
+  di->free_list = dq;
+
+  dummy = node_emit_json(t);
+  di->json_dump->append(dummy);
+}
+
+/* Dump T, and all its children, on STREAM.  */
+
+void
+dump_node_json (const_tree t, dump_flags_t flags, FILE *stream)
+{
+  struct dump_info di;
+  dump_queue_p dq;
+  dump_queue_p next_dq;
+  pretty_printer pp;
+  /* Initialize the dump-information structure.  */
+  di.stream = stream;
+  di.index = 0;
+  di.column = 0;
+  di.queue = 0;
+  di.queue_end = 0;
+  di.free_list = 0;
+  di.flags = flags;
+  di.node = t;
+  di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
+			     splay_tree_delete_pointers);
+  di.json_dump = new json::array ();
+  /* Queue up the first node.  */
+  queue (&di, t);
+
+  /* Until the queue is empty, keep dumping nodes.  */
+  while (di.queue)
+    dequeue_and_dump (&di);
+
+  di.json_dump->dump(stream, true);
+  fputs("\n", stream);
+  /* Now, clean up.  */
+  for (dq = di.free_list; dq; dq = next_dq)
+    {
+      next_dq = dq->next;
+      free (dq);
+    }
+  splay_tree_delete (di.nodes);
+}
+
+DEBUG_FUNCTION void
+debug_tree_json (tree t)
+{
+  json::object* _x = node_emit_json(t);
+  _x->dump(stderr, true);
+  fprintf(stderr, "\n");
+}
diff --git a/gcc/tree-emit-json.h b/gcc/tree-emit-json.h
new file mode 100644
index 00000000000..ea81466a940
--- /dev/null
+++ b/gcc/tree-emit-json.h
@@ -0,0 +1,82 @@ 
+/* Tree-dumping functionality for intermediate representation.
+   Copyright (C) 1999-2024 Free Software Foundation, Inc.
+   Written by Mark Mitchell <mark@codesourcery.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_TREE_JSON_H
+#define GCC_TREE_JSON_H
+
+#include "splay-tree.h"
+#include "dumpfile.h"
+#define INCLUDE_MEMORY
+#include "json.h"
+
+typedef struct dump_info *dump_info_p;
+
+/* Information about a node to be dumped.  */
+
+typedef struct dump_node_info
+{
+  /* The index for the node.  */
+  unsigned int index;
+  /* Nonzero if the node is a binfo.  */
+  unsigned int binfo_p : 1;
+} *dump_node_info_p;
+
+/* A dump_queue is a link in the queue of things to be dumped.  */
+
+typedef struct dump_queue
+{
+  /* The queued tree node.  */
+  splay_tree_node node;
+  /* The next node in the queue.  */
+  struct dump_queue *next;
+} *dump_queue_p;
+
+/* A dump_info gives information about how we should perform the dump
+   and about the current state of the dump.  */
+
+struct dump_info
+{
+  /* The stream on which to dump the information.  */
+  FILE *stream;
+  /* The original node.  */
+  const_tree node;
+  /* User flags.  */
+  dump_flags_t flags;
+  /* The next unused node index.  */
+  unsigned int index;
+  /* The next column.  */
+  unsigned int column;
+  /* The first node in the queue of nodes to be written out.  */
+  dump_queue_p queue;
+  /* The last node in the queue.  */
+  dump_queue_p queue_end;
+  /* Free queue nodes.  */
+  dump_queue_p free_list;
+  /* The tree nodes which we have already written out.  The
+     keys are the addresses of the nodes; the values are the integer
+     indices we assigned them.  */
+  splay_tree nodes;
+  /* JSON tree holder. Carries everything, each node is a sub-array */
+  json::array* json_dump;
+};
+
+extern json::object* node_emit_json(tree t);
+extern void dump_node_json (const_tree t, dump_flags_t flags, FILE *stream);
+#endif /* ! GCC_TREE_JSON_H */