diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 15ead18..62b762b 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -437,6 +437,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__volatile__",	RID_VOLATILE,	0 },
   { "__GIMPLE",		RID_GIMPLE,	D_CONLY },
   { "__PHI",		RID_PHI,	D_CONLY },
+  { "__RTL",		RID_RTL,	D_CONLY },
   { "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 b838869..fc2ce87 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -124,6 +124,9 @@ enum rid
   /* "__PHI", for parsing PHI function in GIMPLE FE.  */
   RID_PHI,
 
+  /* "__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 6d443da..bcfae86 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -62,6 +62,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gcc-rich-location.h"
 #include "c-parser.h"
 #include "gimple-parser.h"
+#include "read-rtl-function.h"
+#include "run-rtl-passes.h"
 
 /* We need to walk over decls with incomplete struct/union/enum types
    after parsing the whole translation unit.
@@ -1311,6 +1313,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, char *start_with_pass);
+
 /* Parse a translation unit (C90 6.7, C99 6.9).
 
    translation-unit:
@@ -1547,7 +1551,11 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
    GIMPLE:
 
    gimple-function-definition:
-     declaration-specifiers[opt] __GIMPLE (gimple-pass-list) declarator
+     declaration-specifiers[opt] __GIMPLE (gimple-or-rtl-pass-list) declarator
+       declaration-list[opt] compound-statement
+
+   rtl-function-definition:
+     declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator
        declaration-list[opt] compound-statement  */
 
 static void
@@ -2043,7 +2051,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
@@ -2075,12 +2083,28 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
          function body as GIMPLE.  */
       if (specs->gimple_p)
 	{
-	  cfun->pass_startwith = specs->gimple_pass;
+	  cfun->pass_startwith = specs->gimple_or_rtl_pass;
 	  bool saved = in_late_binary_op;
 	  in_late_binary_op = true;
 	  c_parser_parse_gimple_body (parser);
 	  in_late_binary_op = saved;
 	}
+      /* Similarly, if it was marked with __RTL, use the RTL parser now,
+	 consuming the function body.  */
+      else if (specs->rtl_p)
+	{
+	  c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass);
+
+	  /* Normally, store_parm_decls sets next_is_function_body,
+	     anticipating a function body.  We need a push_scope/pop_scope
+	     pair to flush out this state, or subsequent function parsing
+	     will go wrong.  */
+	  push_scope ();
+	  pop_scope ();
+
+	  finish_function ();
+	  return;
+	}
       else
 	{
 	  fnbody = c_parser_compound_statement (parser);
@@ -2111,7 +2135,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       if (specs->gimple_p)
 	DECL_SAVED_TREE (fndecl) = NULL_TREE;
 
-      timevar_pop (tv);
       break;
     }
 }
@@ -2603,7 +2626,13 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  c_parser_consume_token (parser);
 	  specs->gimple_p = true;
 	  specs->locations[cdw_gimple] = loc;
-	  specs->gimple_pass = c_parser_gimple_pass_list (parser);
+	  specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
+	  break;
+	case RID_RTL:
+	  c_parser_consume_token (parser);
+	  specs->rtl_p = true;
+	  specs->locations[cdw_rtl] = loc;
+	  specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
 	  break;
 	default:
 	  goto out;
@@ -18281,4 +18310,74 @@ 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 up to and
+   including the closing brace, recording the start/end of the RTL
+   fragment, and reopening the file and re-reading the relevant
+   lines within the RTL parser.
+
+   This requires the opening and closing braces of the C function
+   to be on separate lines from the RTL they wrap.
+
+   Take ownership of START_WITH_PASS, if non-NULL.  */
+
+void
+c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass)
+{
+  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    {
+      free (start_with_pass);
+      return;
+    }
+
+  location_t start_loc = c_parser_peek_token (parser)->location;
+
+  /* Consume all tokens, up to the closing brace, handling
+     matching pairs of braces in the rtl dump.  */
+  int num_open_braces = 1;
+  while (1)
+    {
+      switch (c_parser_peek_token (parser)->type)
+	{
+	case CPP_OPEN_BRACE:
+	  num_open_braces++;
+	  break;
+	case CPP_CLOSE_BRACE:
+	  if (--num_open_braces == 0)
+	    goto found_closing_brace;
+	  break;
+	case CPP_EOF:
+	  error_at (start_loc, "no closing brace");
+	  free (start_with_pass);
+	  return;
+	default:
+	  break;
+	}
+      c_parser_consume_token (parser);
+    }
+
+ found_closing_brace:
+  /* At the closing brace; record its location.  */
+  location_t end_loc = c_parser_peek_token (parser)->location;
+
+  /* Consume the closing brace.  */
+  c_parser_consume_token (parser);
+
+  /* Invoke the RTL parser.  */
+  if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
+    {
+      free (start_with_pass);
+      return;
+    }
+
+ /*  If a pass name was provided for START_WITH_PASS, run the backend
+     accordingly now, on the cfun created above, transferring
+     ownership of START_WITH_PASS.  */
+  if (start_with_pass)
+    run_rtl_passes (start_with_pass);
+}
+
 #include "gt-c-c-parser.h"
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 2604884..39cd3a6 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -268,6 +268,7 @@ enum c_declspec_word {
   cdw_alignas,
   cdw_address_space,
   cdw_gimple,
+  cdw_rtl,
   cdw_number_of_elements /* This one must always be the last
 			    enumerator.  */
 };
@@ -291,8 +292,8 @@ struct c_declspecs {
      NULL; attributes (possibly from multiple lists) will be passed
      separately.  */
   tree attrs;
-  /* The pass to start compiling a __GIMPLE function with.  */
-  char *gimple_pass;
+  /* The pass to start compiling a __GIMPLE or __RTL function with.  */
+  char *gimple_or_rtl_pass;
   /* The base-2 log of the greatest alignment required by an _Alignas
      specifier, in bytes, or -1 if no such specifiers with nonzero
      alignment.  */
@@ -367,6 +368,8 @@ struct c_declspecs {
   BOOL_BITFIELD alignas_p : 1;
   /* Whether any __GIMPLE specifier was specified.  */
   BOOL_BITFIELD gimple_p : 1;
+  /* Whether any __RTL specifier was specified.  */
+  BOOL_BITFIELD rtl_p : 1;
   /* The address space that the declaration belongs to.  */
   addr_space_t address_space;
 };
diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c
index 291bbf6..e68905c 100644
--- a/gcc/c/gimple-parser.c
+++ b/gcc/c/gimple-parser.c
@@ -1008,18 +1008,18 @@ c_parser_gimple_label (c_parser *parser, gimple_seq *seq)
   return;
 }
 
-/* Parse gimple pass list.
+/* Parse gimple/RTL pass list.
 
-   gimple-pass-list:
+   gimple-or-rtl-pass-list:
      startwith("pass-name")
  */
 
 char *
-c_parser_gimple_pass_list (c_parser *parser)
+c_parser_gimple_or_rtl_pass_list (c_parser *parser)
 {
   char *pass = NULL;
 
-  /* Accept __GIMPLE.  */
+  /* Accept __GIMPLE/__RTL.  */
   if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
     return NULL;
   c_parser_consume_token (parser);
diff --git a/gcc/c/gimple-parser.h b/gcc/c/gimple-parser.h
index fd36ce1..85cf13a 100644
--- a/gcc/c/gimple-parser.h
+++ b/gcc/c/gimple-parser.h
@@ -22,6 +22,6 @@ along with GCC; see the file COPYING3.  If not see
 
 /* Gimple parsing functions.  */
 extern void c_parser_parse_gimple_body (c_parser *);
-extern char *c_parser_gimple_pass_list (c_parser *);
+extern char *c_parser_gimple_or_rtl_pass_list (c_parser *);
 
 #endif
diff --git a/gcc/function.h b/gcc/function.h
index fb3cbbc..ec5a9a3 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -236,7 +236,7 @@ struct GTY(()) function {
   /* The loops in this function.  */
   struct loops *x_current_loops;
 
-  /* Filled by the GIMPLE FE, pass to start compilation with.  */
+  /* Filled by the GIMPLE and RTL FEs, pass to start compilation with.  */
   char *pass_startwith;
 
   /* The stack usage of this function.  */
