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): Handle "__RID" 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 | 102 ++++++++++++++++++++- 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, 554 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..b4993d0 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: @@ -1668,6 +1673,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 +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) + { + rtl_body_p = true; + c_parser_consume_token (parser); + /* Optionally, 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, "FIXME"); + } + } + } + finish_declspecs (specs); bool auto_type_p = specs->typespec_word == cts_auto_type; if (c_parser_next_token_is (parser, CPP_SEMICOLON)) @@ -2146,7 +2182,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 +2209,12 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_finish_oacc_routine (oacc_routine_data, current_function_decl, true); DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; + if (rtl_body_p) + { + c_parser_parse_rtl_body (parser, 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 +2237,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, finish_function (); } - timevar_pop (tv); break; } } @@ -18313,4 +18354,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, + recording the start/end of the RTL + fragment, and reopening the file and re-reading the relevant + lines within the RTL parser. */ + +void +c_parser_parse_rtl_body (c_parser *parser, 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; + if (0) + inform (start_loc, "start of RTL"); + + /* 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; + if (0) + inform (end_loc, "end of RTL"); + + /* Consume the closing brace. */ + c_parser_consume_token (parser); + + if (!read_rtl_function_body_from_file_range (start_loc, end_loc)) + return; + + /* 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 b6bafe7..daa4e1c 100644 --- a/gcc/read-md.c +++ b/gcc/read-md.c @@ -417,6 +417,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; } @@ -998,7 +1008,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; @@ -1305,6 +1317,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