From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from zmcc-3-mx.zmailcloud.com (zmcc-3-mx.zmailcloud.com [34.200.143.36]) by sourceware.org (Postfix) with ESMTPS id 6CEEB3858D33 for ; Tue, 27 Feb 2024 21:20:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6CEEB3858D33 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=symas.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=symas.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6CEEB3858D33 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=34.200.143.36 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709068828; cv=none; b=HmEr4vfUL3NVx8tFOJZZD88DU8B95OXzFJ+C3Zw9sf0sGIfsERoEFRhVKLKRw5nIGYgoRo9v6oqp47YrWbKGXC6HLY6cntR/9EPY+616lzrjx64/7QwwAe6IvgUiq8ycE9UK1gDy+6Rw7nyBk7a6XpupDoZF41IWhftfvQiw51M= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1709068828; c=relaxed/simple; bh=QSdvzaPsAi67fXYNsM4NVcrZH3a/zT8BKB2RDXBsCj0=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=fZ5zydQroJ4sVjwb1g1tLpAwAcMcarJEiKV+JFz0vWA17sz/3Y04I49fSnJYZe7AmNA6o3TQnp/wMcuMEuXa5uRomzPCFA9HUR7gpQeVZZa2o2sqgyB3pQhDJInIk8zvWB/D8W5CxKMB4LZmszxIZy0NqkLQKB27TIU52PlHb+A= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from zmcc-3.zmailcloud.com (ec2-3-15-255-223.us-east-2.compute.amazonaws.com [3.15.255.223]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by zmcc-3-mx.zmailcloud.com (Postfix) with ESMTPS id C1283E8926; Tue, 27 Feb 2024 15:20:21 -0600 (CST) Received: from zmcc-3.zmailcloud.com (localhost [127.0.0.1]) by zmcc-3-mta-1.zmailcloud.com (Postfix) with ESMTPS id 9D6987C70; Tue, 27 Feb 2024 15:20:21 -0600 (CST) Received: from localhost (localhost [127.0.0.1]) by zmcc-3-mta-1.zmailcloud.com (Postfix) with ESMTP id 8BECA7C92; Tue, 27 Feb 2024 15:20:21 -0600 (CST) Received: from zmcc-3.zmailcloud.com ([127.0.0.1]) by localhost (zmcc-3-mta-1.zmailcloud.com [127.0.0.1]) (amavis, port 10026) with ESMTP id DFrDMzkDJg8g; Tue, 27 Feb 2024 15:20:21 -0600 (CST) Received: from zmcc-3-mailbox-1.zmailcloud.com (zmcc-3-mailbox-1.zmailcloud.com [172.31.28.18]) by zmcc-3-mta-1.zmailcloud.com (Postfix) with ESMTP id 5C6BD7C70; Tue, 27 Feb 2024 15:20:21 -0600 (CST) From: Robert Dubner To: "Richard Biener" Cc: References: <009401da65ae$8790a750$96b1f5f0$@symas.com> In-Reply-To: Subject: RE: [PATCH] developer option: -fdump-generic-nodes; initial incorporation Thread-Topic: [PATCH] developer option: -fdump-generic-nodes; initial incorporation Date: Tue, 27 Feb 2024 15:20:21 -0600 (CST) Message-ID: <09de01da69c2$c5f57260$51e05720$@symas.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: Microsoft Outlook 16.0 X-Mailer: Zimbra 9.0.0_GA_4583 (Zimbra-ZCO/9.0.0.1939 (10.0.22621 en-US) P2008 Te1e8 R7850) Thread-Index: AQHwCI8fltjtD78rfKIAn3Wo5UMXNAIhECjssOIiBHA= Content-Language: en-us Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-9.1 required=5.0 tests=BAYES_00,GIT_PATCH_0,KAM_DMARC_STATUS,KAM_SHORT,RCVD_IN_DNSWL_LOW,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Richard, Thank you very much for your comments. When I set out to create the capability, I had a "specification" in mind. I didn't have a clue how to create a GENERIC tree that could be fed to th= e=20 middle end in a way that would successfully result in an executable. And= I=20 needed to be able to do that in order to proceed with the project of=20 creating a COBOL front end. So, I came up with the idea of using GCC to compile simple programs, and = to=20 hook into the compiler to examine the trees fed to the middle end, and to= =20 display those trees in the human-readable format I needed to understand=20 them. And that's what I did. My first incarnation generated pure text files, and I used that to get=20 going. After a while I realized that when I used the output file, I was spending= a=20 lot of time searching through the text files. And I had the brainstorm!=20 Hyperlinks! HTML files! We have the technology! So, I created the .HTM= L=20 files as well. I found this useful to the point of necessity in order to learn how to=20 generate the GENERIC trees. I believe it would be equally useful to the=20 next developer who, for whatever reason, needs to understand, on a "You n= eed=20 to learn the alphabet before you can learn how to read" level, what the=20 middle end requires from a GENERIC tree generated by a front end. But I've never used it on a complex program. I've used it only to learn h= ow=20 to create the GENERIC nodes for very particular things, and so I would us= e=20 the -fdump-generic-nodes feature on a very simple C program that=20 demonstrated, in isolation, the feature I needed. Once I figured it out,= I=20 would create front end C routines or macros that used the tree.h/tree.cc=20 features to build those GENERIC trees, and then I would move on. I decided to offer it up here, in order to to learn how to create patches= =20 and to get to know the people and the process, as well as from the desire to share i= t.=20 And instantly I got the "How about a machine-readable format?" comments.=20 Which are reasonable. So, because it wasn't hard, I hacked at the existi= ng=20 code to create a JSON output. (But I remind you that up until now, nobod= y=20 seems to have needed a JSON representation.) And your observation that the human readable representation could be made= =20 from the JSON representation is totally accurate. But that wasn't my specification. My specification was "A tool so that a= =20 human being can examine a simple GENERIC tree to learn how it's done." But it seems to me that we are now moving into the realm of a new=20 specification. Said another way: To go from "A human readable representation of a simpl= e=20 GENERIC tree" to "A machine readable JSON representation of an arbitraril= y=20 complex GENERIC tree, from which a human readable representation can be=20 created" means, in effect, starting over on a different project that I do= n't=20 need. I already *have* a project that I am working on -- the COBOL front= =20 end. The complexity of GENERIC trees is, in my experienced opinion, an obstacl= e=20 for the creation of front ends. The GCC Internals document has a lot of=20 information, but to go from it to a front end is like using the maintenan= ce=20 manual for an F16 fighter to try to learn to fly the aircraft. The program "main(){}" generates a tree with over seventy nodes. I see n= o=20 way to document why that's true; it's all arbitrary in the sense that "th= is=20 is how GCC works". -fdump-generic-nodes made it possible for me to figur= e=20 out how those nodes are connected and, thus, how to create a new front en= d.=20 I figure that other developers might find it useful, as well. I guess I am saying that I am not, at this time, able to work on a whole=20 different tool. I think what I have done so far does something useful th= at=20 doesn't seem to otherwise exist in GCC. I suppose the question for you is, "Is it useful enough?" I won't be offended if the answer is "No" and I hope you won't be offende= d=20 by my not having the bandwidth to address your very thoughtful and valid=20 observations about how it could be better. -----Original Message----- From: Richard Biener Sent: Tuesday, February 27, 2024 04:11 To: Robert Dubner Cc: gcc-patches@gcc.gnu.org Subject: Re: [PATCH] developer option: -fdump-generic-nodes; initial=20 incorporation On Thu, Feb 22, 2024 at 5:46=E2=80=AFPM Robert Dubner = wrote: > > As part of an effort to learn how create a GENERIC tree in order to > implement a > COBOL front end, I created the dump_generic_nodes(), which accepts a > function_decl at the point it is provided to the middle end. The routi= ne > generates three files. One is ASCII, the second is HTML; they contain = the > tree > in a human-readable form. The third is JSON. > > This commit modifies common.opt to accept the -fdump-generic-nodes > command-line > option, creates the dump-generic-nodes.cc and .h files to implement it, > and > inserts a call to the dump_generic_nodes() function near the top of > gimplify_function_tree() in gcc/gimplify.cc While I think that's good and probably the best you can do in language independent code GCCs 'GENERIC' is inherently frontend specific (only GIMPLE is no longer). The gimplifier you hook into eventually relies on the 'gimplify_expr' language hook to deal with frontend specifi= c tree codes and there might be auxiliary info in the language-specific portions of types and decls (DECL_LANG_SPECIFIC, TYPE_LANG_SPECIFIC). That's a caveat only, it might mean that in some cases a 'dump_generic_to_json' language hook might be a nice thing to have. Note this is likely only a "problem" for frontends not having their own internal AST representation they lower to GENERIC; first and foremost the C and C++ language frontends - I'm not sure of others here, but the presence of ./ada/gcc-interface/ada-tree.def ./c/c-tree.def ./cp/cp-tree.def ./d/d-tree.def ./m2/m2-tree.def ./objc/objc-tree.def suggests that "issue" might be wide-spread. > This patch has been tested on X86_64-linux-gnu. I haven't tried to > provide > testcases for the automated system because 1) I haven't learned how to = do > that, > and 2), I am not sure how to test this feature. On the one hand, the > compiler > isn't affected when the switch isn't present; when it is present it see= ms > to > work on simple source code. I think this is a useful feature. I do wonder whether it makes more sens= e to only implement JSON dumping inside the compiler and leave html and text output to postprocessing that. That avoids diverging informatio= n detail and should reduce the amount of code to maintain. Scripts to perform analysis/transform of such JSON could be contributed into the contrib/ directory. To follow general filename standards for auxiliary files you should prepend the filename(s) you dump to with 'aux_base_name', the chance of accidentially trashing users files is then reduced a lot. It might be that with JSON it's reasonable to output a single file per TU only, avoiding issues with say C++ function overloading and possible clashes on filenames. https://gcc.gnu.org/contribute.html#standards lists some bits that we expect to help common appearance of code and maintainance. For example a lot of your functions have no function-level comment documenting them. > Legal requirements: The FSF has on file an "employer disclaimer" for m= e. > > I am using the "Signed off by" tag in an attempt to cover the legal bas= es; > I > trust I will be apprised of anything else that needs to be done. I think that's OK. > gcc/ChangeLog: > > * developer options: -fdump-generic-nodes initial incorporation > > Signed-off-by: Robert Dubner > --- > gcc/Makefile.in | 3 +- > gcc/common.opt | 4 + > gcc/dump-generic-nodes.cc | 1958 +++++++++++++++++++++++++++++++++++++ > gcc/dump-generic-nodes.h | 26 + > gcc/gimplify.cc | 3 + > 5 files changed, 1993 insertions(+), 1 deletion(-) > create mode 100644 gcc/dump-generic-nodes.cc > create mode 100644 gcc/dump-generic-nodes.h > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index a74761b7ab3..81922b0884c 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1441,6 +1441,7 @@ OBJS =3D \ > domwalk.o \ > double-int.o \ > dse.o \ > + dump-generic-nodes.o \ > dumpfile.o \ > dwarf2asm.o \ > dwarf2cfi.o \ > @@ -3857,7 +3858,7 @@ PLUGIN_HEADERS =3D $(TREE_H) $(CONFIG_H) $(SYSTEM= _H) > coretypes.h $(TM_H) \ > hash-set.h dominance.h cfg.h cfgrtl.h cfganal.h cfgbuild.h cfgcleanu= p.h > \ > lcm.h cfgloopmanip.h file-prefix-map.h builtins.def $(INSN_ATTR_H) \ > pass-instances.def params.list $(srcdir)/../include/gomp-constants.h= \ > - $(EXPR_H) $(srcdir)/analyzer/*.h > + $(EXPR_H) $(srcdir)/analyzer/*.h dump-generic-nodes.h > > # generate the 'build fragment' b-header-vars > s-header-vars: Makefile > diff --git a/gcc/common.opt b/gcc/common.opt > index 51c4a17da83..751b9b1f0cc 100644 > --- a/gcc/common.opt > +++ b/gcc/common.opt > @@ -1583,6 +1583,10 @@ fdump-passes > Common Var(flag_dump_passes) Init(0) > Dump optimization passes. > > +fdump-generic-nodes > +Common Var(flag_dump_generic_nodes) Init(0) > +Dump GENERIC trees for each function in three files: .nodes, > .nodes.html, and .json > + > fdump-unnumbered > Common Var(flag_dump_unnumbered) > Suppress output of instruction numbers, line number notes and addresse= s > in debugging dumps. > diff --git a/gcc/dump-generic-nodes.cc b/gcc/dump-generic-nodes.cc > new file mode 100644 > index 00000000000..d44119116d2 > --- /dev/null > +++ b/gcc/dump-generic-nodes.cc > @@ -0,0 +1,1958 @@ > +/* Prints out a tree of generic/gimple nodes in human readable form, b= oth > in > + straight text and in HTML. The entry point is dump_generic_nodes(). > + > + Copyright(C) 1990-2024 Free Software Foundation, Inc. > + > +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 > +. */ > + > +#include "config.h" > +#include "system.h" > +#include "coretypes.h" > +#include "tm.h" > +#include "tree.h" > +#include "cgraph.h" > +#include "diagnostic.h" > +#include "varasm.h" > +#include "print-rtl.h" > +#include "stor-layout.h" > +#include "langhooks.h" > +#include "tree-iterator.h" > +#include "gimple-pretty-print.h" > +#include "tree-cfg.h" > +#include "dumpfile.h" > + > +#undef DEFTREESTRUCT > +#define DEFTREESTRUCT(VAL, NAME) NAME, > +static const char *ts_enum_names[] =3D > + { > + #include "treestruct.def" > + }; > +#undef DEFTREESTRUCT > + > +#define ADD_FLAG(accessor,text)if(accessor(node)){strcat(ach," " text)= ;} > + > +static FILE *ftext =3D NULL; > +static FILE *fhtml =3D NULL; > +static FILE *fjson =3D NULL; > + > +static int json_level =3D 0; > +static const char *json_comma; > +static const int spaces_per_indent =3D 2; > + > +static void rjd_print_node(tree node); > + > +static int phase =3D 1; > + > +/* Define the hash table of nodes already seen. > + Such nodes are not repeated; brief cross-references are used. */ > + > +struct TREE > + { > + tree this_node; > + int seen; > + } ; > + > +static struct TREE *nodes =3D NULL; > +static int GV_size_of_tree =3D 0; > +static int GV_number_of_nodes =3D 0; > + > +static void > +json_fprintf(const char *format, ...) __attribute__ ((format (printf, = 1, > 2))); > + > +static void > +json_fprintf(const char *format, ...) > +{ > + char ach1[2048]; > + if( phase =3D=3D 2 ) > + { > + va_list args; > + va_start(args, format); > + vsnprintf(ach1, sizeof(ach1), format, args); > + va_end(args); > + fprintf(fjson, "%s", ach1); > + } > +} > + > +static void > +json_indent() > +{ > + for(int i=3D0; i + { > + json_fprintf(" "); > + } > +} > + > +static void > +json_newline() > +{ > + json_fprintf("%s\n", json_comma); > + json_indent(); > +} > + > +static int > +find_node_in_nodes(tree node) > +{ > + // This is an O(n^2) abomination. At a suitable time, replace it wi= th > a > + // hashed map! > + int retval =3D -1; > + gcc_assert(GV_number_of_nodes <=3D GV_size_of_tree); > + for(int i=3D0; i + { > + if( nodes[i].this_node =3D=3D node ) > + { > + retval =3D i; > + break; > + } > + } > + return retval; > +} > + > +static int > +add_node_to_nodes(tree node) > +{ > + // Assume we know the node isn't there yet: > + gcc_assert(GV_number_of_nodes <=3D GV_size_of_tree); > + if( GV_number_of_nodes =3D=3D GV_size_of_tree ) > + { > + // We've run out of room. Double the number of nodes: > + GV_size_of_tree *=3D 2; > + if( GV_size_of_tree =3D=3D 0 ) > + { > + GV_size_of_tree =3D 64; > + } > + struct TREE *newnodes =3D > + (struct TREE *)xmalloc( GV_size_of_tree * sizeof(struct > TREE) ); > + memcpy(newnodes,nodes, GV_number_of_nodes * sizeof(struct TREE)); > + free(nodes); > + nodes =3D newnodes; > + } > + gcc_assert(GV_number_of_nodes <=3D GV_size_of_tree); > + nodes[GV_number_of_nodes].this_node =3D node; > + nodes[GV_number_of_nodes].seen =3D 0; > + GV_number_of_nodes +=3D 1; > + return GV_number_of_nodes-1; > +} > + > +#pragma GCC diagnostic ignored "-Wsuggest-attribute=3Dformat" > + > +static void > +rjd_fprintf(const char *format, ...) > +{ > + // NOTE: I painfully learned that mixing fprintf() and vfprintf() ca= lls > + // can result in hard-to-find memory allocation bugs. Probably wort= h > + // tracking down, but the the problem shows up in the libc6 library > + // routines. > + char ach1[2048]; > + char ach2[4196]; > + char ach3[4196]; > + if( phase =3D=3D 2 ) > + { > + va_list args; > + va_start(args, format); > + vsnprintf(ach1, sizeof(ach1), format, args); > + va_end(args); > + > + fprintf(ftext, "%s", ach1); > + > + // Copy ach1 to ach2, replacing '\n' with "
" > + char *p1 =3D ach1; > + char *p2 =3D ach2; > + > + while( *p1 ) > + { > + if(*p1 =3D=3D '\n') > + { > + p1 +=3D 1; > + *p2 =3D '\0'; > + strcat(p2, "
"); > + p2 =3D ach2 + strlen(ach2); > + } > + else > + { > + *p2++ =3D *p1++; > + } > + } > + size_t ach1_length =3D strlen(ach1); > + > + // To make the HTML more-or-less readable, if ach1 ends with a > newline, > + // make ach2 end with a newline as well. > + if( ach1_length && ach1[ach1_length-1] =3D=3D '\n' ) > + { > + *p2++ =3D '\n'; > + } > + *p2++ =3D '\0'; > + > + // We now look for NodeNumberNNN and replace it with > + // NodeNumberNNN > + > + char *pleft =3D strstr(ach2, "NodeNumber"); > + if( pleft ) > + { > + char *pright =3D pleft + strlen("NodeNumber"); > + while( *pright >=3D '0' && *pright <=3D '9' ) > + { > + pright +=3D 1; > + } > + memset(ach3, 0, sizeof(ach3)); > + memcpy(ach3, ach2, pleft - ach2); > + strcat(ach3, " + char *p =3D ach3 + strlen(ach3); > + memcpy(p, pleft, pright-pleft); > + strcat(ach3,"\">"); > + p =3D ach3 + strlen(ach3); > + memcpy(p, pleft, pright-pleft); > + p =3D ach3 + strlen(ach3); > + strcat(ach3,""); > + p =3D ach3 + strlen(ach3); > + strcpy(p, pright); > + strcpy(ach2, ach3); > + } > + > + fprintf(fhtml, "%s", ach2); > + } > +} > + > +#define NOT_QUOTED false > +static void > +json_namevalue(const char *name, const char *value, bool quoted =3D tr= ue) > +{ > + if( phase =3D=3D 2 ) > + { > + json_newline(); > + if( quoted ) > + { > + json_fprintf("\"%s\":\"%s\"", name, value); > + } > + else > + { > + json_fprintf("\"%s\":%s", name, value); > + } > + } > +} > + > +static void > +html_boilerplate(char *title=3DNULL) > +{ > + if( fhtml ) > + { > + if( title ) > + { > + fprintf(fhtml, > + "\n" > + "\n" > + " \n" > + " \n" > + " %s\n" > + " \n" > + " \n" > + " \n", title); > + } > + else > + { > + fprintf(fhtml, "%s", > + " \n" > + "\n"); > + } > + } > +} > + > +/* Print a node in brief fashion*/ > + > +static void > +print_name(const char *prefix, tree node) > +{ > + if( node && TREE_CODE_CLASS(TREE_CODE(node)) =3D=3D tcc_declaration = ) > + { > + tree name =3D DECL_NAME(node); > + if( name ) > + { > + rjd_fprintf("%s\"%s\"", prefix, IDENTIFIER_POINTER(name)); > + } > + } > +} > + > +static void > +rjd_subtree(const char *subtree_name, tree subtree) > +{ > + if( subtree ) > + { > + if( phase =3D=3D 1 ) > + { > + // Make sure the subtree is in the list of nodes. And, yes, thi= s > + // is a potential headachy recursivy thingummy. But computers a= re > + // good at that. > + rjd_print_node(subtree); > + > + int subtree_node_number =3D find_node_in_nodes(subtree); > + if( subtree_node_number =3D=3D -1 ) > + { > + printf("Run in circles, scream and shout!\n"); > + exit(1); > + } > + > + } > + else if( phase =3D=3D 2 ) > + { > + char ach[512]; > + int node_number =3D find_node_in_nodes(subtree); > + if( node_number >=3D 0 ) > + { > + rjd_fprintf("%s: NodeNumber%d", subtree_name, node_number); > + > + // Handle a few subthings that are very common, and useful to > see: > + gcc_assert(node_number < GV_number_of_nodes > + && GV_number_of_nodes <=3D GV_size_of_tree); > + tree subnode =3D nodes[node_number].this_node; > + if( subnode ) > + { > + enum tree_code subcode =3D TREE_CODE(subnode); > + > + // After the NodeNumber, print the code name. Unless it is = an > + // integer_cst, because we convert that to int32 or uint64 > later. > + if( subcode !=3D INTEGER_CST ) > + { > + rjd_fprintf(" %s", get_tree_code_name(subcode)); > + } > + > + if( subcode =3D=3D IDENTIFIER_NODE && IDENTIFIER_POINTER(sub= node) ) > + { > + rjd_fprintf(" \"%s\"", IDENTIFIER_POINTER(subnode)); > + } > + > + print_name(" ", subnode); > + > + if( subcode =3D=3D INTEGER_CST ) > + { > + tree int_cst_type =3D TREE_TYPE(subnode); > + tree_code int_cst_type_code =3D TREE_CODE(int_cst_type); > + > + if( int_cst_type_code =3D=3D POINTER_TYPE ) > + { > + rjd_fprintf(" pointer"); > + } > + else if( int_cst_type_code =3D=3D INTEGER_TYPE) > + { > + // The int_cst_type is an integer_type, so... > + tree min_value =3D TYPE_MIN_VALUE_RAW(int_cst_type); > + print_dec(wi::to_wide(min_value), > + ach, > + TYPE_SIGN(TREE_TYPE(min_value))); > + if( strcmp( ach, "0") ) > + { > + rjd_fprintf(" int",ach); > + } > + else > + { > + rjd_fprintf(" uint",ach); > + } > + > + tree size_in_bits =3D TYPE_SIZE(int_cst_type); > + > + print_dec(wi::to_wide(size_in_bits), > + ach, > + TYPE_SIGN(TREE_TYPE(size_in_bits))); > + rjd_fprintf(ach); > + > + print_dec(wi::to_wide(subnode), > + ach, TYPE_SIGN(TREE_TYPE(subnode))); > + } > + > + print_dec(wi::to_wide(subnode), > + ach, > + TYPE_SIGN(TREE_TYPE(subnode))); > + rjd_fprintf(" %s",ach); > + } > + > + if( subcode =3D=3D DECL_EXPR ) > + { > + int len =3D TREE_OPERAND_LENGTH(subnode); > + if( len ) > + { > + print_name(" ", TREE_OPERAND(subnode, 0)); > + } > + } > + > + if( subcode =3D=3D CALL_EXPR ) > + { > + int len =3D TREE_OPERAND_LENGTH(subnode); > + if( len > 1) > + { > + tree addr_expression =3D TREE_OPERAND(subnode, 1); > + int len2 =3D TREE_OPERAND_LENGTH(addr_expression); > + if( len2 ) > + { > + print_name(" ", TREE_OPERAND(addr_expression, 0)); > + } > + } > + } > + > + if( subcode =3D=3D ADDR_EXPR ) > + { > + int len =3D TREE_OPERAND_LENGTH(subnode); > + if( len > 0) > + { > + print_name(" ", TREE_OPERAND(subnode, 0)); > + } > + } > + > + if( subcode =3D=3D MODIFY_EXPR ) > + { > + int len =3D TREE_OPERAND_LENGTH(subnode); > + if( len > 0) > + { > + tree target =3D TREE_OPERAND(subnode, 0); > + tree_code target_code =3D TREE_CODE(target); > + tree_code_class target_code_class =3D > TREE_CODE_CLASS(target_code); > + if( target_code_class =3D=3D tcc_declaration ) > + { > + print_name(" ", target); > + } > + else if( target_code =3D=3D COMPONENT_REF > + && target_code_class =3D=3D > tcc_reference ) > + { > + int len =3D TREE_OPERAND_LENGTH(target); > + tree structure =3D NULL_TREE; > + tree field =3D NULL_TREE; > + if( len > 0 ) > + { > + structure =3D TREE_OPERAND(target, 0); > + } > + if( len > 1 ) > + { > + field =3D TREE_OPERAND(target, 1); > + } > + print_name(" ", structure); > + print_name("::", field); > + } > + } > + } > + > + rjd_fprintf("\n"); > + } > + // In contrast, for the JSON output, we just want the node > number: > + // But we need to intervene in the case where the subtree name > starts > + // off with "operand[nnn]". We are putting them in JSON array= sm, > so we > + // need to eliminate that name > + if( strstr(subtree_name, "constructor_elt[") !=3D subtree_name= ) > + { > + // constructors are handled separately because they have bot= h > index > + // and value members. Search for "constructor_elt" to find > that code. > + if( strstr(subtree_name, "operand[") =3D=3D subtree_name > + || strstr(subtree_name, "tree_vector_element[") =3D=3D > subtree_name > + || strstr(subtree_name, "statement_list[") =3D=3D subtre= e_name > + || strstr(subtree_name, "nonlocalized_var[") =3D=3D > subtree_name > + ) > + { > + // We are elminating the subtree name > + json_newline(); > + } > + else > + { > + json_namevalue(subtree_name, "", NOT_QUOTED); > + } > + json_fprintf("{\"node\":%d}", node_number); > + } > + } > + else > + { > + // This can happen as a result of certain compilation > + // errors. Just ignore them. > + } > + } > + } > + else > + { > + if( strstr(subtree_name, "operand[") =3D=3D subtree_name ) > + { > + json_newline(); > + json_fprintf("{\"node\":null}"); > + } > + > + } > + > +} > + > +static void > +json_flags(const char *name, const char *ach) > +{ > + const char *p =3D ach+1; // Skip past the initial space > + json_namevalue(name, "", NOT_QUOTED); > + json_level +=3D 1; > + json_comma =3D ""; > + json_fprintf("\n"); > + json_indent(); > + json_fprintf("{"); > + > + while( *p ) > + { > + const char *pend =3D strchr(p, ' '); > + if( !pend ) > + { > + pend =3D p + strlen(p); > + } > + char achName[256]; > + char *d =3D achName; > + while(p < pend ) > + { > + *d++ =3D *p++; > + } > + *d++=3D '\0'; > + if( *p =3D=3D ' ' ) > + { > + p +=3D 1; > + } > + json_namevalue(achName, "true", NOT_QUOTED); > + json_comma =3D ","; > + } > + json_fprintf("\n"); > + json_indent(); > + json_fprintf("}"); > + > + json_level -=3D 1; > + json_comma =3D ","; > +} > + > +static void > +json_start_array(const char *name) > +{ > + // We will set up a JSON array of operands > + json_namevalue(name,"", NOT_QUOTED); > + json_fprintf("\n"); > + json_level +=3D 1; > + json_indent(); > + json_fprintf("["); > + json_comma =3D ""; > +} > +static void > +json_finish_array() > +{ > + json_fprintf("\n"); > + json_indent(); > + json_fprintf("]"); > + json_level -=3D 1; > + json_comma =3D ","; > +} > + > +static void > +rjd_print_node(tree node) > +{ > + char ach[4096]; > + enum tree_code_class tclass; > + int len; > + int i; > + expanded_location xloc; > + enum tree_code code; > + > + if(node =3D=3D 0) > + { > + // When handled a NULL, just return > + return; > + } > + > + int node_number =3D find_node_in_nodes(node); > + if( phase =3D=3D 1 ) > + { > + if( node_number !=3D -1 ) > + { > + // We're building the list of nodes, and we've already processed > this > + // node: > + return; > + } > + > + // We are building the list of nodes, and this is a new one: > + node_number =3D add_node_to_nodes(node); > + } > + // From here on out, we know that node_number is valid, whether in > + // phase 1 or phase 2 > + > + code =3D TREE_CODE(node); > + > + /* It is unsafe to look at any other fields of a node with ERROR_MAR= K > or > + invalid code. */ > + if(code =3D=3D ERROR_MARK || code >=3D MAX_TREE_CODES) > + { > + rjd_fprintf("This node is unsafe. The reported TREE_CODE is > %d\n",code); > + return; > + } > + > + tclass =3D TREE_CODE_CLASS(code); > + > + /* Announce the coming of a new node: */ > + if( phase=3D=3D2 && fhtml ) > + { > + fprintf(fhtml, "

\n", node_number); > + } > + rjd_fprintf("***********************************This is > NodeNumber%d\n", > + node_number); > + > + /* Print the NodeNumber in a more canonical form: */ > + rjd_fprintf("(%p) NodeNumber%d\n", node, node_number); > + > + // Print the tree_code for this node > + rjd_fprintf("tree_code: %s\n", get_tree_code_name(code)); > + json_namevalue("tree_code", get_tree_code_name(code)); > + > + // It might be useful to see the class > + const char *classtxt; > + switch(tclass) > + { > + case tcc_exceptional: > + classtxt =3D "tcc_exceptional"; > + break; > + case tcc_constant: > + classtxt =3D "tcc_constant"; > + break; > + case tcc_type: > + classtxt =3D "tcc_type"; > + break; > + case tcc_declaration: > + classtxt =3D "tcc_declaration"; > + break; > + case tcc_reference: > + classtxt =3D "tcc_reference"; > + break; > + case tcc_comparison: > + classtxt =3D "tcc_comparison"; > + break; > + case tcc_unary: > + classtxt =3D "tcc_unary"; > + break; > + case tcc_binary: > + classtxt =3D "tcc_binary"; > + break; > + case tcc_statement: > + classtxt =3D "tcc_statement"; > + break; > + case tcc_vl_exp: > + classtxt =3D "tcc_vl_exp"; > + break; > + case tcc_expression: > + classtxt =3D "tcc_expression"; > + break; > + default: > + gcc_unreachable(); > + break; > + } > + rjd_fprintf("tree_code_class: %s\n", classtxt); > + json_namevalue("tree_code_class", classtxt); > + > + int required[64]; > + int processed[64]; > + for(int i=3D0; i<64; i++) > + { > + required[i] =3D CODE_CONTAINS_STRUCT(code, i); > + processed[i] =3D 0; > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_BASE) ) > + { > + processed[TS_BASE] =3D 1; > + // There are 16 bits in TS_BASE. The trouble is, they have > + // different meanings for different codes; see the extensive > + // comment in tree-core.h > + strcpy(ach, ""); > + if( tclass !=3D tcc_type && TREE_SIDE_EFFECTS(node) ) > + { > + strcat(ach," side_effects"); > + } > + if( tclass !=3D tcc_type && TREE_CONSTANT(node) ) > + { > + strcat(ach," constant"); > + } > + if( TREE_ADDRESSABLE(node) ) > + { > + strcat(ach," addressable"); > + } > + if( TREE_THIS_VOLATILE(node) ) > + { > + strcat(ach," volatile"); > + } > + if( tclass !=3D tcc_type && TREE_READONLY(node) ) > + { > + strcat(ach," readonly"); > + } > + if( TREE_ASM_WRITTEN(node) ) > + { > + strcat(ach," asm_written"); > + } > + if( TREE_NO_WARNING(node) ) > + { > + strcat(ach," nowarning"); > + } > + if( TREE_VISITED(node) ) > + { > + strcat(ach," visited"); > + } > + > + if( TREE_USED(node) ) > + { > + strcat(ach," used"); > + } > + if( TREE_NOTHROW(node) ) > + { > + strcat(ach," nothrow"); > + } > + if( TREE_STATIC(node) ) > + { > + strcat(ach," static"); > + } > + if( TREE_PUBLIC(node) ) > + { > + strcat(ach," public"); > + } > + if( TREE_PRIVATE(node) ) > + { > + strcat(ach," private"); > + } > + if( TREE_PROTECTED(node) ) > + { > + strcat(ach," protected"); > + } > + if( TREE_DEPRECATED(node) ) > + { > + strcat(ach," deprecated"); > + } > + if( node->base.default_def_flag ) //There isn't a TREE_DEFAULT_DEF > macro > + { > + strcat(ach," default_def"); > + } > + if( tclass =3D=3D tcc_constant ) > + { > + if( TREE_OVERFLOW(node) ) > + { > + strcat(ach," overflow"); > + } > + } > + if( tclass =3D=3D tcc_type ) > + { > + ADD_FLAG(TYPE_UNSIGNED, "unsigned"); > + ADD_FLAG(TYPE_PACKED, "packed"); > + ADD_FLAG(TYPE_USER_ALIGN, "user_align"); > + ADD_FLAG(TYPE_NAMELESS, "nameless"); > + ADD_FLAG(TYPE_ATOMIC, "atomic"); > + } > + if( strlen(ach) ) > + { > + rjd_fprintf("base_flags:%s\n", ach); > + json_flags("base_flags", ach); > + } > + } > + > + if( tclass =3D=3D tcc_type ) > + { > + sprintf(ach, "%s(%u)", > + GET_MODE_NAME(TYPE_MODE(node)),(int)TYPE_MODE(node)); > + rjd_fprintf("machine_mode: %s\n", ach); > + json_namevalue("machine_mode", ach); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_TYPED) ) > + { > + processed[TS_TYPED] =3D 1; > + rjd_subtree("type", TREE_TYPE(node)); > + if( tclass =3D=3D tcc_type ) > + { > + sprintf(ach, "%u", (int)TYPE_ADDR_SPACE(node)); > + rjd_fprintf("address_space:%s\n", ach); > + json_namevalue("address_space", ach); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_DECL_MINIMAL) ) > + { > + processed[TS_DECL_MINIMAL] =3D 1; > + rjd_subtree("name", DECL_NAME(node)); > + rjd_subtree("context", DECL_CONTEXT(node)); > + xloc =3D expand_location(DECL_SOURCE_LOCATION(node)); > + if( xloc.file ) > + { > + sprintf(ach, "%s:%d:%d", xloc.file, xloc.line, xloc.column); > + rjd_fprintf("source_location: %s\n", ach); > + json_namevalue("source_location", ach); > + } > + sprintf(ach, "%d", DECL_PT_UID(node)); > + rjd_fprintf("uid: %s\n", ach); > + json_namevalue("uid", ach, NOT_QUOTED); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_DECL_COMMON) ) > + { > + processed[TS_DECL_COMMON] =3D 1; > + rjd_subtree("size(in bits)", DECL_SIZE(node)); > + rjd_subtree("size_unit(in bytes)", DECL_SIZE_UNIT(node)); > + > + const char *p; > + switch(code) > + { > + case FUNCTION_DECL: > + p =3D "initial(bindings)"; > + break; > + case TRANSLATION_UNIT_DECL: > + p =3D "initial(block)"; > + break; > + case VAR_DECL: > + p =3D "initial value"; > + break; > + default: > + p =3D "initial"; > + break; > + } > + rjd_subtree(p, DECL_INITIAL(node)); > + rjd_subtree("attributes", DECL_ATTRIBUTES(node)); > + rjd_subtree("abstract_origin", DECL_ABSTRACT_ORIGIN(node)); > + > + sprintf(ach, "%s(%u)", > GET_MODE_NAME(DECL_MODE(node)),(int)DECL_MODE(node)); > + rjd_fprintf("machine_mode: %s\n", ach); > + json_namevalue("machine_mode", ach); > + > + strcpy(ach, ""); > + if( DECL_NONLOCAL(node) ) > + { > + strcat(ach," nonlocal"); > + } > + if( DECL_VIRTUAL_P(node) ) > + { > + strcat(ach," virtual"); > + } > + if( DECL_IGNORED_P(node) ) > + { > + strcat(ach," ignored"); > + } > + if( DECL_ABSTRACT_P(node) ) > + { > + strcat(ach," abstrac"); > + } > + if( DECL_ARTIFICIAL(node) ) > + { > + strcat(ach," artificial"); > + } > + if( DECL_PRESERVE_P(node) ) > + { > + strcat(ach," preserve"); > + } > + if( code =3D=3D VAR_DECL && DECL_DEBUG_EXPR(node) ) > + { > + strcat(ach," debug_expr_is_from"); > + } > + if( strlen(ach) ) > + { > + rjd_fprintf("decl_flags:%s\n",ach); > + json_flags("decl_flags", ach); > + } > + > + if( code =3D=3D FIELD_DECL ) > + { > + sprintf(ach, "%u", (int)DECL_OFFSET_ALIGN(node)); > + rjd_fprintf("offset_align: %s\n", ach); > + json_namevalue("offset_align", ach); > + } > + sprintf(ach, "%u", (int)DECL_ALIGN(node)); > + rjd_fprintf("align: %u\n", ach); > + json_namevalue("align", ach, NOT_QUOTED); > + > + sprintf(ach, "%u", (int)DECL_WARN_IF_NOT_ALIGN(node)); > + rjd_fprintf("warn_if_not_align: %s\n", ach); > + json_namevalue("warn_if_not_align", ach, NOT_QUOTED); > + > + sprintf(ach, "%u", (int)DECL_PT_UID(node)); > + rjd_fprintf("pt_uid: %s\n", ach); > + json_namevalue("pt_uid", ach, NOT_QUOTED); > + > + if( DECL_LANG_SPECIFIC(node) ) > + { > + rjd_fprintf("lang_specific(pointer): > %p\n",DECL_LANG_SPECIFIC(node)); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_DECL_WRTL) ) > + { > + processed[TS_DECL_WRTL] =3D 1; > + if( DECL_RTL_SET_P(node) ) > + { > + rjd_fprintf("DECL_RTL for NODE has already been set\n"); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_DECL_WITH_VIS) ) > + { > + processed[TS_DECL_WITH_VIS] =3D 1; > + rjd_subtree("raw_assembler_name", DECL_ASSEMBLER_NAME_RAW(node)); > + if( DECL_LANG_SPECIFIC(node) ) > + { > + rjd_fprintf("symtab_node(pointer): %p\n",DECL_LANG_SPECIFIC(node= )); > + } > + strcpy(ach, ""); > + if( code =3D=3D VAR_DECL ) > + { > + if( DECL_DEFER_OUTPUT(node) ) > + { > + strcat(ach, " defer_output"); > + } > + if( DECL_HARD_REGISTER(node) ) > + { > + strcat(ach, " hard_register"); > + } > + if( DECL_COMMON(node) ) > + { > + strcat(ach, " common"); > + } > + if( DECL_IN_TEXT_SECTION(node) ) > + { > + strcat(ach, " in_text_section"); > + } > + if( DECL_IN_CONSTANT_POOL(node) ) > + { > + strcat(ach, " in_constant_pool"); > + } > + if( DECL_DLLIMPORT_P(node) ) > + { > + strcat(ach, " dllimport_flag"); > + } > + } > + if( DECL_WEAK(node) ) > + { > + strcat(ach, " weak_flag"); > + } > + if( DECL_SEEN_IN_BIND_EXPR_P(node) ) > + { > + strcat(ach, " seen_in_bind_expr"); > + } > + if( DECL_COMDAT(node) ) > + { > + strcat(ach, " comdat_flag"); > + } > + if( DECL_VISIBILITY_SPECIFIED(node) ) > + { > + strcat(ach," visibility_specified"); > + } > + if( code =3D=3D VAR_DECL && DECL_HAS_INIT_PRIORITY_P(node) ) > + { > + strcat(ach," init_priority_p"); > + } > + if( code =3D=3D FUNCTION_DECL && DECL_FINAL_P(node) ) > + { > + strcat(ach," final"); > + } > + if( code =3D=3D FUNCTION_DECL && DECL_STATIC_CHAIN(node) ) > + { > + strcat(ach," regdecl_flag"); > + } > + if( strlen(ach) ) > + { > + rjd_fprintf("decl_with_vis flags:%s\n",ach); > + json_flags("decl_with_vis", ach); > + } > + > + const char *p =3D "???"; > + switch( DECL_VISIBILITY(node) ) > + { > + case VISIBILITY_DEFAULT: > + p =3D "default"; > + break; > + case VISIBILITY_PROTECTED: > + p =3D "protected"; > + break; > + case VISIBILITY_HIDDEN: > + p =3D "hidden"; > + break; > + case VISIBILITY_INTERNAL: > + p =3D "internal"; > + break; > + } > + rjd_fprintf("visibility: %s\n", p); > + json_namevalue("visibility", p); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_DECL_NON_COMMON) ) > + { > + processed[TS_DECL_NON_COMMON] =3D 1; > + rjd_subtree("result", DECL_RESULT_FLD(node)); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_FUNCTION_DECL) ) > + { > + processed[TS_FUNCTION_DECL] =3D 1; > + if( node->function_decl.f ) > + { > + rjd_fprintf("function(pointer): %p\n",node->function_decl.f); > + } > + > + rjd_subtree("arguments", DECL_ARGUMENTS(node)); > + rjd_subtree("personality", DECL_FUNCTION_PERSONALITY(node)); > + rjd_subtree("function_specific_target", > + DECL_FUNCTION_SPECIFIC_TARGET(node)); > + rjd_subtree("function_specific_optimization", > + DECL_FUNCTION_SPECIFIC_OPTIMIZATION(node= )); > + const char *p =3D "saved_tree"; > + if( code =3D=3D FUNCTION_DECL ) > + { > + p =3D "saved_tree(function_body)"; > + } > + rjd_subtree(p, DECL_SAVED_TREE(node)); > + rjd_subtree("vindex", DECL_VINDEX(node)); > + > + rjd_fprintf("function_code: %d\n",node->function_decl.function_cod= e); > + > + switch(DECL_BUILT_IN_CLASS(node)) > + { > + case NOT_BUILT_IN: > + break; > + case BUILT_IN_FRONTEND: > + rjd_fprintf("built_in: frontend\n"); > + json_namevalue("built_in", "frontend"); > + break; > + case BUILT_IN_MD: > + rjd_fprintf("built_in: md\n"); > + json_namevalue("built_in", "md"); > + break; > + case BUILT_IN_NORMAL: > + rjd_fprintf("built_in: normal\n"); > + json_namevalue("built_in", "normal"); > + break; > + } > + switch(FUNCTION_DECL_DECL_TYPE(node)) > + { > + case NONE: > + break; > + case OPERATOR_NEW: > + rjd_fprintf("operator_new: 1\n"); > + json_namevalue("operator_new", "1", NOT_QUOTED); > + break; > + case OPERATOR_DELETE: > + rjd_fprintf("operator_delete: 1\n"); > + json_namevalue("operator_delete", "1", NOT_QUOTED); > + break; > + case LAMBDA_FUNCTION: > + rjd_fprintf("lambda_function: 1\n"); > + json_namevalue("lambda_function", "1", NOT_QUOTED); > + break; > + } > + > + strcpy(ach, ""); > + ADD_FLAG(TREE_PUBLIC, "public"); > + ADD_FLAG(DECL_STATIC_CONSTRUCTOR, "static_ctor_flag"); > + ADD_FLAG(DECL_STATIC_DESTRUCTOR, "static_dtor_flag"); > + ADD_FLAG(DECL_UNINLINABLE, "uninlinable"); > + ADD_FLAG(DECL_POSSIBLY_INLINED, "possibly_inlined"); > + ADD_FLAG(DECL_IS_NOVOPS, "novops_flag"); > + ADD_FLAG(DECL_IS_RETURNS_TWICE, "returns_twice_flag"); > + ADD_FLAG(DECL_IS_MALLOC, "malloc_flag"); > + ADD_FLAG(DECL_DECLARED_INLINE_P, "declared_inline_flag"); > + ADD_FLAG(DECL_NO_INLINE_WARNING_P, "no_inline_warning_flag"); > + ADD_FLAG(DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT, > + "no_instrument_function_entry_exit"); > + ADD_FLAG(DECL_NO_LIMIT_STACK, "no_limit_stack"); > + if( TREE_CODE(node) =3D=3D FUNCTION_DECL ) > + { > + ADD_FLAG(DECL_DISREGARD_INLINE_LIMITS, "disregard_inline_limits"= ); > + } > + ADD_FLAG(DECL_PURE_P, "pure_flag"); > + ADD_FLAG(DECL_LOOPING_CONST_OR_PURE_P, "looping_const_or_pure_flag= "); > + ADD_FLAG(DECL_HAS_DEBUG_ARGS_P, "has_debug_args_flag"); > + ADD_FLAG(DECL_FUNCTION_VERSIONED, "versioned_function"); > + ADD_FLAG(DECL_IS_REPLACEABLE_OPERATOR, "replaceable_operator"); > + if( strlen(ach) ) > + { > + rjd_fprintf("function_flags:%s\n", ach); > + json_flags("function_flags", ach); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_TYPE_COMMON) ) > + { > + processed[TS_TYPE_COMMON] =3D 1; > + > + rjd_subtree("size(in bits)", TYPE_SIZE(node)); > + rjd_subtree("size_unit(in bytes)", TYPE_SIZE_UNIT(node)); > + rjd_subtree("attributes", TYPE_ATTRIBUTES(node)); > + > + sprintf(ach, "%d", TYPE_UID(node)); > + rjd_fprintf("uid: %s\n", ach); > + json_namevalue("uid", ach, NOT_QUOTED); > + > + if( !VECTOR_TYPE_P(node) ) > + { > + sprintf(ach, "%d", TYPE_PRECISION(node)); > + rjd_fprintf("precision: %s\n", ach); > + json_namevalue("precision", ach, NOT_QUOTED); > + } > + > + sprintf(ach, "%d", TYPE_CONTAINS_PLACEHOLDER_INTERNAL(node)); > + rjd_fprintf("contains_placeholder: %d\n", ach); > + json_namevalue("contains_placeholder", ach, NOT_QUOTED); > + > + strcpy(ach, ""); > + ADD_FLAG(TYPE_NO_FORCE_BLK,"no_force_blk_flag"); > + ADD_FLAG(TYPE_NEEDS_CONSTRUCTING,"needs_constructing_flag"); > + if( code =3D=3D RECORD_TYPE > + || code =3D=3D UNION_TYPE > + || code =3D=3D QUAL_UNION_TYPE ) > + { > + ADD_FLAG(TYPE_TRANSPARENT_AGGR,"transparent_aggr_flag"); > + } > + ADD_FLAG(TYPE_RESTRICT, "restrict_flag"); > + if( code =3D=3D RECORD_TYPE > + || code =3D=3D UNION_TYPE > + || code =3D=3D QUAL_UNION_TYPE > + || code =3D=3D ARRAY_TYPE ) > + { > + ADD_FLAG(TYPE_TYPELESS_STORAGE, "typeless_storage"); > + } > + ADD_FLAG(TYPE_EMPTY_P, "empty_flag"); > + ADD_FLAG(TYPE_INDIVISIBLE_P, "indivisible_p"); > + if( strlen(ach) ) > + { > + rjd_fprintf("type_common_flags:%s\n", ach); > + json_flags("type_common_flags", ach); > + } > + > + sprintf(ach, "%d", TYPE_ALIGN(node)); > + rjd_fprintf("align: %s\n", ach); > + json_namevalue("align", ach); > + > + sprintf(ach, "%d", TYPE_WARN_IF_NOT_ALIGN(node)); > + rjd_fprintf("warn_if_not_align: %s\n", ach); > + json_namevalue("warn_if_not_align", ach); > + > + sprintf(ach, "%d", TYPE_ALIAS_SET(node)); > + rjd_fprintf("alias_set_type: %s\n", ach); > + json_namevalue("alias_set_type", ach); > + > + rjd_subtree("pointer_to", TYPE_POINTER_TO(node)); > + rjd_subtree("reference_to", TYPE_REFERENCE_TO(node)); > + > + rjd_subtree("canonical", TYPE_CANONICAL(node)); > + rjd_subtree("next_variant", TYPE_NEXT_VARIANT(node)); > + rjd_subtree("main_variant", TYPE_MAIN_VARIANT(node)); > + rjd_subtree("context", TYPE_CONTEXT(node)); > + rjd_subtree("name", TYPE_REFERENCE_TO(node)); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_TYPE_NON_COMMON) ) > + { > + processed[TS_TYPE_NON_COMMON] =3D 1; > + rjd_subtree("values", TYPE_VALUES_RAW(node)); > + rjd_subtree("minval", TYPE_MIN_VALUE_RAW(node)); > + rjd_subtree("maxval", TYPE_MAX_VALUE_RAW(node)); > + rjd_subtree("lang_1", TYPE_LANG_SLOT_1(node)); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_TYPE_WITH_LANG_SPECIFIC) ) > + { > + processed[TS_TYPE_WITH_LANG_SPECIFIC] =3D 1; > + if( TYPE_LANG_SPECIFIC(node) ) > + { > + rjd_fprintf("lang_type(pointer): %p\n",TYPE_LANG_SPECIFIC(node))= ; > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_INT_CST) ) > + { > + processed[TS_INT_CST] =3D 1; > + if( phase =3D=3D 2 ) > + rjd_fprintf("value: "); > + print_dec(wi::to_wide(node), ach, TYPE_SIGN(TREE_TYPE(node))); > + rjd_fprintf("%s" , ach); > + rjd_fprintf("\n"); > + json_namevalue("value", ach, NOT_QUOTED); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_REAL_CST) ) > + { > + bool not_quoted =3D false; > + processed[TS_REAL_CST] =3D 1; > + > + if(TREE_OVERFLOW(node)) > + { > + strcpy(ach, " overflow "); > + } > + else > + { > + REAL_VALUE_TYPE d =3D TREE_REAL_CST(node); > + if(REAL_VALUE_ISINF(d)) > + { > + strcpy(ach, REAL_VALUE_NEGATIVE(d) ? " -Inf" : " Inf"); > + } > + else if(REAL_VALUE_ISNAN(d)) > + { > + /* Print a NaN in the format [-][Q]NaN[(significand[exponent])= ] > + where significand is a hexadecimal string that starts with > + the 0x prefix followed by 0 if the number is not canonical > + and a non-zero digit if it is, and exponent is decimal. */ > + sprintf(ach, > + "%s%sNaN", > + d.sign ? "-" : "", > + d.signalling ? "S" : "Q"); > + } > + else > + { > + real_to_decimal(ach, &d, sizeof(ach), 0, 1); > + not_quoted =3D true; > + } > + } > + > + rjd_fprintf("value: %s\n", ach); > + json_namevalue("value", ach, not_quoted); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_VEC) ) > + { > + processed[TS_VEC] =3D 1; > + > + len =3D TREE_VEC_LENGTH(node); > + if(len) > + { > + json_start_array("tree_vector_elements"); > + } > + for(i =3D 0; i < len; i++) > + { > + if( TREE_VEC_ELT(node, i) ) > + { > + char temp[32]; > + sprintf(temp, "tree_vector_element[%d]", i); > + > + rjd_subtree(temp, TREE_VEC_ELT(node, i)); > + json_comma =3D ","; > + } > + } > + if(len) > + { > + json_finish_array(); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_EXP) ) > + { > + processed[TS_EXP] =3D 1; > + xloc =3D expand_location( EXPR_LOCATION(node) ); > + if( xloc.file ) > + { > + sprintf(ach, "%s:%d:%d", > + xloc.file, > + xloc.line, > + xloc.column); > + rjd_fprintf("expression_location %s\n", ach); > + json_namevalue("expression_location", ach); > + } > + len =3D TREE_OPERAND_LENGTH(node); > + > + tree node_vars =3D NULL_TREE; > + tree node_body =3D NULL_TREE; > + tree node_block =3D NULL_TREE; > + > + if( len ) > + { > + json_start_array("operands"); > + } > + for(i =3D 0; i < len; i++) > + { > + char temp[32]; > + sprintf(temp, "operand[%d]", i); > + > + if( code =3D=3D BIND_EXPR ) > + { > + switch(i) > + { > + // vars/body/block is the order they appear. I modify that = to > + // vars/block/body because that's easier for me to deal with > when I > + // manually graph the connections of the results > + case 0: > + node_vars =3D node; > + continue; > + break; > + case 1: > + node_body =3D node; > + continue; > + break; > + case 2: > + node_block =3D node; > + continue; > + break; > + } > + } > + if( code =3D=3D COMPONENT_REF ) > + { > + switch(i) > + { > + case 0: > + strcpy(temp,"struct/union"); > + break; > + case 1: > + strcpy(temp,"field"); > + break; > + case 2: > + strcpy(temp,"offset"); > + break; > + } > + } > + rjd_subtree(temp, TREE_OPERAND(node, i)); > + json_comma =3D ","; > + } > + if( len ) > + { > + json_finish_array(); > + } > + > + // Here's where I output the block/vars/body in my preferred order > + if(node_block) > + { > + rjd_subtree("block", TREE_OPERAND(node_block, 2)); > + } > + if(node_vars) > + { > + rjd_subtree("vars", TREE_OPERAND(node_vars, 0)); > + } > + if(node_body) > + { > + rjd_subtree("body", TREE_OPERAND(node_body, 1)); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_LIST) ) > + { > + processed[TS_LIST] =3D 1; > + rjd_subtree("purpose", TREE_PURPOSE(node)); > + rjd_subtree("value", TREE_VALUE(node)); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_STATEMENT_LIST) ) > + { > + processed[TS_STATEMENT_LIST] =3D 1; > + > + // We have a linked list to walk: > + > + int i =3D 0; > + tree_statement_list_node *next =3D STATEMENT_LIST_HEAD(node); > + if( next ) > + { > + json_start_array("statement_list"); > + } > + while( next ) > + { > + sprintf(ach,"statement_list[%d]",i++); > + rjd_subtree(ach, next->stmt); > + > + // By rights, this next statement, while not illegal, should > + // be regarded as immoral. > + next =3D next->next; > + json_comma =3D ","; > + } > + if( STATEMENT_LIST_HEAD(node) ) > + { > + json_finish_array(); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_RESULT_DECL) ) > + { > + processed[TS_RESULT_DECL] =3D 1; > + > + strcpy(ach, ""); > + ADD_FLAG(DECL_BY_REFERENCE, "by_reference"); > + ADD_FLAG(DECL_NONSHAREABLE, "nonshareable"); > + ADD_FLAG(DECL_HAS_VALUE_EXPR_P, "has_value_expr"); > + ADD_FLAG(SSA_VAR_P, "ssa_name_is_possible"); > + if( strlen(ach) ) > + { > + rjd_fprintf("result_flags:%s\n",ach); > + json_flags("result_flags", ach); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_STRING) ) > + { > + // First, do the text/html string: > + strcpy(ach, ""); > + char ach2[8]; > + processed[TS_STRING] =3D 1; > + const char *p =3D TREE_STRING_POINTER(node); > + int i =3D TREE_STRING_LENGTH(node); // sizeof(), not strlen() > + while(--i >=3D 0) > + { > + char ch =3D *p++; > + if(ch >=3D ' ' && ch < 127) > + { > + sprintf(ach2, "%c", ch); > + } > + else > + { > + sprintf(ach2, "\\%03o", ch & 0xFF); > + } > + strcat(ach, ach2); > + } > + rjd_fprintf("string: \""); > + rjd_fprintf("%s\"\n", ach); > + > + // Second, do the JSON string: > + strcpy(ach, ""); > + p =3D TREE_STRING_POINTER(node); > + i =3D TREE_STRING_LENGTH(node); // sizeof(), not strlen() > + while(--i >=3D 0) > + { > + char ch =3D *p++; > + strcpy(ach2, ""); > + switch( ch ) > + { > + case '\"' : > + strcpy(ach2, "\\\""); > + break; > + case '\\' : > + strcpy(ach2, "\\\\"); > + break; > + case '/' : > + strcpy(ach2, "/"); > + break; > + case '\b' : > + strcpy(ach2, "\\b"); > + break; > + case '\f' : > + strcpy(ach2, "\\f"); > + break; > + case '\n' : > + strcpy(ach2, "\\n"); > + break; > + case '\r' : > + strcpy(ach2, "\\r"); > + break; > + case '\t' : > + strcpy(ach2, "\\t"); > + break; > + default: > + if(ch >=3D ' ' && ch < 127) > + { > + sprintf(ach2, "%c", ch); > + } > + else > + { > + sprintf(ach2, "\\u%4.4x", (unsigned int)(ch & 0xFF)); > + } > + } > + strcat(ach, ach2); > + } > + json_namevalue("string", ach); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_IDENTIFIER) ) > + { > + processed[TS_IDENTIFIER] =3D 1; > + rjd_fprintf("identifier: \"%s\"\n", IDENTIFIER_POINTER(node)); > + json_namevalue("identifier", IDENTIFIER_POINTER(node)); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_BLOCK) ) > + { > + processed[TS_BLOCK] =3D 1; > + > + sprintf(ach, "%u", BLOCK_NUMBER(node)); > + rjd_fprintf("block_num: %u\n", ach); > + json_namevalue("block_num", ach); > + > + xloc =3D expand_location(BLOCK_SOURCE_LOCATION(node)); > + if( xloc.file ) > + { > + rjd_fprintf(ach, "%s:%d:%d", > + xloc.file, > + xloc.line, > + xloc.column); > + rjd_fprintf("block_location_start: %s\n", ach); > + json_namevalue("block_location_start", ach); > + } > + > + xloc =3D expand_location(BLOCK_SOURCE_END_LOCATION(node)); > + if( xloc.file ) > + { > + rjd_fprintf(ach, "%s:%d:%d", > + xloc.file, > + xloc.line, > + xloc.column); > + rjd_fprintf("block_location_end: %s\n", ach); > + json_namevalue("block_location_end", ach); > + } > + > + if( BLOCK_DIE(node) ) > + { > + rjd_fprintf("DWARF lexical block(pointer) %p\n", BLOCK_DIE(node)= ); > + } > + > + rjd_subtree("vars", BLOCK_VARS(node)); > + > + len =3D BLOCK_NUM_NONLOCALIZED_VARS(node); > + if( len ) > + { > + json_start_array("nonlocalized_vars"); > + } > + for(i =3D 0; i < len; i++) > + { > + char temp[32]; > + sprintf(temp, "nonlocalized_var[%d]", i); > + rjd_subtree(temp, BLOCK_NONLOCALIZED_VAR(node, i)); > + json_comma =3D ","; > + } > + if( len ) > + { > + json_finish_array(); > + } > + > + rjd_subtree("subblocks", BLOCK_SUBBLOCKS(node)); > + rjd_subtree("supercontext", BLOCK_SUPERCONTEXT(node)); > + rjd_subtree("abstract_origin", BLOCK_ABSTRACT_ORIGIN(node)); > + rjd_subtree("fragment_origin", BLOCK_FRAGMENT_ORIGIN(node)); > + rjd_subtree("fragment_chain", BLOCK_FRAGMENT_CHAIN(node)); > + rjd_subtree("chain", BLOCK_CHAIN(node)); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_PARM_DECL) ) > + { > + processed[TS_PARM_DECL] =3D 1; > + // The only attribute unique to TS_PARM_DECL is rtx rtl. > + // I might process it, if I knew what it was. RJD 2021-01-29 > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_FIELD_DECL) ) > + { > + processed[TS_FIELD_DECL] =3D 1; > + rjd_subtree("offset", DECL_FIELD_OFFSET(node)); > + rjd_subtree("bit_field_type", DECL_BIT_FIELD_TYPE(node)); > + rjd_subtree("qualifier", DECL_QUALIFIER(node)); > + rjd_subtree("bit_offset", DECL_FIELD_BIT_OFFSET(node)); > + rjd_subtree("fcontext", DECL_FCONTEXT(node)); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_VAR_DECL) ) > + { > + processed[TS_VAR_DECL] =3D 1; > + strcpy(ach, ""); > + ADD_FLAG(TREE_PUBLIC,"public"); > + ADD_FLAG(DECL_IN_TEXT_SECTION,"in_text_section"); > + ADD_FLAG(DECL_IN_CONSTANT_POOL,"in_constant_pool"); > + ADD_FLAG(DECL_HARD_REGISTER,"hard_register"); > + ADD_FLAG(DECL_HAS_INIT_PRIORITY_P,"init_priority_p"); > + ADD_FLAG(DECL_HAS_DEBUG_EXPR_P,"debug_expr_is_from"); > + ADD_FLAG(VAR_DECL_IS_VIRTUAL_OPERAND,"is_virtual_operand"); > + ADD_FLAG(DECL_NONLOCAL_FRAME,"non_local_frame_structure"); > + ADD_FLAG(DECL_NONALIASED,"non_aliased"); > + if( strlen(ach) ) > + { > + rjd_fprintf("var_decl_flags:%s\n",ach); > + json_flags("var_decl_flags", ach); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_TYPE_DECL) ) > + { > + processed[TS_TYPE_DECL] =3D 1; > + strcpy(ach, ""); > + ADD_FLAG(TREE_PUBLIC,"public"); > + ADD_FLAG(TYPE_DECL_SUPPRESS_DEBUG,"suppress_debug"); > + if( strlen(ach) ) > + { > + rjd_fprintf("type_decl_flags:%s\n",ach); > + json_flags("type_decl_flags", ach); > + } > + rjd_subtree("original_type", DECL_ORIGINAL_TYPE(node)); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_CONST_DECL) ) > + { > + processed[TS_CONST_DECL] =3D 1; > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_TRANSLATION_UNIT_DECL) ) > + { > + processed[TS_TRANSLATION_UNIT_DECL] =3D 1; > + if( TRANSLATION_UNIT_LANGUAGE(node) ) > + { > + rjd_fprintf("language: %s\n", TRANSLATION_UNIT_LANGUAGE(node)); > + json_namevalue("language", TRANSLATION_UNIT_LANGUAGE(node)); > + } > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_LABEL_DECL) ) > + { > + processed[TS_LABEL_DECL] =3D 1; > + > + strcpy(ach, ""); > + ADD_FLAG(TREE_ADDRESSABLE,"outside_stack_levels"); > + ADD_FLAG(FORCED_LABEL,"forced_label"); > + ADD_FLAG(FALLTHROUGH_LABEL_P,"fallthrough_allowed"); > + ADD_FLAG(SWITCH_BREAK_LABEL_P,"switch_break"); > + ADD_FLAG(DECL_NONLOCAL,"nonlocal_permitted"); > + if( strlen(ach) ) > + { > + rjd_fprintf("label_decl_flags:%s\n",ach); > + json_flags("label_decl_flags", ach); > + } > + > + rjd_subtree("label_context", DECL_CONTEXT(node)); > + > + sprintf(ach, "%d", LABEL_DECL_UID(node)); > + rjd_fprintf("label_uid: %s\n", ach); > + json_namevalue("label_uid", ach); > + > + sprintf(ach, "%d", EH_LANDING_PAD_NR(node)); > + rjd_fprintf("eh_landing_pad: %s\n", ach); > + json_namevalue("eh_landing_pad", ach); > + } > + > + if( CODE_CONTAINS_STRUCT(code, TS_CONSTRUCTOR) ) > + { > + processed[TS_CONSTRUCTOR] =3D 1; > + > + if( CONSTRUCTOR_NO_CLEARING(node) ) > + { > + rjd_fprintf("no_clearing: ON\n"); > + json_namevalue("no_clearing", "true", NOT_QUOTED); > + } > + else > + { > + rjd_fprintf("no_clearing: off\n"); > + json_namevalue("no_clearing", "false", NOT_QUOTED); > + } > + > + char temp[32]; > + > + if( CONSTRUCTOR_NELTS(node) ) > + { > + json_start_array("constructor_elts"); > + } > + for(size_t i=3D0; i + { > + constructor_elt *c_elt =3D CONSTRUCTOR_ELT(node, i); > + > + sprintf(temp, "constructor_elt[%d].index",(int)i); > + rjd_subtree(temp, c_elt->index); > + > + sprintf(temp, "constructor_elt[%d].value",(int)i); > + rjd_subtree(temp, c_elt->value); > + > + int node_number_i =3D find_node_in_nodes(c_elt->index); > + sprintf(ach, "{\"constructor\":{\"index_node\":%d,", > node_number_i); > + json_newline(); > + json_fprintf("%s", ach); > + json_comma =3D ","; > + > + int node_number_v =3D find_node_in_nodes(c_elt->value); > + sprintf(ach, "\"value_node\":%d}}", node_number_v); > + json_fprintf("%s", ach); > + json_comma =3D ","; > + } > + if( CONSTRUCTOR_NELTS(node) ) > + { > + json_finish_array(); > + } > + } > + > + // We put this next statement at the end, because it's nice when CHA= IN > + // is the last thing we see: > + if( CODE_CONTAINS_STRUCT(code, TS_COMMON) ) > + { > + processed[TS_COMMON] =3D 1; > + rjd_subtree("chain", TREE_CHAIN(node)); > + } > + > + for(int i=3D0; i<64; i++) > + { > + if( required[i] && !processed[i]) > + { > + /* Arriving here means that you have encountered a tree struct > + that you don't know how to handle. This happened to me just > + now. The error message I see is > + > + structure 'parm decl': NOT PROCESSED!!!! > + > + What to do? > + > + Well, the first thing I do is look in gcc/treestruct.def for > + "parm decl". I find that text in this line: > + > + DEFTREESTRUCT(TS_PARM_DECL, "parm decl") > + > + This tells me that the tree struct's enum code is TS_PARM_DE= CL > + > + Next, I look in gcc/tree-core.h for the text "TS_PARM_DECL".= I > find > + it in this line: > + > + struct tree_parm_decl GTY ((tag("TS_PARM_DECL"))) > parm_decl; > + > + This tells me the structure I need to handle is > "tree_parm_decl". > + The declaration of that structure is found earlier in > gcc/tree-core.h > + > + struct GTY(()) tree_parm_decl { > + struct tree_decl_with_rtl common; > + rtx incoming_rtl; }; > + > + That structure has a substructure "tree_decl_with_rtl", whic= h > will > + require its one handler. The structure has its own specifi= c > + attribute "rtx incoming_rtl", which we might, or might not w= ant > to > + use as a source of display information. But, in any case, w= e > do need > + to add code up above for handling TS_PARM_DECL structures. > You'll > + find that code in the block starting with > + > + if( CODE_CONTAINS_STRUCT(code, TS_PARM_DECL) ) > + {...} > + > + For each attribute in the TS_xxx that you are working with, > there is > + an accessor macro in gcc/tree.h for getting at that data. Y= ou > need > + to be using those macros; there are a lot of hints and > information > + about the attribute. For example, by searching for > ".incoming_rtl" > + -- note the leading dot -- you find this commented entry in > + gcc/tree.h: > + > + /_* For PARM_DECL, holds an RTL for the stack slot or > register > + where the data was actually passed. *_/ > + #define DECL_INCOMING_RTL(NODE) \ > + (PARM_DECL_CHECK(NODE)->parm_decl.incoming_rtl) > + > + We are processing a PARM_DECL node, which means that the mac= ro > + invocation: > + > + DECL_INCOMING_RTL(node) > + > + will safely return "incoming_rtl", because the PARM_DECL_CHE= CK > macro > + won't throw an error. > + > + And that's how this error message is eliminated. > + */ > + > + rjd_fprintf("structure \'%s\': ",ts_enum_names[i]); > + rjd_fprintf("NOT PROCESSED!!!!\n" ); > + fprintf(stderr, "structure \'%s\': ",ts_enum_names[i]); > + fprintf(stderr, "NOT PROCESSED!!!!\n" ); > + exit(1); > + } > + } > + > + if( phase=3D=3D2 && fhtml ) > + { > + fprintf(fhtml, "

\n"); > + } > +} > + > +void > +dump_generic_nodes(const char *filename, tree root) > +{ > + /* This function is called at the beginning of > gimplify_function_tree() in > + * gimplify.cc. The 'root' parameter is supposed to be a func_decl > node. > + * > + * When the flag_dump_generic_nodes flag is true, that means the > compiler was > + * invoked with -fdump-generic-nodes, and that means we jump into > action. > + * > + * We create two files based on filename. When filename is NULL, i= t > gets > + * replaced with the name of the function as extracted from the > func_decl > + * node. > + * > + * filename.nodes is a text file. filename.nodes.html has the same > + * information in a hypertext file with in-file links to referenced > nodes. > + * > + * The output is a listing of all of the function's nodes and their > + * attributes. Here is an example of the first two nodes of a typi= cal > file: > + > +***********************************This is NodeNumber0 > +(0x7f12e13b0d00) NodeNumber0 > +tree_code: function_decl > +tree_code_class: tcc_declaration > +base_flags: static public > +type: NodeNumber1 function_type > +name: NodeNumber6410 identifier_node "main" > +context: NodeNumber107 translation_unit_decl "bigger.c" > +source_location: bigger.c:7:5 > +uid: 3663 > +initial(bindings): NodeNumber6411 block > +machine_mode: QI(15) > +align: 8 > +warn_if_not_align: 0 > +pt_uid: 3663 > +raw_assembler_name: NodeNumber6410 identifier_node "main" > +visibility: default > +result: NodeNumber6412 result_decl > +function(pointer): 0x7f12e135d508 > +arguments: NodeNumber6413 parm_decl "argc" > +saved_tree(function_body): NodeNumber6417 statement_list > +function_code: 0 > +function_flags: public no_instrument_function_entry_exit > +***********************************This is NodeNumber1 > +(0x7f12e13b3d20) NodeNumber1 > +tree_code: function_type > +tree_code_class: tcc_type > +machine_mode: QI(15) > +type: NodeNumber2 integer_type > +address_space:0 > +size(in bits): NodeNumber55 uint128 8 > +size_unit(in bytes): NodeNumber12 uint64 1 > +uid: 1515 > +precision: 0 > +contains_placeholder: 0 > +align: 8 > +warn_if_not_align: 0 > +alias_set_type: -1 > +canonical: NodeNumber1 function_type > +main_variant: NodeNumber1 function_type > +values: NodeNumber6408 tree_list > +***********************************This is NodeNumber3 > + > + */ > + > + if( flag_dump_generic_nodes ) > + { > + GV_number_of_nodes =3D 0; > + char achFilename[1024]; > + if( !filename ) > + { > + // If, perchance, the root is a decl, use its > + // name field as the root of the output file. This means > + // that each function_decl will result in its output file: > + // main.tags, foo.tags, bar.tags, and so on. > + > + if( DECL_P(root) ) > + { > + filename =3D IDENTIFIER_POINTER(DECL_NAME(root)); > + } > + } > + > + if( filename ) > + { > + // Find the root name: > + const char *p1 =3D strrchr(filename,'/'); > + if( p1 ) > + { > + p1 +=3D 1; > + } > + else > + { > + p1 =3D filename; > + } > + strcpy(achFilename,filename); > + char *p2 =3D strrchr(achFilename,'.'); > + if( p2 ) > + { > + *p2 =3D '\0'; > + } > + strcat(achFilename,".nodes"); > + ftext =3D fopen(achFilename, "w"); > + if( !ftext ) > + { > + error("Unable to open %s", achFilename); > + } > + // For reasons I don't understand this setvbuf is necessary. > Without > + // it the vfprintf calls here in this routine interfere with > + // printf calls elsewhere. > + setvbuf(ftext, NULL, _IONBF, 0); > + > + strcat(achFilename,".html"); > + fhtml =3D fopen(achFilename, "w"); > + if( !ftext ) > + { > + error("Unable to open %s", achFilename); > + } > + setvbuf(fhtml, NULL, _IONBF, 0); > + > + char title[1024]; > + strcpy(title, "GENERIC for "); > + strcat(title, filename); > + strcat(title, "()"); > + > + html_boilerplate(title); > + > + strcpy(achFilename,filename); > + p2 =3D strrchr(achFilename,'.'); > + if( p2 ) > + { > + *p2 =3D '\0'; > + } > + strcat(achFilename,".json"); > + fjson =3D fopen(achFilename, "w"); > + if( !fjson ) > + { > + error("Unable to open %s", achFilename); > + } > + // For reasons I don't understand this setvbuf is necessary. > Without > + // it the vfprintf calls here in this routine interfere with > + // printf calls elsewhere. > + setvbuf(fjson, NULL, _IONBF, 0); > + } > + else > + { > + fprintf( stderr, > + "%s(): Needs either a filename or a DECL_NODE\n", > + __func__); > + gcc_assert(false); > + } > + > + if( ftext ) > + { > + phase =3D 1; > + rjd_print_node(root); > + > + phase =3D 2; > + > + // Here is the JSON "header" > + json_level =3D 0; > + json_comma =3D ","; > + json_indent(); > + json_fprintf("{\n"); > + json_fprintf("\"version\":\"1.0\""); > + > + json_newline(); > + json_fprintf("\"node_count\":%d", GV_number_of_nodes); > + > + json_comma =3D ","; > + json_newline(); > + json_fprintf("\"nodes\":\n"); > + json_fprintf("["); > + > + json_level +=3D 1; > + json_comma =3D ""; > + for(int i=3D0; i + { > + json_newline(); > + json_comma =3D ","; > + json_fprintf("{\n"); > + json_indent(); > + json_fprintf("\"node\":%d", i); > + > + rjd_print_node(nodes[i].this_node); > + > + json_fprintf("\n"); > + json_indent(); > + json_fprintf("}"); > + } > + json_level -=3D 1; > + > + // Here is the JSON "trailer, that ties off the header" > + json_fprintf("\n"); > + json_fprintf("]\n"); > + json_fprintf("}\n"); > + json_level =3D 1; > + > + fclose(ftext); > + ftext =3D NULL; > + > + html_boilerplate(); > + fclose(fhtml); > + ftext =3D NULL; > + > + fclose(fjson); > + ftext =3D NULL; > + } > + } > +} > diff --git a/gcc/dump-generic-nodes.h b/gcc/dump-generic-nodes.h > new file mode 100644 > index 00000000000..ffe18ce2aa5 > --- /dev/null > +++ b/gcc/dump-generic-nodes.h > @@ -0,0 +1,26 @@ > +/* Various declarations for language-independent pretty-print > subroutines. > + Copyright (C) 2002-2024 Free Software Foundation, Inc. > + Contributed by Gabriel Dos Reis > + > +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 > +. */ > + > +#ifndef GCC_PRINT_GIMPLE_NODES_H > +#define GCC_PRINT_GIMPLE_NODES_H > + > +extern void dump_generic_nodes(const char *file_name, tree fndecl); > + > +#endif > diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc > index 7f79b3cc7e6..7d3c23bcb80 100644 > --- a/gcc/gimplify.cc > +++ b/gcc/gimplify.cc > @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3. If not see > #include "omp-offload.h" > #include "context.h" > #include "tree-nested.h" > +#include "dump-generic-nodes.h" > > /* Hash set of poisoned variables in a bind expr. */ > static hash_set *asan_poisoned_variables =3D NULL; > @@ -19232,6 +19233,8 @@ gimplify_function_tree (tree fndecl) > > gcc_assert (!gimple_body (fndecl)); > > + dump_generic_nodes(NULL, fndecl); > + > if (DECL_STRUCT_FUNCTION (fndecl)) > push_cfun (DECL_STRUCT_FUNCTION (fndecl)); > else > -- > 2.34.1 >