[PATCH] Add "__RTL" to cc1 (v2)

Richard Biener richard.guenther@gmail.com
Thu Oct 13 13:49:00 GMT 2016


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
>



More information about the Gcc-patches mailing list