diff mbox

Add "__RTL" to cc1 (v2)

Message ID 1475855912-44611-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Oct. 7, 2016, 3:58 p.m. UTC
On Wed, 2016-10-05 at 16:09 +0000, Joseph Myers wrote:
> On Wed, 5 Oct 2016, David Malcolm wrote:
> 
> > @@ -1752,6 +1759,35 @@ 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)
> 
> if (c_parser_next_token_is_keyword (parser, RID_RTL))
> 
> You're missing an update to the comment above this function to show
> what
> the new syntax is.

Thanks.  Here's an updated version of the patch which fixes that,
along with some other fixes:
* Use c_parser_next_token_is_keyword.
* Removed a stray "FIXME".
* Removed some debug code.
* Add more comments
* Fixed a typo in the ChangeLog ("__RID" -> "__RTL")

Blurb from original version:

This patch implements Richi's idea of having a custom __RTL marker
in C function definitions, to indicate that the body of the function
is to be parsed as RTL, rather than C:

int __RTL test_fn_1 (int i)
{
 (function "times_two"
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     ;; etc
   ) ;; insn-chain
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
  ) ;; function
}

This allows for decls and types to be declared in C, and to use
the function decl from the C frontend.

I added support for running a single pass by giving __RTL an optional
parameter (the name of the pass).  For example:

int __RTL ("rtl-dfinit") test_fn_2 (int i)
{
 (function "times_two"
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     ;; etc
   ) ;; insn-chain
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
  ) ;; function
}

The top-level "function" directive is rather redundant; perhaps it should
be omitted?  This would give e.g.:

int __RTL ("rtl-dfinit") test_fn_3 (int i)
{
   (insn-chain
     (note 1 0 4 (nil) NOTE_INSN_DELETED)
     ;; etc
   ) ;; insn-chain
   (crtl
     (return_rtx
       (reg/i:SI 0 ax)
     ) ;; return_rtx
   ) ;; crtl
}

(Though maybe we want to keep it as a place to hold top-level metadata)

gcc/c-family/ChangeLog:
	* c-common.c (c_common_reswords): Add "__RTL".
	* c-common.h (enum rid): Add RID_RTL.

gcc/c/ChangeLog:
	* c-parser.c: Include "read-rtl-function.h" and
	"run-one-rtl-pass.h".
	(c_parser_declaration_or_fndef): In the "GNU extensions" part of
	the leading comment, add an alternate production for
	"function-definition", along with new "rtl-body-specifier" and
	"rtl-body-pass-specifier" productions.  Handle "__RTL" by calling
	c_parser_parse_rtl_body.  Convert a timevar_push/pop pair
	to an auto_timevar, to cope with early exit.
	(c_parser_parse_rtl_body): New function.

gcc/ChangeLog:
	* read-md.c (base_rtx_reader::read_char): Support filtering
	the input to a subset of line numbers.
	(base_rtx_reader::base_rtx_reader): Initialize fields
	m_first_line and m_last_line.
	(base_rtx_reader::read_file_fragment): New method.
	* read-md.h (base_rtx_reader::read_file_fragment): New decl.
	(base_rtx_reader::m_first_line): New field.
	(base_rtx_reader::m_last_line): New field.
	* read-rtl-function.c (function_reader::create_function): Only create
	cfun if it doesn't already exist.
	(read_rtl_function_body_from_file_range): New function.
	* read-rtl-function.h (read_rtl_function_body_from_file_range):
	New decl.

gcc/testsuite/ChangeLog:
	* rtl.dg/rtl.exp: Add .c files below rtl.dg to "tests".
	* rtl.dg/x86_64/different-structs.c: New file.
	* rtl.dg/x86_64/test-return-const.c.after-expand.c: New file.
	* rtl.dg/x86_64/test-return-const.c.before-fwprop.c: New file.
	* rtl.dg/x86_64/test-rtl.c: New file.
	* rtl.dg/x86_64/times-two.c.after-expand.c: New file.
	* rtl.dg/x86_64/times-two.c.before-df.c: New file.
---
 gcc/c-family/c-common.c                            |   1 +
 gcc/c-family/c-common.h                            |   3 +
 gcc/c/c-parser.c                                   | 113 ++++++++++++++++++++-
 gcc/read-md.c                                      |  34 ++++++-
 gcc/read-md.h                                      |   7 ++
 gcc/read-rtl-function.c                            |  78 ++++++++++----
 gcc/read-rtl-function.h                            |   3 +
 gcc/testsuite/rtl.dg/rtl.exp                       |   4 +-
 gcc/testsuite/rtl.dg/x86_64/different-structs.c    | 101 ++++++++++++++++++
 .../x86_64/test-return-const.c.after-expand.c      |  23 +++++
 .../x86_64/test-return-const.c.before-fwprop.c     |  27 +++++
 gcc/testsuite/rtl.dg/x86_64/test-rtl.c             |  95 +++++++++++++++++
 .../rtl.dg/x86_64/times-two.c.after-expand.c       |  40 ++++++++
 .../rtl.dg/x86_64/times-two.c.before-df.c          |  57 +++++++++++
 14 files changed, 565 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/different-structs.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-rtl.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
 create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c

Comments

Richard Biener Oct. 13, 2016, 1:49 p.m. UTC | #1
On Fri, Oct 7, 2016 at 5:58 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Wed, 2016-10-05 at 16:09 +0000, Joseph Myers wrote:
>> On Wed, 5 Oct 2016, David Malcolm wrote:
>>
>> > @@ -1752,6 +1759,35 @@ 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)
>>
>> if (c_parser_next_token_is_keyword (parser, RID_RTL))
>>
>> You're missing an update to the comment above this function to show
>> what
>> the new syntax is.
>
> Thanks.  Here's an updated version of the patch which fixes that,
> along with some other fixes:
> * Use c_parser_next_token_is_keyword.
> * Removed a stray "FIXME".
> * Removed some debug code.
> * Add more comments
> * Fixed a typo in the ChangeLog ("__RID" -> "__RTL")
>
> Blurb from original version:
>
> This patch implements Richi's idea of having a custom __RTL marker
> in C function definitions, to indicate that the body of the function
> is to be parsed as RTL, rather than C:
>
> int __RTL test_fn_1 (int i)
> {
>  (function "times_two"
>    (insn-chain
>      (note 1 0 4 (nil) NOTE_INSN_DELETED)
>      ;; etc
>    ) ;; insn-chain
>    (crtl
>      (return_rtx
>        (reg/i:SI 0 ax)
>      ) ;; return_rtx
>    ) ;; crtl
>   ) ;; function
> }
>
> This allows for decls and types to be declared in C, and to use
> the function decl from the C frontend.
>
> I added support for running a single pass by giving __RTL an optional
> parameter (the name of the pass).  For example:

So what's the default behavior?

> int __RTL ("rtl-dfinit") test_fn_2 (int i)
> {
>  (function "times_two"
>    (insn-chain
>      (note 1 0 4 (nil) NOTE_INSN_DELETED)
>      ;; etc
>    ) ;; insn-chain
>    (crtl
>      (return_rtx
>        (reg/i:SI 0 ax)
>      ) ;; return_rtx
>    ) ;; crtl
>   ) ;; function
> }

Does it really run a single pass only?  Thus you can't do a { dg-do run } test
with __RTL?  The GIMPLE FE has a __GIMPLE (starts-with: "pass") thing
starting from a specific pass but going all the way to assembly output.

It looks like your run-one-rtl-pass thingy is directly invoked from
the "frontend"
rather than passing down everything to the middle-end?

Richard.

> The top-level "function" directive is rather redundant; perhaps it should
> be omitted?  This would give e.g.:
>
> int __RTL ("rtl-dfinit") test_fn_3 (int i)
> {
>    (insn-chain
>      (note 1 0 4 (nil) NOTE_INSN_DELETED)
>      ;; etc
>    ) ;; insn-chain
>    (crtl
>      (return_rtx
>        (reg/i:SI 0 ax)
>      ) ;; return_rtx
>    ) ;; crtl
> }
>
> (Though maybe we want to keep it as a place to hold top-level metadata)
>
> gcc/c-family/ChangeLog:
>         * c-common.c (c_common_reswords): Add "__RTL".
>         * c-common.h (enum rid): Add RID_RTL.
>
> gcc/c/ChangeLog:
>         * c-parser.c: Include "read-rtl-function.h" and
>         "run-one-rtl-pass.h".
>         (c_parser_declaration_or_fndef): In the "GNU extensions" part of
>         the leading comment, add an alternate production for
>         "function-definition", along with new "rtl-body-specifier" and
>         "rtl-body-pass-specifier" productions.  Handle "__RTL" by calling
>         c_parser_parse_rtl_body.  Convert a timevar_push/pop pair
>         to an auto_timevar, to cope with early exit.
>         (c_parser_parse_rtl_body): New function.
>
> gcc/ChangeLog:
>         * read-md.c (base_rtx_reader::read_char): Support filtering
>         the input to a subset of line numbers.
>         (base_rtx_reader::base_rtx_reader): Initialize fields
>         m_first_line and m_last_line.
>         (base_rtx_reader::read_file_fragment): New method.
>         * read-md.h (base_rtx_reader::read_file_fragment): New decl.
>         (base_rtx_reader::m_first_line): New field.
>         (base_rtx_reader::m_last_line): New field.
>         * read-rtl-function.c (function_reader::create_function): Only create
>         cfun if it doesn't already exist.
>         (read_rtl_function_body_from_file_range): New function.
>         * read-rtl-function.h (read_rtl_function_body_from_file_range):
>         New decl.
>
> gcc/testsuite/ChangeLog:
>         * rtl.dg/rtl.exp: Add .c files below rtl.dg to "tests".
>         * rtl.dg/x86_64/different-structs.c: New file.
>         * rtl.dg/x86_64/test-return-const.c.after-expand.c: New file.
>         * rtl.dg/x86_64/test-return-const.c.before-fwprop.c: New file.
>         * rtl.dg/x86_64/test-rtl.c: New file.
>         * rtl.dg/x86_64/times-two.c.after-expand.c: New file.
>         * rtl.dg/x86_64/times-two.c.before-df.c: New file.
> ---
>  gcc/c-family/c-common.c                            |   1 +
>  gcc/c-family/c-common.h                            |   3 +
>  gcc/c/c-parser.c                                   | 113 ++++++++++++++++++++-
>  gcc/read-md.c                                      |  34 ++++++-
>  gcc/read-md.h                                      |   7 ++
>  gcc/read-rtl-function.c                            |  78 ++++++++++----
>  gcc/read-rtl-function.h                            |   3 +
>  gcc/testsuite/rtl.dg/rtl.exp                       |   4 +-
>  gcc/testsuite/rtl.dg/x86_64/different-structs.c    | 101 ++++++++++++++++++
>  .../x86_64/test-return-const.c.after-expand.c      |  23 +++++
>  .../x86_64/test-return-const.c.before-fwprop.c     |  27 +++++
>  gcc/testsuite/rtl.dg/x86_64/test-rtl.c             |  95 +++++++++++++++++
>  .../rtl.dg/x86_64/times-two.c.after-expand.c       |  40 ++++++++
>  .../rtl.dg/x86_64/times-two.c.before-df.c          |  57 +++++++++++
>  14 files changed, 565 insertions(+), 21 deletions(-)
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/different-structs.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/test-rtl.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
>  create mode 100644 gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
>
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index 491c637..ecef32b 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -524,6 +524,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 c88619b..e19751e 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 6bc42da..693d1bd 100644
> --- a/gcc/c/c-parser.c
> +++ b/gcc/c/c-parser.c
> @@ -59,6 +59,8 @@ 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 "run-one-rtl-pass.h"
>
>  /* We need to walk over decls with incomplete struct/union/enum types
>     after parsing the whole translation unit.
> @@ -1421,6 +1423,9 @@ 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,
> +                                    const char *single_pass_name);
> +
>  /* Parse a translation unit (C90 6.7, C99 6.9).
>
>     translation-unit:
> @@ -1624,6 +1629,16 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
>       declaration-specifiers declarator declaration-list[opt]
>         compound-statement
>
> +   function-definition:
> +     declaration-specifiers rtl-body-specifier declarator declaration-list[opt]
> +       compound-statement
> +
> +   rtl-body-specifier:
> +     __RTL rtl-body-pass-specifier[opt]
> +
> +   rtl-body-pass-specifier:
> +     ( string )
> +
>     attribute ;
>
>     Objective-C:
> @@ -1668,6 +1683,8 @@ 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;
> +  const char *single_pass_name = NULL;
>
>    if (static_assert_ok
>        && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
> @@ -1752,6 +1769,33 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>        c_parser_skip_to_end_of_block_or_statement (parser);
>        return;
>      }
> +
> +  /* Handle GNU extension rtl-body-specifier by detecting "__RTL".  */
> +  if (c_parser_next_token_is_keyword (parser, RID_RTL))
> +    {
> +      rtl_body_p = true;
> +      c_parser_consume_token (parser);
> +
> +      /* Handle the optional rtl-body-pass-specifier: parens wrapping
> +        a string, giving a pass name.  */
> +      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
> +       {
> +         c_parser_consume_token (parser);
> +         c_token *tok = c_parser_peek_token (parser);
> +         if (tok->type != CPP_STRING)
> +           {
> +             c_parser_error (parser, "expected string");
> +             c_parser_skip_to_end_of_block_or_statement (parser);
> +             return;
> +           }
> +         gcc_assert (TREE_CODE (tok->value) == STRING_CST);
> +         single_pass_name = TREE_STRING_POINTER (tok->value);
> +         c_parser_consume_token (parser);
> +
> +         c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
> +       }
> +    }
> +
>    finish_declspecs (specs);
>    bool auto_type_p = specs->typespec_word == cts_auto_type;
>    if (c_parser_next_token_is (parser, CPP_SEMICOLON))
> @@ -2146,7 +2190,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
> @@ -2173,6 +2217,15 @@ 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 we had an rtl-body-specifier, use the RTL parser now,
> +        consuming the function body.  */
> +      if (rtl_body_p)
> +       {
> +         c_parser_parse_rtl_body (parser, single_pass_name);
> +         return;
> +       }
> +
>        fnbody = c_parser_compound_statement (parser);
>        if (flag_cilkplus && contains_array_notation_expr (fnbody))
>         fnbody = expand_array_notation_exprs (fnbody);
> @@ -2195,7 +2248,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>           finish_function ();
>         }
>
> -      timevar_pop (tv);
>        break;
>      }
>  }
> @@ -18313,4 +18365,61 @@ 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.  */
> +
> +void
> +c_parser_parse_rtl_body (c_parser *parser, const char *single_pass_name)
> +{
> +  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
> +    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;
> +       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))
> +    return;
> +
> + /*  If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
> +      on cfun, as created above.  */
> +  if (single_pass_name)
> +    run_one_rtl_pass_by_name (single_pass_name);
> +}
> +
>  #include "gt-c-c-parser.h"
> diff --git a/gcc/read-md.c b/gcc/read-md.c
> index be55777..e713466 100644
> --- a/gcc/read-md.c
> +++ b/gcc/read-md.c
> @@ -419,6 +419,16 @@ base_rtx_reader::read_char (void)
>    else
>      m_read_md_colno++;
>
> +  /* 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;
>  }
>
> @@ -1000,7 +1010,9 @@ base_rtx_reader::base_rtx_reader ()
>    m_read_md_lineno (0),
>    m_read_md_colno (0),
>    m_first_dir_md_include (NULL),
> -  m_last_dir_md_include_ptr (&m_first_dir_md_include)
> +  m_last_dir_md_include_ptr (&m_first_dir_md_include),
> +  m_first_line (0),
> +  m_last_line (0)
>  {
>    /* Set the global singleton pointer.  */
>    base_rtx_reader_ptr = this;
> @@ -1307,6 +1319,26 @@ base_rtx_reader::read_md_files (int argc, const char **argv,
>    return !have_error;
>  }
>
> +/* Read FILENAME, filtering to just the given lines.  */
> +
> +bool
> +base_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 !have_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 4933912..2058002 100644
> --- a/gcc/read-md.h
> +++ b/gcc/read-md.h
> @@ -98,6 +98,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
> @@ -159,6 +162,10 @@ class base_rtx_reader
>
>    /* A pointer to the null terminator of the md include chain.  */
>    file_name_list **m_last_dir_md_include_ptr;
> +
> +  /* If non-zero, filter the input to just this subset of lines.  */
> +  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 0723585..73493ec 100644
> --- a/gcc/read-rtl-function.c
> +++ b/gcc/read-rtl-function.c
> @@ -593,23 +593,31 @@ function_reader::create_function ()
>    else
>      rtl_register_cfg_hooks ();
>
> -  /* Create cfun.  */
> -  tree fn_name = get_identifier (m_name ? m_name : "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;
> +  /* When run from selftests or "rtl1", cfun is NULL.
> +     When run from "cc1" for a C function tagged with __RTL, cfun is the
> +     tagged function.  */
> +  if (!cfun)
> +    {
> +      tree fn_name = get_identifier (m_name ? m_name : "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;
>
>    cfun->curr_properties = (PROP_cfg | PROP_rtl);
>
> @@ -1817,6 +1825,42 @@ read_rtl_function_body (int argc, const char **argv,
>    return true;
>  }
>
> +/* Run the RTL dump parser on the range of lines between START_LOC and
> +   END_LOC (including those lines).  */
> +
> +bool
> +read_rtl_function_body_from_file_range (location_t start_loc,
> +                                       location_t end_loc)
> +{
> +  expanded_location exploc_start = expand_location (start_loc);
> +  expanded_location exploc_end = expand_location (end_loc);
> +
> +  if (exploc_start.file != exploc_end.file)
> +    {
> +      error_at (end_loc, "start/end of RTL fragment are in different files");
> +      return false;
> +    }
> +  if (exploc_start.line >= exploc_end.line)
> +    {
> +      error_at (end_loc,
> +               "start of RTL fragment must be on an earlier line than end");
> +      return false;
> +    }
> +
> +  in_rtl_frontend_p = true;
> +
> +  initialize_rtl ();
> +  init_emit ();
> +  init_varasm_status ();
> +
> +  function_reader reader (NULL);
> +  if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
> +                                 exploc_end.line - 1))
> +    return false;
> +
> +  return true;
> +}
> +
>  #if CHECKING_P
>
>  namespace selftest {
> diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
> index d26c797..c69d308 100644
> --- a/gcc/read-rtl-function.h
> +++ b/gcc/read-rtl-function.h
> @@ -34,4 +34,7 @@ extern bool read_rtl_function_body (int argc, const char **argv,
>                                     function_reader_policy *policy,
>                                     int *out_pseudo_offset);
>
> +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/testsuite/rtl.dg/rtl.exp b/gcc/testsuite/rtl.dg/rtl.exp
> index 71bebb9..6c7c7f4 100644
> --- a/gcc/testsuite/rtl.dg/rtl.exp
> +++ b/gcc/testsuite/rtl.dg/rtl.exp
> @@ -29,8 +29,10 @@ if ![info exists DEFAULT_RTLFLAGS] then {
>  # Initialize `dg'.
>  dg-init
>
> -# Gather a list of all tests.
> +# Gather a list of all tests: both .rtl tests for use with rtl1, and .c tests
> +# for use with cc1.
>  set tests [lsort [find $srcdir/$subdir *.rtl]]
> +set tests [concat $tests [lsort [find $srcdir/$subdir *.c]]]
>
>  verbose "rtl.exp tests: $tests" 1
>
> diff --git a/gcc/testsuite/rtl.dg/x86_64/different-structs.c b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
> new file mode 100644
> index 0000000..d5c0bed
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
> @@ -0,0 +1,101 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +
> +extern double sqrt(double x);
> +
> +struct foo
> +{
> +  double x;
> +  double y;
> +};
> +
> +struct bar
> +{
> +  double x;
> +  double y;
> +};
> +
> +double __RTL test (struct foo *f, const struct bar *b)
> +{
> +#if 0
> +  /* Result of "expand" on this C code, compiled for x86_64 with -Os.  */
> +  f->x += b->x;
> +  f->y += b->y;
> +  return sqrt (f->x * f->x + f->y * f->y);
> +#endif
> +(function "test"
> +  (insn-chain
> +    (note 1 0 5 (nil) NOTE_INSN_DELETED)
> +    (note 5 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +    (insn 2 5 3 2 (set (reg/v/f:DI 97 [ f ])
> +                (reg:DI 5 di [ f ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
> +             (nil))
> +    (insn 3 2 4 2 (set (reg/v/f:DI 98 [ b ])
> +                (reg:DI 4 si [ b ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
> +             (nil))
> +    (note 4 3 7 2 NOTE_INSN_FUNCTION_BEG)
> +    (insn 7 4 8 2 (set (reg:DF 99)
> +                (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
> +             (nil))
> +    (insn 8 7 9 2 (set (reg:DF 89 [ _3 ])
> +                (plus:DF (reg:DF 99)
> +                    (mem:DF (reg/v/f:DI 98 [ b ]) [2 b_12(D)->x+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
> +             (nil))
> +    (insn 9 8 10 2 (set (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])
> +                (reg:DF 89 [ _3 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
> +             (nil))
> +    (insn 10 9 11 2 (set (reg:DF 100)
> +                (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
> +                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
> +             (nil))
> +    (insn 11 10 12 2 (set (reg:DF 92 [ _6 ])
> +                (plus:DF (reg:DF 100)
> +                    (mem:DF (plus:DI (reg/v/f:DI 98 [ b ])
> +                            (const_int 8 [0x8])) [2 b_12(D)->y+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
> +             (nil))
> +    (insn 12 11 13 2 (set (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
> +                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])
> +                (reg:DF 92 [ _6 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
> +             (nil))
> +    (insn 13 12 14 2 (set (reg:DF 101)
> +                (mult:DF (reg:DF 89 [ _3 ])
> +                    (reg:DF 89 [ _3 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (nil))
> +    (insn 14 13 15 2 (set (reg:DF 102)
> +                (mult:DF (reg:DF 92 [ _6 ])
> +                    (reg:DF 92 [ _6 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (nil))
> +    (insn 15 14 16 2 (set (reg:DF 103)
> +                (plus:DF (reg:DF 101)
> +                    (reg:DF 102))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (nil))
> +    (insn 16 15 17 2 (set (reg:DF 21 xmm0)
> +                (reg:DF 103)) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (nil))
> +    (call_insn/j 17 16 18 2 (set (reg:DF 21 xmm0)
> +                (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
> +                    (const_int 0 [0]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
> +             (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>)
> +                (expr_list:REG_EH_REGION (const_int 0 [0])
> +                    (nil)))
> +            (expr_list:DF (use (reg:DF 21 xmm0))
> +                (nil)))
> +    (barrier 18 17 0)
> +  ) ;; insn-chain
> +  (cfg
> +    (bb 0
> +      (edge 0 2 (flags 0x1))
> +    ) ;; bb
> +    (bb 2
> +      (edge 2 1 (flags 0x1002))
> +    ) ;; bb
> +    (bb 1
> +    ) ;; bb
> +  ) ;; cfg
> +  (crtl
> +    (return_rtx
> +      (reg/i:DF 21 xmm0)
> +    ) ;; return_rtx
> +  ) ;; crtl
> +) ;; function "test"
> +
> +}
> diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
> new file mode 100644
> index 0000000..11b6f24
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
> @@ -0,0 +1,23 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +
> +int __RTL test_returning_constant (void)
> +{
> +  /* C code:
> +     return 42; */
> +
> +  (function "test_returning_constant"
> +    (insn-chain
> +      (note 1 0 3 (nil) NOTE_INSN_DELETED)
> +      (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
> +      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
> +           (const_int 42 [0x2a])) test-return-const.c:3 -1
> +         (nil))
> +      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
> +             (reg:SI 87 [ <retval> ])) test-return-const.c:4 -1
> +         (nil))
> +      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
> +         (nil))
> +     ) ;; insn-chain
> +   );; function
> +}
> diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
> new file mode 100644
> index 0000000..83594b3
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-fwprop1" } */
> +
> +int __RTL ("rtl-fwprop1") test_returning_constant (void)
> +{
> +  /* C code:
> +     return 42; */
> +  (function "test"
> +    (insn-chain
> +      (note 3 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
> +      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
> +        (const_int 42 [0x2a])) test-return-const.c:3 82 {*movsi_internal}
> +        (nil))
> +      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
> +       (const_int 42 [0x2a])) test-return-const.c:4 82 {*movsi_internal}
> +        (expr_list:REG_DEAD (reg:SI 87 [ <retval> ])
> +        (nil)))
> +      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
> +       (nil))
> +    ) ;; insn-chain
> +  ) ;; function
> +}
> +
> +/* Verify that insn 5 is eliminated.  */
> +/* { dg-final { scan-rtl-dump "deferring deletion of insn with uid = 5" "fwprop1" } } */
> +/* { dg-final { scan-rtl-dump "Deleted 1 trivially dead insns" "fwprop1" } } */
> diff --git a/gcc/testsuite/rtl.dg/x86_64/test-rtl.c b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
> new file mode 100644
> index 0000000..0ffeab7
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
> @@ -0,0 +1,95 @@
> +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
> +
> +/* Test of embedding RTL dump in a C function, tagged with "__RTL".
> +
> +   This is a dump of test.c from immediately after "expand", for x86_64.  */
> +
> +int __RTL test_1 (int i, int j, int k)
> +{
> +  /*
> +    if (i < j)
> +      return k + 4;
> +    else
> +      return -k;
> +  */
> +  (function "test_1"
> +   (insn-chain
> +  (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))
> +
> +    ) ;; insn-chain
> +   ) ;; function
> +}
> diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
> new file mode 100644
> index 0000000..8536bf4
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
> @@ -0,0 +1,40 @@
> +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
> +
> +int __RTL times_two (int i)
> +{
> +  /* C function:
> +     return i * 2;  */
> +  (function "times_two"
> +    (insn-chain
> +  (note 1 0 4 (nil) NOTE_INSN_DELETED)
> +  (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +  (insn 2 4 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 ])) times-two.c:2 -1
> +     (nil))
> +  (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
> +  (insn 6 3 7 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])) times-two.c:3 -1
> +     (nil))
> +  (insn 7 6 10 2 (parallel [
> +            (set (reg:SI 87 [ _2 ])
> +                (ashift:SI (reg:SI 89)
> +                    (const_int 1 [0x1])))
> +            (clobber (reg:CC 17 flags))
> +        ]) times-two.c:3 -1
> +     (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
> +                    (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
> +            (const_int 1 [0x1]))
> +        (nil)))
> +  (insn 10 7 14 2 (set (reg:SI 88 [ <retval> ])
> +        (reg:SI 87 [ _2 ])) times-two.c:3 -1
> +     (nil))
> +  (insn 14 10 15 2 (set (reg/i:SI 0 ax)
> +        (reg:SI 88 [ <retval> ])) times-two.c:4 -1
> +     (nil))
> +  (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
> +     (nil))
> +    ) ;; insn-chain
> +  ) ;; function
> +}
> diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
> new file mode 100644
> index 0000000..b4d20a7
> --- /dev/null
> +++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
> @@ -0,0 +1,57 @@
> +/* { dg-do compile { target x86_64-*-* } } */
> +/* { dg-options "-fdump-rtl-dfinit" } */
> +
> +int __RTL ("rtl-dfinit") times_two (int i)
> +{
> +  /* C function:
> +     return i * 2;  */
> + (function "times_two"
> +  (insn-chain
> +   (note 1 0 4 (nil) NOTE_INSN_DELETED)
> +   (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
> +   (insn 2 4 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
> +                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
> +        (reg:SI 5 di [ i ])) times-two.c:2 82 {*movsi_internal}
> +     (nil))
> +   (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
> +   (insn 6 3 7 2 (set (reg:SI 89)
> +        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
> +                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) times-two.c:3 82 {*movsi_internal}
> +     (nil))
> +   (insn 7 6 10 2 (parallel [
> +            (set (reg:SI 87 [ _2 ])
> +                (ashift:SI (reg:SI 89)
> +                    (const_int 1 [0x1])))
> +            (clobber (reg:CC 17 flags))
> +        ]) times-two.c:3 529 {*ashlsi3_1}
> +     (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
> +                    (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
> +            (const_int 1 [0x1]))
> +        (nil)))
> +   (insn 10 7 14 2 (set (reg:SI 88 [ <retval> ])
> +        (reg:SI 87 [ _2 ])) times-two.c:3 82 {*movsi_internal}
> +     (nil))
> +   (insn 14 10 15 2 (set (reg/i:SI 0 ax)
> +        (reg:SI 88 [ <retval> ])) times-two.c:4 82 {*movsi_internal}
> +     (nil))
> +   (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
> +     (nil))
> +   ) ;; insn-chain
> +
> +   (crtl
> +     (return_rtx
> +       (reg/i:SI 0 ax)
> +     ) ;; return_rtx
> +   ) ;; crtl
> +  ) ;; function
> +}
> +
> +/* Verify that the dataflow information matches what cc1 would have
> +   generated.  In particular, in earlier versions of the RTL
> +   frontend, the exit block use of reg 0 (ax) wasn't picked up
> +   on, due to not setting up crtl->return_rtx based on
> +   DECL_RESULT (fndecl).  */
> +
> +/* { dg-final { scan-rtl-dump ";;  exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
> +
> +/* { dg-final { scan-rtl-dump ";;  regs ever live.*0 .ax. 5 .di. 17 .flags." "dfinit" } } */
> --
> 1.8.5.3
>
Bernd Schmidt Oct. 13, 2016, 1:51 p.m. UTC | #2
On 10/13/2016 03:49 PM, Richard Biener wrote:
> Does it really run a single pass only?  Thus you can't do a { dg-do run } test
> with __RTL?

I think that's really not the intended use-case. To my mind this is for 
unit-testing: ensuring that a given rtl pass performs the expected 
transformation on an input.


Bernd
Richard Biener Oct. 14, 2016, 9:33 a.m. UTC | #3
On Thu, Oct 13, 2016 at 3:51 PM, Bernd Schmidt <bschmidt@redhat.com> wrote:
> On 10/13/2016 03:49 PM, Richard Biener wrote:
>>
>> Does it really run a single pass only?  Thus you can't do a { dg-do run }
>> test
>> with __RTL?
>
>
> I think that's really not the intended use-case. To my mind this is for
> unit-testing: ensuring that a given rtl pass performs the expected
> transformation on an input.

Ok, so at least for the GIMPLE FE side I thought it's useful to allow
a correctness verification with something simpler than pattern matching
on the pass output.  By means of doing runtime verification of an expected
result (this necessarily includes running followup passes as we have to
generate code).  I don't see why this shouldn't apply to __RTL -- it might
be more difficult to get __RTL testcases to the point where they emit
assembly of course.

OTOH the question then still is what's the default behavior if you do _not_
specify a "single pass to run".

Richard.

>
> Bernd
Bernd Schmidt Oct. 14, 2016, 9:48 a.m. UTC | #4
On 10/14/2016 11:33 AM, Richard Biener wrote:

> Ok, so at least for the GIMPLE FE side I thought it's useful to allow
> a correctness verification with something simpler than pattern matching
> on the pass output.  By means of doing runtime verification of an expected
> result (this necessarily includes running followup passes as we have to
> generate code).  I don't see why this shouldn't apply to __RTL -- it might
> be more difficult to get __RTL testcases to the point where they emit
> assembly of course.

Also, if this ends up with a lot of testcases, I still think it would be 
best to have these use a special rtl-test port so that the tests don't 
become a maintenance burden for real ports, and so that we can construct 
the tests any way we like.
Such a port might not even be able to produce executable code (unless 
you also want to write a sim).


Bernd
Richard Biener Oct. 14, 2016, 9:50 a.m. UTC | #5
On Fri, Oct 14, 2016 at 11:48 AM, Bernd Schmidt <bschmidt@redhat.com> wrote:
> On 10/14/2016 11:33 AM, Richard Biener wrote:
>
>> Ok, so at least for the GIMPLE FE side I thought it's useful to allow
>> a correctness verification with something simpler than pattern matching
>> on the pass output.  By means of doing runtime verification of an expected
>> result (this necessarily includes running followup passes as we have to
>> generate code).  I don't see why this shouldn't apply to __RTL -- it might
>> be more difficult to get __RTL testcases to the point where they emit
>> assembly of course.
>
>
> Also, if this ends up with a lot of testcases, I still think it would be
> best to have these use a special rtl-test port so that the tests don't
> become a maintenance burden for real ports, and so that we can construct the
> tests any way we like.
> Such a port might not even be able to produce executable code (unless you
> also want to write a sim).

Sure - I don't say running only a single pass doesn't make sense in some cases.
It just adds a less fragile way of testing for correctness.

Richard.

>
> Bernd
David Malcolm Oct. 14, 2016, 7:23 p.m. UTC | #6
On Thu, 2016-10-13 at 15:49 +0200, Richard Biener wrote:
> On Fri, Oct 7, 2016 at 5:58 PM, David Malcolm <dmalcolm@redhat.com>
> wrote:
> > On Wed, 2016-10-05 at 16:09 +0000, Joseph Myers wrote:
> > > On Wed, 5 Oct 2016, David Malcolm wrote:
> > > 
> > > > @@ -1752,6 +1759,35 @@ 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)
> > > 
> > > if (c_parser_next_token_is_keyword (parser, RID_RTL))
> > > 
> > > You're missing an update to the comment above this function to
> > > show
> > > what
> > > the new syntax is.
> > 
> > Thanks.  Here's an updated version of the patch which fixes that,
> > along with some other fixes:
> > * Use c_parser_next_token_is_keyword.
> > * Removed a stray "FIXME".
> > * Removed some debug code.
> > * Add more comments
> > * Fixed a typo in the ChangeLog ("__RID" -> "__RTL")
> > 
> > Blurb from original version:
> > 
> > This patch implements Richi's idea of having a custom __RTL marker
> > in C function definitions, to indicate that the body of the
> > function
> > is to be parsed as RTL, rather than C:
> > 
> > int __RTL test_fn_1 (int i)
> > {
> >  (function "times_two"
> >    (insn-chain
> >      (note 1 0 4 (nil) NOTE_INSN_DELETED)
> >      ;; etc
> >    ) ;; insn-chain
> >    (crtl
> >      (return_rtx
> >        (reg/i:SI 0 ax)
> >      ) ;; return_rtx
> >    ) ;; crtl
> >   ) ;; function
> > }
> > 
> > This allows for decls and types to be declared in C, and to use
> > the function decl from the C frontend.
> > 
> > I added support for running a single pass by giving __RTL an
> > optional
> > parameter (the name of the pass).  For example:
> 
> So what's the default behavior?

Currently it loads the RTL, but doesn't manage to generate assembler
for it.  There are some state issues to be tracked down.

int __RTL ("rtl-dfinit") test_fn_2 (int i)
> > {
> >  (function "times_two"
> >    (insn-chain
> >      (note 1 0 4 (nil) NOTE_INSN_DELETED)
> >      ;; etc
> >    ) ;; insn-chain
> >    (crtl
> >      (return_rtx
> >        (reg/i:SI 0 ax)
> >      ) ;; return_rtx
> >    ) ;; crtl
> >   ) ;; function
> > }
> 
> Does it really run a single pass only? 

Yes.

>  Thus you can't do a { dg-do run } test
> with __RTL?  

Currently not, but I think I can fix that.

> The GIMPLE FE has a __GIMPLE (starts-with: "pass") thing
> starting from a specific pass but going all the way to assembly
> output.

It strikes me that we might need that; we probably need some way to
identify what state the RTL is in.

> It looks like your run-one-rtl-pass thingy is directly invoked from
> the "frontend"
> rather than passing down everything to the middle-end?

Yes.  There are some nasty state issues here: the whole of the RTL
-handling in the backend seems to expect a single function, and various
other singleton state (e.g. "crtl" aka "x_rtl").  The RTL "frontend" is
populating that state directly, so I think I have to do one function at
a time, running any/all RTL passes as soon as each one is parsed.

[...]
David Malcolm Oct. 14, 2016, 7:25 p.m. UTC | #7
On Fri, 2016-10-14 at 11:33 +0200, Richard Biener wrote:
> On Thu, Oct 13, 2016 at 3:51 PM, Bernd Schmidt <bschmidt@redhat.com>
> wrote:
> > On 10/13/2016 03:49 PM, Richard Biener wrote:
> > > 
> > > Does it really run a single pass only?  Thus you can't do a { dg
> > > -do run }
> > > test
> > > with __RTL?
> > 
> > 
> > I think that's really not the intended use-case. To my mind this is
> > for
> > unit-testing: ensuring that a given rtl pass performs the expected
> > transformation on an input.
> 
> Ok, so at least for the GIMPLE FE side I thought it's useful to allow
> a correctness verification with something simpler than pattern
> matching
> on the pass output.  By means of doing runtime verification of an
> expected
> result (this necessarily includes running followup passes as we have
> to
> generate code).  I don't see why this shouldn't apply to __RTL -- it
> might
> be more difficult to get __RTL testcases to the point where they emit
> assembly of course.
> 
> OTOH the question then still is what's the default behavior if you do
> _not_
> specify a "single pass to run".

As noted elsewhere, the current behavior is that it merely parses the
function and ignores it - and that's a bug in the current
implementation.

The behavior probably should be that it runs the remainder of the RTL
passes from some specified point, and generates valid assembler (so
that we can have dg-do DejaGnu tests).
Bernd Schmidt Oct. 14, 2016, 7:27 p.m. UTC | #8
On 10/14/2016 09:25 PM, David Malcolm wrote:
>
> The behavior probably should be that it runs the remainder of the RTL
> passes from some specified point, and generates valid assembler (so
> that we can have dg-do DejaGnu tests).

Actually I had imagined that tests would specify before and after RTL so 
that we verify that the pass we're testing does what it's supposed to do.


Bernd
David Malcolm Oct. 14, 2016, 7:35 p.m. UTC | #9
On Fri, 2016-10-14 at 21:27 +0200, Bernd Schmidt wrote:
> On 10/14/2016 09:25 PM, David Malcolm wrote:
> > 
> > The behavior probably should be that it runs the remainder of the
> > RTL
> > passes from some specified point, and generates valid assembler (so
> > that we can have dg-do DejaGnu tests).
> 
> Actually I had imagined that tests would specify before and after RTL
> so 
> that we verify that the pass we're testing does what it's supposed to
> do.

Note that this approach would allow for:

  { dg-final { scan-rtl-dump "SOMETHING" "PASS OF INTEREST" } } */

directives in the .c file, so it would support specifying the "after
RTL" to some extent.
diff mbox

Patch

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 491c637..ecef32b 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -524,6 +524,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 c88619b..e19751e 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 6bc42da..693d1bd 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -59,6 +59,8 @@  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 "run-one-rtl-pass.h"
 
 /* We need to walk over decls with incomplete struct/union/enum types
    after parsing the whole translation unit.
@@ -1421,6 +1423,9 @@  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,
+				     const char *single_pass_name);
+
 /* Parse a translation unit (C90 6.7, C99 6.9).
 
    translation-unit:
@@ -1624,6 +1629,16 @@  static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
      declaration-specifiers declarator declaration-list[opt]
        compound-statement
 
+   function-definition:
+     declaration-specifiers rtl-body-specifier declarator declaration-list[opt]
+       compound-statement
+
+   rtl-body-specifier:
+     __RTL rtl-body-pass-specifier[opt]
+
+   rtl-body-pass-specifier:
+     ( string )
+
    attribute ;
 
    Objective-C:
@@ -1668,6 +1683,8 @@  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;
+  const char *single_pass_name = NULL;
 
   if (static_assert_ok
       && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
@@ -1752,6 +1769,33 @@  c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       c_parser_skip_to_end_of_block_or_statement (parser);
       return;
     }
+
+  /* Handle GNU extension rtl-body-specifier by detecting "__RTL".  */
+  if (c_parser_next_token_is_keyword (parser, RID_RTL))
+    {
+      rtl_body_p = true;
+      c_parser_consume_token (parser);
+
+      /* Handle the optional rtl-body-pass-specifier: parens wrapping
+	 a string, giving a pass name.  */
+      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+	{
+	  c_parser_consume_token (parser);
+	  c_token *tok = c_parser_peek_token (parser);
+	  if (tok->type != CPP_STRING)
+	    {
+	      c_parser_error (parser, "expected string");
+	      c_parser_skip_to_end_of_block_or_statement (parser);
+	      return;
+	    }
+	  gcc_assert (TREE_CODE (tok->value) == STRING_CST);
+	  single_pass_name = TREE_STRING_POINTER (tok->value);
+	  c_parser_consume_token (parser);
+
+	  c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+	}
+    }
+
   finish_declspecs (specs);
   bool auto_type_p = specs->typespec_word == cts_auto_type;
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -2146,7 +2190,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
@@ -2173,6 +2217,15 @@  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 we had an rtl-body-specifier, use the RTL parser now,
+	 consuming the function body.  */
+      if (rtl_body_p)
+	{
+	  c_parser_parse_rtl_body (parser, single_pass_name);
+	  return;
+	}
+
       fnbody = c_parser_compound_statement (parser);
       if (flag_cilkplus && contains_array_notation_expr (fnbody))
 	fnbody = expand_array_notation_exprs (fnbody);
@@ -2195,7 +2248,6 @@  c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	  finish_function ();
 	}
 
-      timevar_pop (tv);
       break;
     }
 }
@@ -18313,4 +18365,61 @@  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.  */
+
+void
+c_parser_parse_rtl_body (c_parser *parser, const char *single_pass_name)
+{
+  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    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;
+	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))
+    return;
+
+ /*  If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
+      on cfun, as created above.  */
+  if (single_pass_name)
+    run_one_rtl_pass_by_name (single_pass_name);
+}
+
 #include "gt-c-c-parser.h"
diff --git a/gcc/read-md.c b/gcc/read-md.c
index be55777..e713466 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -419,6 +419,16 @@  base_rtx_reader::read_char (void)
   else
     m_read_md_colno++;
 
+  /* 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;
 }
 
@@ -1000,7 +1010,9 @@  base_rtx_reader::base_rtx_reader ()
   m_read_md_lineno (0),
   m_read_md_colno (0),
   m_first_dir_md_include (NULL),
-  m_last_dir_md_include_ptr (&m_first_dir_md_include)
+  m_last_dir_md_include_ptr (&m_first_dir_md_include),
+  m_first_line (0),
+  m_last_line (0)
 {
   /* Set the global singleton pointer.  */
   base_rtx_reader_ptr = this;
@@ -1307,6 +1319,26 @@  base_rtx_reader::read_md_files (int argc, const char **argv,
   return !have_error;
 }
 
+/* Read FILENAME, filtering to just the given lines.  */
+
+bool
+base_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 !have_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 4933912..2058002 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -98,6 +98,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
@@ -159,6 +162,10 @@  class base_rtx_reader
 
   /* A pointer to the null terminator of the md include chain.  */
   file_name_list **m_last_dir_md_include_ptr;
+
+  /* If non-zero, filter the input to just this subset of lines.  */
+  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 0723585..73493ec 100644
--- a/gcc/read-rtl-function.c
+++ b/gcc/read-rtl-function.c
@@ -593,23 +593,31 @@  function_reader::create_function ()
   else
     rtl_register_cfg_hooks ();
 
-  /* Create cfun.  */
-  tree fn_name = get_identifier (m_name ? m_name : "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;
+  /* When run from selftests or "rtl1", cfun is NULL.
+     When run from "cc1" for a C function tagged with __RTL, cfun is the
+     tagged function.  */
+  if (!cfun)
+    {
+      tree fn_name = get_identifier (m_name ? m_name : "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;
 
   cfun->curr_properties = (PROP_cfg | PROP_rtl);
 
@@ -1817,6 +1825,42 @@  read_rtl_function_body (int argc, const char **argv,
   return true;
 }
 
+/* Run the RTL dump parser on the range of lines between START_LOC and
+   END_LOC (including those lines).  */
+
+bool
+read_rtl_function_body_from_file_range (location_t start_loc,
+					location_t end_loc)
+{
+  expanded_location exploc_start = expand_location (start_loc);
+  expanded_location exploc_end = expand_location (end_loc);
+
+  if (exploc_start.file != exploc_end.file)
+    {
+      error_at (end_loc, "start/end of RTL fragment are in different files");
+      return false;
+    }
+  if (exploc_start.line >= exploc_end.line)
+    {
+      error_at (end_loc,
+		"start of RTL fragment must be on an earlier line than end");
+      return false;
+    }
+
+  in_rtl_frontend_p = true;
+
+  initialize_rtl ();
+  init_emit ();
+  init_varasm_status ();
+
+  function_reader reader (NULL);
+  if (!reader.read_file_fragment (exploc_start.file, exploc_start.line,
+				  exploc_end.line - 1))
+    return false;
+
+  return true;
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/read-rtl-function.h b/gcc/read-rtl-function.h
index d26c797..c69d308 100644
--- a/gcc/read-rtl-function.h
+++ b/gcc/read-rtl-function.h
@@ -34,4 +34,7 @@  extern bool read_rtl_function_body (int argc, const char **argv,
 				    function_reader_policy *policy,
 				    int *out_pseudo_offset);
 
+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/testsuite/rtl.dg/rtl.exp b/gcc/testsuite/rtl.dg/rtl.exp
index 71bebb9..6c7c7f4 100644
--- a/gcc/testsuite/rtl.dg/rtl.exp
+++ b/gcc/testsuite/rtl.dg/rtl.exp
@@ -29,8 +29,10 @@  if ![info exists DEFAULT_RTLFLAGS] then {
 # Initialize `dg'.
 dg-init
 
-# Gather a list of all tests.
+# Gather a list of all tests: both .rtl tests for use with rtl1, and .c tests
+# for use with cc1.
 set tests [lsort [find $srcdir/$subdir *.rtl]]
+set tests [concat $tests [lsort [find $srcdir/$subdir *.c]]]
 
 verbose "rtl.exp tests: $tests" 1
 
diff --git a/gcc/testsuite/rtl.dg/x86_64/different-structs.c b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
new file mode 100644
index 0000000..d5c0bed
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/different-structs.c
@@ -0,0 +1,101 @@ 
+/* { dg-do compile { target x86_64-*-* } } */
+
+extern double sqrt(double x);
+
+struct foo
+{
+  double x;
+  double y;
+};
+
+struct bar
+{
+  double x;
+  double y;
+};
+
+double __RTL test (struct foo *f, const struct bar *b)
+{
+#if 0
+  /* Result of "expand" on this C code, compiled for x86_64 with -Os.  */
+  f->x += b->x;
+  f->y += b->y;
+  return sqrt (f->x * f->x + f->y * f->y);
+#endif
+(function "test"
+  (insn-chain
+    (note 1 0 5 (nil) NOTE_INSN_DELETED)
+    (note 5 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+    (insn 2 5 3 2 (set (reg/v/f:DI 97 [ f ])
+                (reg:DI 5 di [ f ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
+             (nil))
+    (insn 3 2 4 2 (set (reg/v/f:DI 98 [ b ])
+                (reg:DI 4 si [ b ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:16 -1
+             (nil))
+    (note 4 3 7 2 NOTE_INSN_FUNCTION_BEG)
+    (insn 7 4 8 2 (set (reg:DF 99)
+                (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
+             (nil))
+    (insn 8 7 9 2 (set (reg:DF 89 [ _3 ])
+                (plus:DF (reg:DF 99)
+                    (mem:DF (reg/v/f:DI 98 [ b ]) [2 b_12(D)->x+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
+             (nil))
+    (insn 9 8 10 2 (set (mem:DF (reg/v/f:DI 97 [ f ]) [2 f_11(D)->x+0 S8 A64])
+                (reg:DF 89 [ _3 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:17 -1
+             (nil))
+    (insn 10 9 11 2 (set (reg:DF 100)
+                (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
+                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
+             (nil))
+    (insn 11 10 12 2 (set (reg:DF 92 [ _6 ])
+                (plus:DF (reg:DF 100)
+                    (mem:DF (plus:DI (reg/v/f:DI 98 [ b ])
+                            (const_int 8 [0x8])) [2 b_12(D)->y+0 S8 A64]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
+             (nil))
+    (insn 12 11 13 2 (set (mem:DF (plus:DI (reg/v/f:DI 97 [ f ])
+                        (const_int 8 [0x8])) [2 f_11(D)->y+0 S8 A64])
+                (reg:DF 92 [ _6 ])) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:18 -1
+             (nil))
+    (insn 13 12 14 2 (set (reg:DF 101)
+                (mult:DF (reg:DF 89 [ _3 ])
+                    (reg:DF 89 [ _3 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (insn 14 13 15 2 (set (reg:DF 102)
+                (mult:DF (reg:DF 92 [ _6 ])
+                    (reg:DF 92 [ _6 ]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (insn 15 14 16 2 (set (reg:DF 103)
+                (plus:DF (reg:DF 101)
+                    (reg:DF 102))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (insn 16 15 17 2 (set (reg:DF 21 xmm0)
+                (reg:DF 103)) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (nil))
+    (call_insn/j 17 16 18 2 (set (reg:DF 21 xmm0)
+                (call (mem:QI (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>) [0 __builtin_sqrt S1 A8])
+                    (const_int 0 [0]))) ../../src/gcc/testsuite/rtl.dg/x86_64/different-structs.c:19 -1
+             (expr_list:REG_CALL_DECL (symbol_ref:DI ("sqrt") [flags 0x41]  <function_decl 0x7f82b1429d00 sqrt>)
+                (expr_list:REG_EH_REGION (const_int 0 [0])
+                    (nil)))
+            (expr_list:DF (use (reg:DF 21 xmm0))
+                (nil)))
+    (barrier 18 17 0)
+  ) ;; insn-chain
+  (cfg
+    (bb 0
+      (edge 0 2 (flags 0x1))
+    ) ;; bb
+    (bb 2
+      (edge 2 1 (flags 0x1002))
+    ) ;; bb
+    (bb 1
+    ) ;; bb
+  ) ;; cfg
+  (crtl
+    (return_rtx 
+      (reg/i:DF 21 xmm0)
+    ) ;; return_rtx
+  ) ;; crtl
+) ;; function "test"
+
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
new file mode 100644
index 0000000..11b6f24
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.after-expand.c
@@ -0,0 +1,23 @@ 
+/* { dg-do compile { target x86_64-*-* } } */
+
+int __RTL test_returning_constant (void)
+{
+  /* C code:
+     return 42; */
+
+  (function "test_returning_constant"
+    (insn-chain
+      (note 1 0 3 (nil) NOTE_INSN_DELETED)
+      (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
+	    (const_int 42 [0x2a])) test-return-const.c:3 -1
+         (nil))
+      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
+	      (reg:SI 87 [ <retval> ])) test-return-const.c:4 -1
+         (nil))
+      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
+         (nil))
+     ) ;; insn-chain
+   );; function
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
new file mode 100644
index 0000000..83594b3
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/test-return-const.c.before-fwprop.c
@@ -0,0 +1,27 @@ 
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-fwprop1" } */
+
+int __RTL ("rtl-fwprop1") test_returning_constant (void)
+{
+  /* C code:
+     return 42; */
+  (function "test"
+    (insn-chain
+      (note 3 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
+      (insn 5 2 9 2 (set (reg:SI 87 [ <retval> ])
+        (const_int 42 [0x2a])) test-return-const.c:3 82 {*movsi_internal}
+        (nil))
+      (insn 9 5 10 2 (set (reg/i:SI 0 ax)
+	(const_int 42 [0x2a])) test-return-const.c:4 82 {*movsi_internal}
+        (expr_list:REG_DEAD (reg:SI 87 [ <retval> ])
+	 (nil)))
+      (insn 10 9 0 2 (use (reg/i:SI 0 ax)) test-return-const.c:4 -1
+       (nil))
+    ) ;; insn-chain
+  ) ;; function
+}
+
+/* Verify that insn 5 is eliminated.  */
+/* { dg-final { scan-rtl-dump "deferring deletion of insn with uid = 5" "fwprop1" } } */
+/* { dg-final { scan-rtl-dump "Deleted 1 trivially dead insns" "fwprop1" } } */
diff --git a/gcc/testsuite/rtl.dg/x86_64/test-rtl.c b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
new file mode 100644
index 0000000..0ffeab7
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/test-rtl.c
@@ -0,0 +1,95 @@ 
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+/* Test of embedding RTL dump in a C function, tagged with "__RTL".
+
+   This is a dump of test.c from immediately after "expand", for x86_64.  */
+
+int __RTL test_1 (int i, int j, int k)
+{
+  /*
+    if (i < j)
+      return k + 4;
+    else
+      return -k;
+  */
+  (function "test_1"
+   (insn-chain
+  (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))
+
+    ) ;; insn-chain
+   ) ;; function
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
new file mode 100644
index 0000000..8536bf4
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.after-expand.c
@@ -0,0 +1,40 @@ 
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+int __RTL times_two (int i)
+{
+  /* C function:
+     return i * 2;  */
+  (function "times_two"
+    (insn-chain
+  (note 1 0 4 (nil) NOTE_INSN_DELETED)
+  (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+  (insn 2 4 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 ])) times-two.c:2 -1
+     (nil))
+  (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
+  (insn 6 3 7 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])) times-two.c:3 -1
+     (nil))
+  (insn 7 6 10 2 (parallel [
+            (set (reg:SI 87 [ _2 ])
+                (ashift:SI (reg:SI 89)
+                    (const_int 1 [0x1])))
+            (clobber (reg:CC 17 flags))
+        ]) times-two.c:3 -1
+     (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI 82 virtual-stack-vars)
+                    (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+            (const_int 1 [0x1]))
+        (nil)))
+  (insn 10 7 14 2 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _2 ])) times-two.c:3 -1
+     (nil))
+  (insn 14 10 15 2 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) times-two.c:4 -1
+     (nil))
+  (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
+     (nil))
+    ) ;; insn-chain
+  ) ;; function
+}
diff --git a/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
new file mode 100644
index 0000000..b4d20a7
--- /dev/null
+++ b/gcc/testsuite/rtl.dg/x86_64/times-two.c.before-df.c
@@ -0,0 +1,57 @@ 
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-options "-fdump-rtl-dfinit" } */
+
+int __RTL ("rtl-dfinit") times_two (int i)
+{
+  /* C function:
+     return i * 2;  */
+ (function "times_two"
+  (insn-chain
+   (note 1 0 4 (nil) NOTE_INSN_DELETED)
+   (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+   (insn 2 4 3 2 (set (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+        (reg:SI 5 di [ i ])) times-two.c:2 82 {*movsi_internal}
+     (nil))
+   (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
+   (insn 6 3 7 2 (set (reg:SI 89)
+        (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])) times-two.c:3 82 {*movsi_internal}
+     (nil))
+   (insn 7 6 10 2 (parallel [
+            (set (reg:SI 87 [ _2 ])
+                (ashift:SI (reg:SI 89)
+                    (const_int 1 [0x1])))
+            (clobber (reg:CC 17 flags))
+        ]) times-two.c:3 529 {*ashlsi3_1}
+     (expr_list:REG_EQUAL (ashift:SI (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+                    (const_int -4 [0xfffffffffffffffc])) [1 i+0 S4 A32])
+            (const_int 1 [0x1]))
+        (nil)))
+   (insn 10 7 14 2 (set (reg:SI 88 [ <retval> ])
+        (reg:SI 87 [ _2 ])) times-two.c:3 82 {*movsi_internal}
+     (nil))
+   (insn 14 10 15 2 (set (reg/i:SI 0 ax)
+        (reg:SI 88 [ <retval> ])) times-two.c:4 82 {*movsi_internal}
+     (nil))
+   (insn 15 14 0 2 (use (reg/i:SI 0 ax)) times-two.c:4 -1
+     (nil))
+   ) ;; insn-chain
+
+   (crtl
+     (return_rtx
+       (reg/i:SI 0 ax)
+     ) ;; return_rtx
+   ) ;; crtl
+  ) ;; function
+}
+
+/* Verify that the dataflow information matches what cc1 would have
+   generated.  In particular, in earlier versions of the RTL
+   frontend, the exit block use of reg 0 (ax) wasn't picked up
+   on, due to not setting up crtl->return_rtx based on
+   DECL_RESULT (fndecl).  */
+
+/* { dg-final { scan-rtl-dump ";;  exit block uses.*0 .ax. 6 .bp. 7 .sp. 20 .frame." "dfinit" } } */
+
+/* { dg-final { scan-rtl-dump ";;  regs ever live.*0 .ax. 5 .di. 17 .flags." "dfinit" } } */