This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Hack to make gimple dump parseable as C (was Re: [gimplefe] [gsoc16] Gimple Front End Project)


On Thu, 2016-03-10 at 11:50 +0100, Richard Biener wrote:
> On Thu, Mar 10, 2016 at 11:46 AM, Richard Biener
> <richard.guenther@gmail.com> wrote:
> > On Wed, Mar 9, 2016 at 8:45 PM, Manuel LÃpez-IbÃÃez
> > <lopezibanez@gmail.com> wrote:
> > > On 9 March 2016 at 02:50, Trevor Saunders <tbsaunde@tbsaunde.org>
> > > wrote:
> > > > On Tue, Mar 08, 2016 at 05:12:56PM -0500, Diego Novillo wrote:
> > > > > This way, implementing a library that supports dealing with
> > > > > GIMPLE
> > > > > becomes much simpler.  This provides a nice foundation for
> > > > > all kinds
> > > > > of gimple-oriented tooling in the future.
> > > > 
> > > > Well, one nice thing about choosing a subset of C as your
> > > > textual
> > > > representation of gimple is that all the tools that deal with C
> > > > already
> > > > can deal with it, and so you won't really need separate tools
> > > > for gimple
> > > > (that would be my theory anyway).
> > > 
> > > What tools available for C would be useful for working with
> > > gimple IR?
> > > Diego means tools like those available for modifying, compiling
> > > and
> > > verifying LLVM IR and its bytecode representation. Things like
> > > http://www.cis.upenn.edu/~stevez/vellvm/ and
> > > http://blog.regehr.org/archives/1170 No such thing is available
> > > for C
> > > (nor GIMPLE), because they are not a well-defined IR
> > > (http://lambda-the-ultimate.org/node/715#comment-6526).
> > > 
> > > If the gimple IR were a strict subset of GNU C, then by all means
> > > let's re-use the C FE. However, gimple encodes things that are
> > > necessary for other languages but are not C. C++ gimple dumps
> > > have
> > > try-finally. Fortran dumps use explicit parentheses "((x))".
> > > Surely,
> > > Ada adds its own quirks to gimple. You can probably represent all
> > > this
> > > with a C-looking language plus some large number of new
> > > __builtins_
> > > and __attributes__. At that point you will end up with something
> > > that
> > > is neither a super-set, nor a sub-set of any of the many C
> > > variants
> > > already supported by the C parser. Thus, one would need to
> > > significantly hack the existing C parser to correctly parse this
> > > C-looking language, while not breaking any of the things
> > > supported by
> > > the C parser, nor accepting anything not supported by gnu/std C.
> > > 
> > > Should the gimple-C parser support promotion rules? If GIMPLE is
> > > three-adresses-based, why support expressions with more than two
> > > operands at all? If the dumped IR should be sufficient to stop
> > > compilation, dump, reload, and continue, then how to represent
> > > language-specific tree codes that survive until RTL? (perhaps FE
> > > trees
> > > leaking into RTL got fixed already and I'm outdated here). What
> > > about
> > > preserving the original source locations? And debug info? All
> > > that
> > > would need to be handled by a gcc equivalent of LLVM's opt tool.
> > > How
> > > is all that going to be represented in gimple-C?
> > 
> > Well.  I'd like to have a convenient way to write unit-tests for
> > GIMPLE (SSA) passes
> > that work good enough which means I have to approximate the GIMPLE
> > IL fed into a
> > GIMPLE pass so that I can reproduce a critical situation and keep
> > that stable
> > over the evolution of GCC (and passes before that pass).
> > 
> > The most simplistic and pragmatic way was the proposal intruducing 
> > -Otest
> > https://gcc.gnu.org/ml/gcc-patches/2010-08/msg01879.html
> > 
> > I'd like to have "proper" pass manager modifications to make that
> > work better.
> > 
> > Then I'd like to be able to re-construct SSA without jumping
> > through hoops
> > (usually you can get close but if you require copies propagated in
> > a special
> > way you are basically lost for example).
> > 
> > Thus my proposal to make the GSoC student attack the unit-testing
> > problem
> > by doing modifications to the pass manager and "extending" an
> > existing
> > frontend (C for simplicity).
> > 
> > It's true that in the ideal world a "GIMPLE frontend" has to work
> > differently
> > but then to get a 100% GIMPLE frontend you indeed arrive at what
> > LTO
> > does and then I agree we should attack that from the LTO side and
> > not
> > develop another thing besides it.  But this is a _much_ larger task
> > and
> > I don't see anyone finishing that.  Also keep in mind that the LTO
> > side will
> > likely simplify a lot by stripping out the ability to stream things
> > that are
> > only required for debug information (I hopefully will finish LTO
> > early debug
> > for GCC 7).
> > 
> > So - can we please somehow focus on the original question about a
> > GSoC project around the "GIMPLE frontend"?  Of course you now can
> > take Davids promise of spending some development time on this
> > into consideration.  Try drafting something that can be reasonably
> > accomplished with giving us something to actually use in the GCC 7
> > timeframe.
> 
> Oh, and rather than trying to define semantics of GIMPLE to write a
> frontend I'd write the reverse first - a "backend" (aka dumper) plus
> a
> simulator.  During that effort you can then also do the specification
> part.
> You'd produce bytecode plus a textual form.
> 
> Note that if the textual form is too nice people may view it as a
> loop-hole
> into our runtime license exception.

I'll try to summarize the implementation approaches suggested so far:

(1) use the existing "gimple-front-end" branch
  (1.1) tuple-based format
  (1.2) rework/rewrite it to use a C-like format

(2) use the C frontend, with a new -fgimple option

(3) use/rework the LTO streamer code, with a textual format.


For both (1) and (2) we'd need input data.  We could:
 (A) adapt the existing dumper to be more amenable to loading as C, or
 (B) write a new dumper

I've been doing some rough prototyping work of (A).  (I've also been
doing some prototyping of (3), hacking up the LTO streamer; I'll post
that separately).

Attached is a crude patch that hacks up the existing gimple dumping
enough for it to be *mostly* parsable as C, along with a test file
(test-loop.c), and the sample output (test-loop.c.018t.ssa).

Generating the dumpfile:
  $ ./xgcc -B. -c ../../src/test-loop.c -fdump-tree-ssa

Reading it:
  $ ./xgcc -B. -xc test-loop.c.018t.ssa -fgimple

The "-fgimple" does nothing yet.  The existing C FE parses the result,
mostly: the dumps don't contain type information, and the parser can't
handle phi nodes, so we get:

test-loop.c.018t.ssa: In function âtest_1â:
test-loop.c.018t.ssa:28:8: warning: implicit declaration of function
â__PHIâ [-Wimplicit-function-declaration]
   _1 = __PHI (/* bb_3:*/_5, /* bb_4:*/_6);
        ^~~~~
test-loop.c.018t.ssa: At top level:
test-loop.c.018t.ssa:39:16: warning: âstruct fooâ declared inside
parameter list will not be visible outside of this definition or
declaration
 test_2 (struct foo * lhs, struct foo * rhs)
                ^~~
test-loop.c.018t.ssa: In function âtest_2â:
test-loop.c.018t.ssa:67:13: error: dereferencing pointer to incomplete
type âstruct fooâ
   _6 = lhs_5->count;
             ^~

I stripped off the "(D)" suffix from the default defs e.g.:

     struct foo * lhs_5(D);
            ^~~
so there isn't a way to see if SSA_NAME_IS_DEFAULT_DEF (node) is set on
an SSA_NAME in this representation (perhaps we could synthesize an
assignment at the decl of the SSA_NAME, so it becomes e.g.:

     struct foo * lhs_5 = lhs;

Also, this is throwing away parts of the IR (e.g. loop information), in
the hope that it can be constructed faithfully on load.

But with all these caveats it does (mostly) parse as C.

I haven't yet attempted to directly make gimple from this when -fgimple
is set; does that seem like a worthwhile experiment?

Hope this is constructive
Dave
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 7c5f6c7..ac0173d 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1227,6 +1227,10 @@ ffreestanding
 C ObjC C++ ObjC++
 Do not assume that standard C libraries and \"main\" exist.
 
+fgimple
+C Var(flag_gimple, 0)
+Parse as GNU GIMPLE
+
 fgnu-keywords
 C++ ObjC++ Var(flag_no_gnu_keywords, 0)
 Recognize GNU-defined keywords.
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index e27214f..7d90072 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -864,6 +864,9 @@ static void
 dump_gimple_label (pretty_printer *buffer, glabel *gs, int spc, int flags)
 {
   tree label = gimple_label_label (gs);
+#if 1
+  pp_printf (buffer, "label_%i:", LABEL_DECL_UID (label));
+#else
   if (flags & TDF_RAW)
       dump_gimple_fmt (buffer, spc, flags, "%G <%T>", gs, label);
   else
@@ -875,6 +878,7 @@ dump_gimple_label (pretty_printer *buffer, glabel *gs, int spc, int flags)
     pp_string (buffer, " [non-local]");
   if ((flags & TDF_EH) && EH_LANDING_PAD_NR (label))
     pp_printf (buffer, " [LP %d]", EH_LANDING_PAD_NR (label));
+#endif
 }
 
 /* Dump a GIMPLE_GOTO tuple on the pretty_printer BUFFER, SPC
@@ -1933,6 +1937,23 @@ dump_gimple_phi (pretty_printer *buffer, gphi *phi, int spc, bool comment,
   if (flags & TDF_ALIAS)
     dump_ssaname_info (buffer, lhs, spc);
 
+#if 1
+  dump_generic_node (buffer, lhs, spc, flags, false);
+  pp_string (buffer, " = __PHI (");
+  for (i = 0; i < gimple_phi_num_args (phi); i++)
+    {
+      if ((flags & TDF_LINENO) && gimple_phi_arg_has_location (phi, i))
+	dump_location (buffer, gimple_phi_arg_location (phi, i));
+      pp_string (buffer, "/* bb_");
+      pp_decimal_int (buffer, gimple_phi_arg_edge (phi, i)->src->index);
+      pp_string (buffer, ":*/");
+      dump_generic_node (buffer, gimple_phi_arg_def (phi, i), spc, flags,
+			 false);
+      if (i < gimple_phi_num_args (phi) - 1)
+	pp_string (buffer, ", ");
+    }
+  pp_string (buffer, ");");
+#else
   if (comment)
     pp_string (buffer, "# ");
 
@@ -1957,6 +1978,7 @@ dump_gimple_phi (pretty_printer *buffer, gphi *phi, int spc, bool comment,
 	pp_string (buffer, ", ");
     }
   pp_greater (buffer);
+#endif
 }
 
 
@@ -2402,11 +2424,7 @@ dump_gimple_bb_header (FILE *outf, basic_block bb, int indent, int flags)
 	}
     }
   else
-    {
-      gimple *stmt = first_stmt (bb);
-      if (!stmt || gimple_code (stmt) != GIMPLE_LABEL)
-	fprintf (outf, "%*s<bb %d>:\n", indent, "", bb->index);
-    }
+    fprintf (outf, "%*sbb_%d:\n", indent, "", bb->index);
 }
 
 
@@ -2451,24 +2469,9 @@ dump_phi_nodes (pretty_printer *buffer, basic_block bb, int indent, int flags)
 static void
 pp_cfg_jump (pretty_printer *buffer, basic_block bb)
 {
-  gimple *stmt;
-
-  stmt = first_stmt (bb);
-
-  pp_string (buffer, "goto <bb ");
+  pp_string (buffer, "goto bb_");
   pp_decimal_int (buffer, bb->index);
-  pp_greater (buffer);
-  if (stmt && gimple_code (stmt) == GIMPLE_LABEL)
-    {
-      pp_string (buffer, " (");
-      dump_generic_node (buffer,
-			 gimple_label_label (as_a <glabel *> (stmt)),
-			 0, 0, false);
-      pp_right_paren (buffer);
-      pp_semicolon (buffer);
-    }
-  else
-    pp_semicolon (buffer);
+  pp_semicolon (buffer);
 }
 
 
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 04e46fd..67ee591 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -7417,7 +7417,8 @@ dump_function_to_file (tree fndecl, FILE *file, int flags)
     }
 
   current_function_decl = fndecl;
-  fprintf (file, "%s %s(", function_name (fun), tmclone ? "[tm-clone] " : "");
+  print_generic_expr (file, TREE_TYPE (TREE_TYPE (fndecl)), dump_flags);
+  fprintf (file, "\n%s %s(", function_name (fun), tmclone ? "[tm-clone] " : "");
 
   arg = DECL_ARGUMENTS (fndecl);
   while (arg)
@@ -7484,6 +7485,7 @@ dump_function_to_file (tree fndecl, FILE *file, int flags)
 	    }
 	}
 
+#if 0
       if (!vec_safe_is_empty (fun->local_decls))
 	FOR_EACH_LOCAL_DECL (fun, ix, var)
 	  {
@@ -7494,11 +7496,12 @@ dump_function_to_file (tree fndecl, FILE *file, int flags)
 
 	    any_var = true;
 	  }
+#endif
       if (gimple_in_ssa_p (cfun))
 	for (ix = 1; ix < num_ssa_names; ++ix)
 	  {
 	    tree name = ssa_name (ix);
-	    if (name && !SSA_NAME_VAR (name))
+	    if (!virtual_operand_p (name))
 	      {
 		fprintf (file, "  ");
 		print_generic_expr (file, TREE_TYPE (name), flags);
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 9c13d84..b2ea824 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -191,7 +191,7 @@ dump_decl_name (pretty_printer *pp, tree node, int flags)
 	  if (flags & TDF_NOUID)
 	    pp_printf (pp, "%c.xxxx", c);
 	  else
-	    pp_printf (pp, "%c.%u", c, DECL_UID (node));
+	    pp_printf (pp, "%c_%u", c, DECL_UID (node));
 	}
     }
   if ((flags & TDF_ALIAS) && DECL_PT_UID (node) != DECL_UID (node))
@@ -2597,10 +2597,12 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, int flags,
 			   spc, flags, false);
       pp_underscore (pp);
       pp_decimal_int (pp, SSA_NAME_VERSION (node));
+#if 0
       if (SSA_NAME_IS_DEFAULT_DEF (node))
 	pp_string (pp, "(D)");
       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (node))
 	pp_string (pp, "(ab)");
+#endif
       break;
 
     case WITH_SIZE_EXPR:
@@ -3861,14 +3863,14 @@ dump_function_header (FILE *dump_file, tree fdecl, int flags)
   else
     aname = "<unset-asm-name>";
 
-  fprintf (dump_file, "\n;; Function %s (%s, funcdef_no=%d",
+  fprintf (dump_file, "\n/* Function %s (%s, funcdef_no=%d",
 	   dname, aname, fun->funcdef_no);
   if (!(flags & TDF_NOUID))
     fprintf (dump_file, ", decl_uid=%d", DECL_UID (fdecl));
   if (node)
     {
       fprintf (dump_file, ", cgraph_uid=%d", node->uid);
-      fprintf (dump_file, ", symbol_order=%d)%s\n\n", node->order,
+      fprintf (dump_file, ", symbol_order=%d)%s", node->order,
                node->frequency == NODE_FREQUENCY_HOT
                ? " (hot)"
                : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
@@ -3878,7 +3880,9 @@ dump_function_header (FILE *dump_file, tree fdecl, int flags)
                : "");
     }
   else
-    fprintf (dump_file, ")\n\n");
+    fprintf (dump_file, ")");
+
+  fprintf (dump_file, " */\n\n");
 }
 
 /* Dump double_int D to pretty_printer PP.  UNS is true
diff --git a/test-loop.c b/test-loop.c
new file mode 100644
index 0000000..ebb8aef
--- /dev/null
+++ b/test-loop.c
@@ -0,0 +1,31 @@
+int test_1 (int i, int j, int k)
+{
+  if (i < j)
+    return k + 4;
+  else
+    return -k;
+}
+
+/* Example showing:
+   - data structure
+   - loop
+   - call to "abort".  */
+
+struct foo
+{
+  int count;
+  float *data;
+};
+
+float test_2 (struct foo *lhs, struct foo *rhs)
+{
+  float result = 0.0f;
+
+  if (lhs->count != rhs->count)
+    __builtin_abort ();
+
+  for (int i = 0; i < lhs->count; i++)
+    result += lhs->data[i] * rhs->data[i];
+
+  return result;
+}
diff --git a/test-loop.c.018t.ssa b/test-loop.c.018t.ssa
new file mode 100644
index 0000000..bd907c1
--- /dev/null
+++ b/test-loop.c.018t.ssa
@@ -0,0 +1,114 @@
+
+/* Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0) */
+
+int
+test_1 (int i, int j, int k)
+{
+  int _1;
+  int i_2;
+  int j_3;
+  int k_4;
+  int _5;
+  int _6;
+
+  bb_2:
+  if (i_2 < j_3)
+    goto bb_3;
+  else
+    goto bb_4;
+
+  bb_3:
+  _5 = k_4 + 4;
+  goto bb_5;
+
+  bb_4:
+  _6 = -k_4;
+
+  bb_5:
+  _1 = __PHI (/* bb_3:*/_5, /* bb_4:*/_6);
+label_2:
+  return _1;
+
+}
+
+
+
+/* Function test_2 (test_2, funcdef_no=1, decl_uid=1765, cgraph_uid=1, symbol_order=1) */
+
+float
+test_2 (struct foo * lhs, struct foo * rhs)
+{
+  float result_1;
+  int i_2;
+  float result_3;
+  struct foo * lhs_5;
+  int _6;
+  struct foo * rhs_7;
+  int _8;
+  int i_9;
+  int _10;
+  float * _11;
+  long unsigned int _12;
+  long unsigned int _13;
+  float * _14;
+  float _15;
+  float * _16;
+  long unsigned int _17;
+  long unsigned int _18;
+  float * _19;
+  float _20;
+  float _21;
+  float result_22;
+  int i_23;
+  float _24;
+
+  bb_2:
+  result_3 = 0.0;
+  _6 = lhs_5->count;
+  _8 = rhs_7->count;
+  if (_6 != _8)
+    goto bb_3;
+  else
+    goto bb_4;
+
+  bb_3:
+  __builtin_abort ();
+
+  bb_4:
+  i_9 = 0;
+  goto bb_6;
+
+  bb_5:
+  _11 = lhs_5->data;
+  _12 = (long unsigned int) i_2;
+  _13 = _12 * 4;
+  _14 = _11 + _13;
+  _15 = *_14;
+  _16 = rhs_7->data;
+  _17 = (long unsigned int) i_2;
+  _18 = _17 * 4;
+  _19 = _16 + _18;
+  _20 = *_19;
+  _21 = _15 * _20;
+  result_22 = _21 + result_1;
+  i_23 = i_2 + 1;
+
+  bb_6:
+  result_1 = __PHI (/* bb_4:*/result_3, /* bb_5:*/result_22);
+  i_2 = __PHI (/* bb_4:*/i_9, /* bb_5:*/i_23);
+  _10 = lhs_5->count;
+  if (_10 > i_2)
+    goto bb_5;
+  else
+    goto bb_7;
+
+  bb_7:
+  _24 = result_1;
+
+  bb_8:
+label_5:
+  return _24;
+
+}
+
+

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]