From a55f87f5922a4188fba801020532c8f5a251efab Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 10 May 2016 16:20:48 -0400
Subject: [PATCH 37/42] FIXME: Barebones implementation of "__RTL"

---
 gcc/c-family/c-common.c         |  1 +
 gcc/c-family/c-common.h         |  3 ++
 gcc/c/c-parser.c                | 63 ++++++++++++++++++++++++++++++-
 gcc/read-md.c                   | 32 ++++++++++++++++
 gcc/read-md.h                   |  5 +++
 gcc/read-rtl-function.c         | 39 +++++++++++--------
 gcc/read-rtl-function.h         |  3 ++
 gcc/system.h                    |  2 +-
 gcc/testsuite/rtl.dg/test-rtl.c | 83 +++++++++++++++++++++++++++++++++++++++++
 9 files changed, 212 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/rtl.dg/test-rtl.c

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 48d8b05..67901b7 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -522,6 +522,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
   { "__volatile",	RID_VOLATILE,	0 },
   { "__volatile__",	RID_VOLATILE,	0 },
+  { "__RTL",		RID_RTL,	0 },
   { "alignas",		RID_ALIGNAS,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "alignof",		RID_ALIGNOF,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "asm",		RID_ASM,	D_ASM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 5bbf951..50244eb 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -118,6 +118,9 @@ enum rid
 
   RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
 
+  /* "__RTL", for the RTL-parsing extension to the C frontend.  */
+  RID_RTL,
+
   /* C11 */
   RID_ALIGNAS, RID_GENERIC,
 
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 5f610e9..8653684 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -59,6 +59,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-expr.h"
 #include "context.h"
 #include "gcc-rich-location.h"
+#include "read-rtl-function.h"
+#include "rtl.h"
+#include "emit-rtl.h"
+#include "cfgrtl.h"
 
 /* We need to walk over decls with incomplete struct/union/enum types
    after parsing the whole translation unit.
@@ -1417,6 +1421,8 @@ static tree c_parser_array_notation (location_t, c_parser *, tree, tree);
 static tree c_parser_cilk_clause_vectorlength (c_parser *, tree, bool);
 static void c_parser_cilk_grainsize (c_parser *, bool *);
 
+static void c_parser_parse_rtl_body (c_parser *parser);
+
 /* Parse a translation unit (C90 6.7, C99 6.9).
 
    translation-unit:
@@ -1659,6 +1665,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
   tree all_prefix_attrs;
   bool diagnosed_no_specs = false;
   location_t here = c_parser_peek_token (parser)->location;
+  bool rtl_body_p = false;
 
   if (static_assert_ok
       && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
@@ -1743,6 +1750,17 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       c_parser_skip_to_end_of_block_or_statement (parser);
       return;
     }
+
+  if (c_parser_next_token_is (parser, CPP_KEYWORD))
+    {
+      c_token *kw_token = c_parser_peek_token (parser);
+      if (kw_token->keyword == RID_RTL)
+	{
+	  rtl_body_p = true;
+	  c_parser_consume_token (parser);
+	}
+    }
+
   finish_declspecs (specs);
   bool auto_type_p = specs->typespec_word == cts_auto_type;
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -2125,7 +2143,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
         tv = TV_PARSE_INLINE;
       else
         tv = TV_PARSE_FUNC;
-      timevar_push (tv);
+      auto_timevar at (g_timer, tv);
 
       /* Parse old-style parameter declarations.  ??? Attributes are
 	 not allowed to start declaration specifiers here because of a
@@ -2152,6 +2170,12 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
+      if (rtl_body_p)
+	{
+	  c_parser_parse_rtl_body (parser);
+	  return;
+	}
+
       fnbody = c_parser_compound_statement (parser);
       if (flag_cilkplus && contains_array_notation_expr (fnbody))
 	fnbody = expand_array_notation_exprs (fnbody);
@@ -2174,7 +2198,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	  finish_function ();
 	}
 
-      timevar_pop (tv);
       break;
     }
 }
@@ -18230,4 +18253,40 @@ c_parser_array_notation (location_t loc, c_parser *parser, tree initial_index,
   return value_tree;
 }
 
+/* Parse the body of a function declaration marked with "__RTL".
+
+   The RTL parser works on the level of characters read from a
+   FILE *, whereas c_parser works at the level of tokens.
+   Square this circle by consuming all of the tokens,
+   recording the start/end of the RTL
+   fragment, and reopening the file and re-reading the relevant
+   lines within the RTL parser.  */
+
+void
+c_parser_parse_rtl_body (c_parser *parser)
+{
+  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    return;
+
+  location_t start_loc = c_parser_peek_token (parser)->location;
+  inform (start_loc, "start of RTL");
+
+  /* Consume all tokens, up to the closing brace.  */
+  while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+      c_parser_consume_token (parser);
+
+  /* At the closing brace; record its location.  */
+  location_t end_loc = c_parser_peek_token (parser)->location;
+  inform (end_loc, "end of RTL");
+
+  /* Consume the closing brace.  */
+  c_parser_consume_token (parser);
+
+  if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
+    return;
+
+  /* Using this requires un-poisoning rtl.h.  */
+  print_rtl_with_bb (stdout, get_insns (), 1024);
+}
+
 #include "gt-c-c-parser.h"
diff --git a/gcc/read-md.c b/gcc/read-md.c
index 7a7d849..90d3342 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -413,6 +413,16 @@ base_rtx_reader::read_char (void)
   LOG_SCOPE1 ("read_char: '%c'", ch);
   update_location (true);
 
+  /* If we're filtering lines, treat everything outside the
+     range of interest as a space.  */
+  if (m_first_line && m_last_line)
+    {
+      if (m_read_md_lineno < m_first_line)
+	return ' ';
+      if (m_read_md_lineno > m_last_line)
+	return EOF;
+    }
+
   return ch;
 }
 
@@ -1027,6 +1037,8 @@ base_rtx_reader::base_rtx_reader (line_maps *line_table)
   m_first_dir_md_include (NULL),
   m_last_dir_md_include_ptr (&m_first_dir_md_include),
   m_log_indent (0)
+  m_first_line (0),
+  m_last_line (0)
 {
   rtx_reader_line_table = m_line_table;
 
@@ -1372,6 +1384,26 @@ base_rtx_reader::read_md_files (int argc, const char **argv,
   return !seen_error ();
 }
 
+/* FIXME.  */
+
+bool
+rtx_reader::read_file_fragment (const char *filename,
+				int first_line,
+				int last_line)
+{
+  m_read_md_filename = filename;
+  m_read_md_file = fopen (m_read_md_filename, "r");
+  if (m_read_md_file == 0)
+    {
+      perror (m_read_md_filename);
+      return false;
+    }
+  m_first_line = first_line;
+  m_last_line = last_line;
+  handle_toplevel_file ();
+  return !seen_error ();
+}
+
 /* class noop_reader : public base_rtx_reader */
 
 /* A dummy implementation which skips unknown directives.  */
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 9d7ba75..c45029b 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -95,6 +95,9 @@ class base_rtx_reader
   virtual ~base_rtx_reader ();
 
   bool read_md_files (int, const char **, bool (*) (const char *));
+  bool read_file_fragment (const char *filename,
+			   int first_line,
+			   int last_line);
 
   /* A hook that handles a single .md-file directive, up to but not
      including the closing ')'.  It takes two arguments: the file position
@@ -171,6 +174,8 @@ class base_rtx_reader
   file_name_list **m_last_dir_md_include_ptr;
 
   int m_log_indent;
+  int m_first_line;
+  int m_last_line;
 };
 
 /* Global singleton; constrast with rtx_reader_ptr below.  */
diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c
index e8cafd4..ffddb85 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -1173,27 +1173,34 @@ function_reader::create_function ()
   else
     rtl_register_cfg_hooks ();
 
-  /* Create cfun.  */
-  tree fn_name = get_identifier ("test_1");
-  tree int_type = integer_type_node;
-  tree return_type = int_type;
-  tree arg_types[3] = {int_type, int_type, int_type};
-  tree fn_type = build_function_type_array (return_type, 3, arg_types);
-  tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
-				 fn_type);
-  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
-			     return_type);
-  DECL_ARTIFICIAL (resdecl) = 1;
-  DECL_IGNORED_P (resdecl) = 1;
-  DECL_RESULT (fndecl) = resdecl;
-  allocate_struct_function (fndecl, false);
-  /* This sets cfun.  */
+  /* When run from "rtl1", cfun is NULL.
+     When run from "cc1", cfun is the function tagged with "__RTL".  */
+  if (!cfun)
+    {
+      tree fn_name = get_identifier ("test_1");
+      tree int_type = integer_type_node;
+      tree return_type = int_type;
+      tree arg_types[3] = {int_type, int_type, int_type};
+      tree fn_type = build_function_type_array (return_type, 3, arg_types);
+      tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+				     fn_type);
+      tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+				 return_type);
+      DECL_ARTIFICIAL (resdecl) = 1;
+      DECL_IGNORED_P (resdecl) = 1;
+      DECL_RESULT (fndecl) = resdecl;
+      allocate_struct_function (fndecl, false);
+      /* This sets cfun.  */
+      current_function_decl = fndecl;
+    }
+  gcc_assert (cfun);
+  gcc_assert (current_function_decl);
+  tree fndecl = current_function_decl;
 
   /* Normally, various state gets set up by expand_function_start, e.g.
      crtl->return_rtx, based on DECL_RESULT (fndecl).
      We call it here to ensure the state is set up, with emit_insns as
      false, so no new instructions are emitted.  */
-  current_function_decl = fndecl;
   expand_function_start (fndecl, false);
 
   create_cfg_and_basic_blocks ();
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
index b4704dd..5ae83ed 100644
--- a/gcc/read-rtl-function.h
+++ b/gcc/read-rtl-function.h
@@ -54,4 +54,7 @@ extern bool read_rtl_function_body (int argc, const char **argv,
 				    bool (*parse_opt) (const char *),
 				    function_reader_policy *policy);
 
+extern bool read_rtl_function_body_from_file_range (location_t start_loc,
+						    location_t end_loc);
+
 #endif /* GCC_READ_RTL_FUNCTION_H */
diff --git a/gcc/system.h b/gcc/system.h
index 8a17197..2c97c1e 100644
--- a/gcc/system.h
+++ b/gcc/system.h
@@ -1022,7 +1022,7 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
 /* Front ends should never have to include middle-end headers.  Enforce
    this by poisoning the header double-include protection defines.  */
 #ifdef IN_GCC_FRONTEND
-#pragma GCC poison GCC_RTL_H GCC_EXCEPT_H GCC_EXPR_H
+//pragma GCC poison GCC_RTL_H GCC_EXCEPT_H GCC_EXPR_H
 #endif
 
 /* Note: not all uses of the `index' token (e.g. variable names and
diff --git a/gcc/testsuite/rtl.dg/test-rtl.c b/gcc/testsuite/rtl.dg/test-rtl.c
new file mode 100644
index 0000000..2eabc22
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/test-rtl.c
@@ -0,0 +1,83 @@
+/* Test of embedding RTL dump in a C function, tagged with "__RTL".
+
+   This is a dump of test.c from immediately after "expand".  */
+
+int __RTL test_1 (int i, int j, int k)
+{
+  (note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 6 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 3 2 4 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32])
+        (reg:SI 4 si [ j ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(insn 4 3 5 2 (set (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+        (reg:SI 1 dx [ k ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+     (nil))
+(note 5 4 8 2 NOTE_INSN_FUNCTION_BEG)
+(insn 8 5 9 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(insn 9 8 10 2 (set (reg:CCGC 17 flags)
+        (compare:CCGC (reg:SI 89)
+            (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -8 [0xfffffffffffffff8])) [1 j+0 S4 A32]))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil))
+(jump_insn 10 9 11 2 (set (pc)
+        (if_then_else (ge (reg:CCGC 17 flags)
+                (const_int 0 [0]))
+            (label_ref 16)
+            (pc))) ../../src/gcc/testsuite/rtl.dg/test.c:3 -1
+     (nil)
+ -> 16)
+(note 11 10 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 4 (set (reg:SI 90)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil))
+(insn 13 12 14 4 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (plus:SI (reg:SI 90)
+                    (const_int 4 [0x4])))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (expr_list:REG_EQUAL (plus:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+            (const_int 4 [0x4]))
+        (nil)))
+(jump_insn 14 13 15 4 (set (pc)
+        (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+     (nil)
+ -> 20)
+(barrier 15 14 16)
+(code_label 16 15 17 5 2 (nil) [1 uses])
+(note 17 16 18 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 5 (set (reg:SI 91)
+        (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (nil))
+(insn 19 18 20 5 (parallel [
+            (set (reg:SI 87 [ _1 ])
+                (neg:SI (reg:SI 91)))
+            (clobber (reg:CC 17 flags))
+        ]) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+     (expr_list:REG_EQUAL (neg:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+        (nil)))
+(code_label 20 19 21 6 3 (nil) [1 uses])
+(note 21 20 22 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 6 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _1 ])) -1
+     (nil))
+(insn 26 22 27 6 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+(insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+     (nil))
+
+}
-- 
1.8.5.3

