@@ -6187,10 +6187,7 @@ pass_expand::execute (function *fun)
discover_nonconstant_array_refs ();
targetm.expand_to_rtl_hook ();
- crtl->stack_alignment_needed = STACK_BOUNDARY;
- crtl->max_used_stack_slot_alignment = STACK_BOUNDARY;
- crtl->stack_alignment_estimated = 0;
- crtl->preferred_stack_boundary = STACK_BOUNDARY;
+ crtl->init_stack_alignment ();
fun->cfg->max_jumptable_ents = 0;
/* Resovle the function section. Some targets, like ARM EABI rely on knowledge
@@ -6222,7 +6219,7 @@ pass_expand::execute (function *fun)
}
/* Set up parameters and prepare for return, for the function. */
- expand_function_start (current_function_decl);
+ expand_function_start (current_function_decl, true);
/* If we emitted any instructions for setting up the variables,
emit them before the FUNCTION_START note. */
@@ -5677,7 +5677,8 @@ init_emit (void)
crtl->emit.regno_pointer_align
= XCNEWVEC (unsigned char, crtl->emit.regno_pointer_align_length);
- regno_reg_rtx = ggc_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
+ regno_reg_rtx =
+ ggc_cleared_vec_alloc<rtx> (crtl->emit.regno_pointer_align_length);
/* Put copies of all the hard registers into regno_reg_rtx. */
memcpy (regno_reg_rtx,
@@ -6295,5 +6296,17 @@ need_atomic_barrier_p (enum memmodel model, bool pre)
gcc_unreachable ();
}
}
+
+/* Initialize fields of rtl_data related to stack alignment. */
+
+void
+rtl_data::init_stack_alignment ()
+{
+ stack_alignment_needed = STACK_BOUNDARY;
+ max_used_stack_slot_alignment = STACK_BOUNDARY;
+ stack_alignment_estimated = 0;
+ preferred_stack_boundary = STACK_BOUNDARY;
+}
+
#include "gt-emit-rtl.h"
@@ -55,6 +55,8 @@ struct GTY(()) incoming_args {
/* Datastructures maintained for currently processed function in RTL form. */
struct GTY(()) rtl_data {
+ void init_stack_alignment ();
+
struct expr_status expr;
struct emit_status emit;
struct varasm_status varasm;
@@ -61,7 +61,7 @@ error (const char *format, ...)
va_list ap;
va_start (ap, format);
- fprintf (stderr, "%s: ", progname);
+ fprintf (stderr, "%s: error: ", progname);
vfprintf (stderr, format, ap);
va_end (ap);
fputc ('\n', stderr);
@@ -78,7 +78,7 @@ fatal (const char *format, ...)
va_list ap;
va_start (ap, format);
- fprintf (stderr, "%s: ", progname);
+ fprintf (stderr, "%s: error: ", progname);
vfprintf (stderr, format, ap);
va_end (ap);
fputc ('\n', stderr);
@@ -28,8 +28,21 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ERRORS_H
#define GCC_ERRORS_H
+/* Records a position in the file. */
+struct file_location {
+ file_location () {}
+ file_location (const char *, int);
+
+ const char *filename;
+ int lineno;
+};
+
+inline file_location::file_location (const char *filename_in, int lineno_in)
+ : filename (filename_in), lineno (lineno_in) {}
+
extern void warning (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
extern void error (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
+extern void error_at (file_location, const char *, ...) ATTRIBUTE_PRINTF_2 ATTRIBUTE_COLD;
extern void fatal (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
extern void internal_error (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1 ATTRIBUTE_COLD;
extern const char *trim_filename (const char *);
@@ -1903,7 +1903,8 @@ instantiate_decls (tree fndecl)
instantiate_decl_rtl (DECL_RTL (DECL_VALUE_EXPR (decl)));
/* Now process all variables defined in the function or its subblocks. */
- instantiate_decls_1 (DECL_INITIAL (fndecl));
+ if (DECL_INITIAL (fndecl))
+ instantiate_decls_1 (DECL_INITIAL (fndecl));
FOR_EACH_LOCAL_DECL (cfun, ix, decl)
if (DECL_RTL_SET_P (decl))
@@ -5082,10 +5083,12 @@ stack_protect_epilogue (void)
emitting RTL.
SUBR is the FUNCTION_DECL node.
PARMS_HAVE_CLEANUPS is nonzero if there are cleanups associated with
- the function's parameters, which must be run at any return statement. */
+ the function's parameters, which must be run at any return statement.
+ EMIT_INSNS is true if instructions are to emitted, false to avoid this
+ (for use by the RTL frontend). */
void
-expand_function_start (tree subr)
+expand_function_start (tree subr, bool emit_insns)
{
/* Make sure volatile mem refs aren't considered
valid operands of arithmetic insns. */
@@ -5101,7 +5104,8 @@ expand_function_start (tree subr)
/* Make the label for return statements to jump to. Do not special
case machines with special return instructions -- they will be
handled later during jump, ifcvt, or epilogue creation. */
- return_label = gen_label_rtx ();
+ if (emit_insns)
+ return_label = gen_label_rtx ();
/* Initialize rtx used to return the value. */
/* Do this before assign_parms so that we copy the struct value address
@@ -5127,7 +5131,7 @@ expand_function_start (tree subr)
/* Expect to be passed the address of a place to store the value.
If it is passed as an argument, assign_parms will take care of
it. */
- if (sv)
+ if (sv && emit_insns)
{
value_address = gen_reg_rtx (Pmode);
emit_move_insn (value_address, sv);
@@ -5204,7 +5208,7 @@ expand_function_start (tree subr)
assign_parms (subr);
/* If function gets a static chain arg, store it. */
- if (cfun->static_chain_decl)
+ if (cfun->static_chain_decl && emit_insns)
{
tree parm = cfun->static_chain_decl;
rtx local, chain;
@@ -5248,7 +5252,7 @@ expand_function_start (tree subr)
/* If the function receives a non-local goto, then store the
bits we need to restore the frame pointer. */
- if (cfun->nonlocal_goto_save_area)
+ if (cfun->nonlocal_goto_save_area && emit_insns)
{
tree t_save;
rtx r_save;
@@ -5271,22 +5275,25 @@ expand_function_start (tree subr)
The move is supposed to make sdb output more accurate. */
/* Indicate the beginning of the function body,
as opposed to parm setup. */
- emit_note (NOTE_INSN_FUNCTION_BEG);
+ if (emit_insns)
+ {
+ emit_note (NOTE_INSN_FUNCTION_BEG);
- gcc_assert (NOTE_P (get_last_insn ()));
+ gcc_assert (NOTE_P (get_last_insn ()));
- parm_birth_insn = get_last_insn ();
+ parm_birth_insn = get_last_insn ();
- if (crtl->profile)
- {
+ if (crtl->profile)
+ {
#ifdef PROFILE_HOOK
- PROFILE_HOOK (current_function_funcdef_no);
+ PROFILE_HOOK (current_function_funcdef_no);
#endif
- }
+ }
- /* If we are doing generic stack checking, the probe should go here. */
- if (flag_stack_check == GENERIC_STACK_CHECK)
- stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+ /* If we are doing generic stack checking, the probe should go here. */
+ if (flag_stack_check == GENERIC_STACK_CHECK)
+ stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+ }
}
void
@@ -619,7 +619,7 @@ extern void pop_dummy_function (void);
extern void init_dummy_function_start (void);
extern void init_function_start (tree);
extern void stack_protect_epilogue (void);
-extern void expand_function_start (tree);
+extern void expand_function_start (tree, bool);
extern void expand_dummy_function_end (void);
extern void thread_prologue_and_epilogue_insns (void);
@@ -1287,6 +1287,7 @@ static const struct compiler default_compilers[] =
{".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
{".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
{".go", "#Go", 0, 1, 0},
+ {".rtl", "#RTL", 0, 1, 0},
/* Next come the entries for C. */
{".c", "@c", 0, 0, 1},
{"@c",
@@ -79,7 +79,8 @@ main (int argc, const char **argv)
{
progname = "genconstants";
- if (!read_md_files (argc, argv, NULL, NULL))
+ noop_reader reader;
+ if (!reader.read_md_files (argc, argv, NULL))
return (FATAL_EXIT_CODE);
/* Initializing the MD reader has the side effect of loading up
@@ -49,7 +49,8 @@ main (int argc, const char **argv)
{
progname = "genenums";
- if (!read_md_files (argc, argv, NULL, NULL))
+ noop_reader reader;
+ if (!reader.read_md_files (argc, argv, NULL))
return (FATAL_EXIT_CODE);
puts ("/* Generated automatically by the program `genenums'");
@@ -47,7 +47,8 @@ main (int argc, const char **argv)
progname = "genmddeps";
include_callback = add_filedep;
- if (!read_md_files (argc, argv, NULL, NULL))
+ noop_reader reader;
+ if (!reader.read_md_files (argc, argv, NULL))
return FATAL_EXIT_CODE;
*last = NULL;
@@ -1204,7 +1204,8 @@ write_tm_constrs_h (void)
printf ("\
/* Generated automatically by the program '%s'\n\
- from the machine description file '%s'. */\n\n", progname, in_fname);
+ from the machine description file '%s'. */\n\n", progname,
+ rtx_reader_ptr->get_top_level_filename ());
puts ("\
#ifndef GCC_TM_CONSTRS_H\n\
@@ -1403,7 +1404,8 @@ write_tm_preds_h (void)
printf ("\
/* Generated automatically by the program '%s'\n\
- from the machine description file '%s'. */\n\n", progname, in_fname);
+ from the machine description file '%s'. */\n\n", progname,
+ rtx_reader_ptr->get_top_level_filename ());
puts ("\
#ifndef GCC_TM_PREDS_H\n\
@@ -1552,7 +1554,8 @@ write_insn_preds_c (void)
printf ("\
/* Generated automatically by the program '%s'\n\
- from the machine description file '%s'. */\n\n", progname, in_fname);
+ from the machine description file '%s'. */\n\n", progname,
+ rtx_reader_ptr->get_top_level_filename ());
puts ("\
#include \"config.h\"\n\
@@ -2226,10 +2226,18 @@ process_define_subst (void)
}
}
-/* A read_md_files callback for reading an rtx. */
+/* A subclass of rtx_reader which reads .md files and calls process_rtx on
+ the top-level elements. */
-static void
-rtx_handle_directive (file_location loc, const char *rtx_name)
+class gen_reader : public rtx_reader
+{
+ public:
+ gen_reader () : rtx_reader () {}
+ void handle_unknown_directive (file_location, const char *);
+};
+
+void
+gen_reader::handle_unknown_directive (file_location loc, const char *rtx_name)
{
auto_vec<rtx, 32> subrtxs;
if (!read_rtx (rtx_name, &subrtxs))
@@ -2500,7 +2508,7 @@ check_define_attr_duplicates ()
/* The entry point for initializing the reader. */
-bool
+rtx_reader *
init_rtx_reader_args_cb (int argc, const char **argv,
bool (*parse_opt) (const char *))
{
@@ -2516,7 +2524,8 @@ init_rtx_reader_args_cb (int argc, const char **argv,
split_sequence_num = 1;
peephole2_sequence_num = 1;
- read_md_files (argc, argv, parse_opt, rtx_handle_directive);
+ gen_reader *reader = new gen_reader ();
+ reader->read_md_files (argc, argv, parse_opt);
if (define_attr_queue != NULL)
check_define_attr_duplicates ();
@@ -2532,12 +2541,18 @@ init_rtx_reader_args_cb (int argc, const char **argv,
if (define_attr_queue != NULL)
gen_mnemonic_attr ();
- return !have_error;
+ if (have_error)
+ {
+ delete reader;
+ return NULL;
+ }
+
+ return reader;
}
/* Programs that don't have their own options can use this entry point
instead. */
-bool
+rtx_reader *
init_rtx_reader_args (int argc, const char **argv)
{
return init_rtx_reader_args_cb (argc, argv, 0);
@@ -125,9 +125,9 @@ struct optab_pattern
};
extern rtx add_implicit_parallel (rtvec);
-extern bool init_rtx_reader_args_cb (int, const char **,
- bool (*)(const char *));
-extern bool init_rtx_reader_args (int, const char **);
+extern rtx_reader *init_rtx_reader_args_cb (int, const char **,
+ bool (*)(const char *));
+extern rtx_reader *init_rtx_reader_args (int, const char **);
extern bool read_md_rtx (md_rtx_info *);
extern unsigned int get_num_insn_codes ();
@@ -220,7 +220,7 @@ print_rtx (const_rtx in_rtx)
string:
if (str == 0)
- fputs (" \"\"", outfile);
+ fputs (" (nil)", outfile);
else
fprintf (outfile, " (\"%s\")", str);
sawclose = 1;
@@ -586,6 +586,8 @@ print_rtx (const_rtx in_rtx)
#ifndef GENERATOR_FILE
if (XBBDEF (in_rtx, i))
fprintf (outfile, " %i", XBBDEF (in_rtx, i)->index);
+ else
+ fprintf (outfile, " (nil)");
#endif
break;
@@ -31,12 +31,6 @@ struct ptr_loc {
int lineno;
};
-/* A singly-linked list of filenames. */
-struct file_name_list {
- struct file_name_list *next;
- const char *fname;
-};
-
/* Obstack used for allocating MD strings. */
struct obstack string_obstack;
@@ -56,34 +50,13 @@ static htab_t joined_conditions;
/* An obstack for allocating joined_conditions entries. */
static struct obstack joined_conditions_obstack;
-/* The file we are reading. */
-FILE *read_md_file;
-
-/* The filename of READ_MD_FILE. */
-const char *read_md_filename;
-
-/* The current line number in READ_MD_FILE. */
-int read_md_lineno;
-
-/* The name of the toplevel file that indirectly included READ_MD_FILE. */
-const char *in_fname;
-
-/* The directory part of IN_FNAME. NULL if IN_FNAME is a bare filename. */
-static char *base_dir;
-
-/* The first directory to search. */
-static struct file_name_list *first_dir_md_include;
-
-/* A pointer to the null terminator of the md include chain. */
-static struct file_name_list **last_dir_md_include_ptr = &first_dir_md_include;
-
/* This callback will be invoked whenever an md include directive is
processed. To be used for creation of the dependency file. */
void (*include_callback) (const char *);
-/* The current maximum length of directory names in the search path
- for include files. (Altered as we get more of them.) */
-static size_t max_include_len;
+/* Global singleton. */
+
+rtx_reader *rtx_reader_ptr;
/* A table of md_constant structures, hashed by name. Null if no
constant expansion should occur. */
@@ -92,7 +65,7 @@ static htab_t md_constants;
/* A table of enum_type structures, hashed by name. */
static htab_t enum_types;
-static void handle_file (directive_handler_t);
+static void read_skip_construct (int depth, file_location loc);
/* Given an object that starts with a char * name field, return a hash
code for its name. */
@@ -303,7 +276,8 @@ fatal_with_file_and_line (const char *msg, ...)
va_start (ap, msg);
- fprintf (stderr, "%s:%d: ", read_md_filename, read_md_lineno);
+ fprintf (stderr, "%s:%d: error: ", rtx_reader_ptr->get_filename (),
+ rtx_reader_ptr->get_lineno ());
vfprintf (stderr, msg, ap);
putc ('\n', stderr);
@@ -322,8 +296,9 @@ fatal_with_file_and_line (const char *msg, ...)
}
context[i] = '\0';
- fprintf (stderr, "%s:%d: following context is `%s'\n",
- read_md_filename, read_md_lineno, context);
+ fprintf (stderr, "%s:%d: note: following context is `%s'\n",
+ rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+ context);
va_end (ap);
exit (1);
@@ -372,7 +347,7 @@ read_skip_spaces (void)
if (c != '*')
{
unread_char (c);
- fatal_with_file_and_line ("stray '/' in file");
+ return '/';
}
prevc = 0;
@@ -391,11 +366,76 @@ read_skip_spaces (void)
}
}
+/* Consume the next character, issuing a fatal error if it is not
+ EXPECTED. */
+
+void require_char (char expected)
+{
+ int ch = read_char ();
+ if (ch != expected)
+ fatal_expected_char (expected, ch);
+}
+
+/* Consume any whitespace, then consume the next non-whitespace
+ character, issuing a fatal error if it is not EXPECTED. */
+
+void require_char_ws (char expected)
+{
+ int ch = read_skip_spaces ();
+ if (ch != expected)
+ fatal_expected_char (expected, ch);
+}
+
+/* Consume any whitespace, then consume the next word (as per read_name),
+ issuing a fatal error if it is not EXPECTED. */
+
+void require_word_ws (const char *expected)
+{
+ struct md_name name;
+ read_name (&name);
+ if (strcmp (name.string, expected))
+ fatal_with_file_and_line ("missing '%s'", expected);
+}
+
+/* Read the next character from the file. */
+
+int
+rtx_reader::read_char (void)
+{
+ int ch;
+
+ ch = getc (m_read_md_file);
+ if (ch == '\n')
+ m_read_md_lineno++;
+
+ return ch;
+}
+
+/* Put back CH, which was the last character read from the file. */
+
+void
+rtx_reader::unread_char (int ch)
+{
+ if (ch == '\n')
+ m_read_md_lineno--;
+ ungetc (ch, m_read_md_file);
+}
+
+/* Peek at the next character from the file without consuming it. */
+
+int
+peek_char (void)
+{
+ int ch = read_char ();
+ unread_char (ch);
+ return ch;
+}
+
/* Read an rtx code name into NAME. It is terminated by any of the
punctuation chars of rtx printed syntax. */
-void
-read_name (struct md_name *name)
+static bool
+read_name_1 (struct md_name *name, file_location *out_loc)
{
int c;
size_t i;
@@ -433,8 +473,12 @@ read_name (struct md_name *name)
c = read_char ();
}
+ unread_char (c);
+ *out_loc = rtx_reader_ptr->get_current_location ();
+ read_char ();
+
if (i == 0)
- fatal_with_file_and_line ("missing name or number");
+ return false;
name->buffer[i] = 0;
name->string = name->buffer;
@@ -455,6 +499,36 @@ read_name (struct md_name *name)
}
while (def);
}
+
+ return true;
+}
+
+/* Read an rtx code name into NAME. It is terminated by any of the
+ punctuation chars of rtx printed syntax. */
+
+file_location
+read_name (struct md_name *name)
+{
+ file_location loc;
+ if (!read_name_1 (name, &loc))
+ fatal_with_file_and_line ("missing name or number");
+ return loc;
+}
+
+file_location
+read_name_or_nil (struct md_name *name)
+{
+ file_location loc;
+ if (!read_name_1 (name, &loc))
+ {
+ file_location loc = rtx_reader_ptr->get_current_location ();
+ read_skip_construct (0, loc);
+ /* Skip the ')'. */
+ read_char ();
+ name->buffer[0] = 0;
+ name->string = name->buffer;
+ }
+ return loc;
}
/* Subroutine of the string readers. Handles backslash escapes.
@@ -501,7 +575,8 @@ read_escape (void)
/* pass anything else through, but issue a warning. */
default:
fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
- read_md_filename, read_md_lineno, c);
+ rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+ c);
obstack_1grow (&string_obstack, '\\');
break;
}
@@ -544,7 +619,7 @@ read_braced_string (void)
{
int c;
int brace_depth = 1; /* caller-processed */
- unsigned long starting_read_md_lineno = read_md_lineno;
+ unsigned long starting_read_md_lineno = rtx_reader_ptr->get_lineno ();
obstack_1grow (&string_obstack, '{');
while (brace_depth)
@@ -590,7 +665,7 @@ read_string (int star_if_braced)
c = read_skip_spaces ();
}
- old_lineno = read_md_lineno;
+ old_lineno = rtx_reader_ptr->get_lineno ();
if (c == '"')
stringbuf = read_quoted_string ();
else if (c == '{')
@@ -599,17 +674,21 @@ read_string (int star_if_braced)
obstack_1grow (&string_obstack, '*');
stringbuf = read_braced_string ();
}
+ else if (saw_paren && c == 'n')
+ {
+ /* Handle (nil) by returning NULL. */
+ require_char ('i');
+ require_char ('l');
+ require_char_ws (')');
+ return NULL;
+ }
else
fatal_with_file_and_line ("expected `\"' or `{', found `%c'", c);
if (saw_paren)
- {
- c = read_skip_spaces ();
- if (c != ')')
- fatal_expected_char (')', c);
- }
+ require_char_ws (')');
- set_md_ptr_loc (stringbuf, read_md_filename, old_lineno);
+ set_md_ptr_loc (stringbuf, rtx_reader_ptr->get_filename (), old_lineno);
return stringbuf;
}
@@ -764,9 +843,7 @@ handle_constants (void)
int c;
htab_t defs;
- c = read_skip_spaces ();
- if (c != '[')
- fatal_expected_char ('[', c);
+ require_char_ws ('[');
/* Disable constant expansion during definition processing. */
defs = md_constants;
@@ -782,9 +859,7 @@ handle_constants (void)
read_name (&value);
add_constant (defs, xstrdup (name.string), xstrdup (value.string), 0);
- c = read_skip_spaces ();
- if (c != ')')
- fatal_expected_char (')', c);
+ require_char_ws (')');
}
md_constants = defs;
}
@@ -846,9 +921,7 @@ handle_enum (file_location loc, bool md_p)
*slot = def;
}
- c = read_skip_spaces ();
- if (c != '[')
- fatal_expected_char ('[', c);
+ require_char_ws ('[');
while ((c = read_skip_spaces ()) != ']')
{
@@ -900,13 +973,35 @@ traverse_enum_types (htab_trav callback, void *info)
htab_traverse (enum_types, callback, info);
}
+
+/* Constructor for rtx_reader. */
+
+rtx_reader::rtx_reader ()
+: m_toplevel_fname (NULL),
+ m_read_md_filename (NULL),
+ m_read_md_lineno (0),
+ m_first_dir_md_include (NULL),
+ m_last_dir_md_include_ptr (&m_first_dir_md_include)
+{
+ /* Set the global singleton pointer. */
+ rtx_reader_ptr = this;
+}
+
+/* rtx_reader's destructor. */
+
+rtx_reader::~rtx_reader ()
+{
+ /* Clear the global singleton pointer. */
+ rtx_reader_ptr = NULL;
+}
+
/* Process an "include" directive, starting with the optional space
after the "include". Read in the file and use HANDLE_DIRECTIVE
to process each unknown directive. LINENO is the line number on
which the "include" occurred. */
-static void
-handle_include (file_location loc, directive_handler_t handle_directive)
+void
+rtx_reader::handle_include (file_location loc)
{
const char *filename;
const char *old_filename;
@@ -923,7 +1018,7 @@ handle_include (file_location loc, directive_handler_t handle_directive)
struct file_name_list *stackp;
/* Search the directory path, trying to open the file. */
- for (stackp = first_dir_md_include; stackp; stackp = stackp->next)
+ for (stackp = m_first_dir_md_include; stackp; stackp = stackp->next)
{
static const char sep[2] = { DIR_SEPARATOR, '\0' };
@@ -939,8 +1034,8 @@ handle_include (file_location loc, directive_handler_t handle_directive)
filename with BASE_DIR. */
if (input_file == NULL)
{
- if (base_dir)
- pathname = concat (base_dir, filename, NULL);
+ if (m_base_dir)
+ pathname = concat (m_base_dir, filename, NULL);
else
pathname = xstrdup (filename);
input_file = fopen (pathname, "r");
@@ -956,21 +1051,22 @@ handle_include (file_location loc, directive_handler_t handle_directive)
/* Save the old cursor. Note that the LINENO argument to this
function is the beginning of the include statement, while
read_md_lineno has already been advanced. */
- old_file = read_md_file;
- old_filename = read_md_filename;
- old_lineno = read_md_lineno;
+ old_file = m_read_md_file;
+ old_filename = m_read_md_filename;
+ old_lineno = m_read_md_lineno;
if (include_callback)
include_callback (pathname);
- read_md_file = input_file;
- read_md_filename = pathname;
- handle_file (handle_directive);
+ m_read_md_file = input_file;
+ m_read_md_filename = pathname;
+
+ handle_file ();
/* Restore the old cursor. */
- read_md_file = old_file;
- read_md_filename = old_filename;
- read_md_lineno = old_lineno;
+ m_read_md_file = old_file;
+ m_read_md_filename = old_filename;
+ m_read_md_lineno = old_lineno;
/* Do not free the pathname. It is attached to the various rtx
queue elements. */
@@ -980,16 +1076,16 @@ handle_include (file_location loc, directive_handler_t handle_directive)
read_md_filename are valid. Use HANDLE_DIRECTIVE to handle
unknown directives. */
-static void
-handle_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_file ()
{
struct md_name directive;
int c;
- read_md_lineno = 1;
+ m_read_md_lineno = 1;
while ((c = read_skip_spaces ()) != EOF)
{
- file_location loc (read_md_filename, read_md_lineno);
+ file_location loc = get_current_location ();
if (c != '(')
fatal_expected_char ('(', c);
@@ -1001,51 +1097,51 @@ handle_file (directive_handler_t handle_directive)
else if (strcmp (directive.string, "define_c_enum") == 0)
handle_enum (loc, false);
else if (strcmp (directive.string, "include") == 0)
- handle_include (loc, handle_directive);
- else if (handle_directive)
- handle_directive (loc, directive.string);
+ handle_include (loc);
else
- read_skip_construct (1, loc);
+ handle_unknown_directive (loc, directive.string);
- c = read_skip_spaces ();
- if (c != ')')
- fatal_expected_char (')', c);
+ require_char_ws (')');
}
- fclose (read_md_file);
+ fclose (m_read_md_file);
}
-/* Like handle_file, but for top-level files. Set up in_fname and
- base_dir accordingly. */
+/* Like handle_file, but for top-level files. Set up m_toplevel_fname
+ and m_base_dir accordingly. */
-static void
-handle_toplevel_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_toplevel_file ()
{
const char *base;
- in_fname = read_md_filename;
- base = lbasename (in_fname);
- if (base == in_fname)
- base_dir = NULL;
+ m_toplevel_fname = m_read_md_filename;
+ base = lbasename (m_toplevel_fname);
+ if (base == m_toplevel_fname)
+ m_base_dir = NULL;
else
- base_dir = xstrndup (in_fname, base - in_fname);
+ m_base_dir = xstrndup (m_toplevel_fname, base - m_toplevel_fname);
- handle_file (handle_directive);
+ handle_file ();
+}
+
+file_location
+rtx_reader::get_current_location () const
+{
+ return file_location (m_read_md_filename, m_read_md_lineno);
}
/* Parse a -I option with argument ARG. */
-static void
-parse_include (const char *arg)
+void
+rtx_reader::add_include_path (const char *arg)
{
struct file_name_list *dirtmp;
dirtmp = XNEW (struct file_name_list);
dirtmp->next = 0;
dirtmp->fname = arg;
- *last_dir_md_include_ptr = dirtmp;
- last_dir_md_include_ptr = &dirtmp->next;
- if (strlen (dirtmp->fname) > max_include_len)
- max_include_len = strlen (dirtmp->fname);
+ *m_last_dir_md_include_ptr = dirtmp;
+ m_last_dir_md_include_ptr = &dirtmp->next;
}
/* The main routine for reading .md files. Try to process all the .md
@@ -1055,16 +1151,11 @@ parse_include (const char *arg)
PARSE_OPT, if nonnull, is passed all unknown command-line arguments.
It should return true if it recognizes the argument or false if a
- generic error should be reported.
-
- If HANDLE_DIRECTIVE is nonnull, the parser calls it for each
- unknown directive, otherwise it just skips such directives.
- See the comment above the directive_handler_t definition for
- details about the callback's interface. */
+ generic error should be reported. */
bool
-read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
- directive_handler_t handle_directive)
+rtx_reader::read_md_files (int argc, const char **argv,
+ bool (*parse_opt) (const char *))
{
int i;
bool no_more_options;
@@ -1102,9 +1193,9 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
if (argv[i][1] == 'I')
{
if (argv[i][2] != '\0')
- parse_include (argv[i] + 2);
+ add_include_path (argv[i] + 2);
else if (++i < argc)
- parse_include (argv[i]);
+ add_include_path (argv[i]);
else
fatal ("directory name missing after -I option");
continue;
@@ -1132,9 +1223,9 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
if (already_read_stdin)
fatal ("cannot read standard input twice");
- read_md_file = stdin;
- read_md_filename = "<stdin>";
- handle_toplevel_file (handle_directive);
+ m_read_md_file = stdin;
+ m_read_md_filename = "<stdin>";
+ handle_toplevel_file ();
already_read_stdin = true;
continue;
}
@@ -1150,14 +1241,14 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
/* If we get here we are looking at a non-option argument, i.e.
a file to be processed. */
- read_md_filename = argv[i];
- read_md_file = fopen (read_md_filename, "r");
- if (read_md_file == 0)
+ m_read_md_filename = argv[i];
+ m_read_md_file = fopen (m_read_md_filename, "r");
+ if (m_read_md_file == 0)
{
- perror (read_md_filename);
+ perror (m_read_md_filename);
return false;
}
- handle_toplevel_file (handle_directive);
+ handle_toplevel_file ();
num_files++;
}
@@ -1165,10 +1256,19 @@ read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
read the standard input now. */
if (num_files == 0 && !already_read_stdin)
{
- read_md_file = stdin;
- read_md_filename = "<stdin>";
- handle_toplevel_file (handle_directive);
+ m_read_md_file = stdin;
+ m_read_md_filename = "<stdin>";
+ handle_toplevel_file ();
}
return !have_error;
}
+
+/* class noop_reader : public rtx_reader */
+
+/* A dummy implementation which skips unknown directives. */
+void
+noop_reader::handle_unknown_directive (file_location loc, const char *)
+{
+ read_skip_construct (1, loc);
+}
@@ -21,18 +21,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_READ_MD_H
#include "obstack.h"
-
-/* Records a position in the file. */
-struct file_location {
- file_location () {}
- file_location (const char *, int);
-
- const char *filename;
- int lineno;
-};
-
-inline file_location::file_location (const char *filename_in, int lineno_in)
- : filename (filename_in), lineno (lineno_in) {}
+#include "errors.h"
/* Holds one symbol or number in the .md file. */
struct md_name {
@@ -90,16 +79,122 @@ struct enum_type {
unsigned int num_values;
};
-/* A callback that handles a single .md-file directive, up to but not
- including the closing ')'. It takes two arguments: the file position
- at which the directive started, and the name of the directive. The next
- unread character is the optional space after the directive name. */
-typedef void (*directive_handler_t) (file_location, const char *);
+class rtx_reader
+{
+ public:
+ rtx_reader ();
+ virtual ~rtx_reader ();
+
+ bool read_md_files (int, const char **, bool (*) (const char *));
+
+ /* A hook that handles a single .md-file directive, up to but not
+ including the closing ')'. It takes two arguments: the file position
+ at which the directive started, and the name of the directive. The next
+ unread character is the optional space after the directive name. */
+ virtual void handle_unknown_directive (file_location, const char *) = 0;
+
+ /* A hook for the RTL frontend to override, to record insn UIDs for later
+ fixup. */
+ virtual void add_fixup_insn_uid (file_location /*loc*/, rtx /*insn*/,
+ int /*operand_idx*/, int /*insn_uid*/)
+ {}
+
+ /* A hook for the RTL frontend to override, to record basic block IDs
+ for later fixup. */
+ virtual void add_fixup_bb (file_location /*loc*/, rtx /*insn*/,
+ int /*operand_idx*/, int /*bb_idx*/)
+ {}
+
+ /* A hook for the RTL frontend to override, to record basic block IDs
+ for fixup of NOTE_INSN_BASIC_BLOCK. */
+ virtual void add_fixup_note_insn_basic_block (file_location /*loc*/,
+ rtx /*insn*/,
+ int /*operand_idx*/,
+ int /*bb_idx*/)
+ {}
+
+ /* A hook for the RTL frontend to override, to record source location
+ information for fixing up into location_t values. */
+ virtual void add_fixup_source_location (file_location /*loc*/, rtx /*insn*/,
+ int /*operand_idx*/,
+ const char */*filename*/,
+ int /*lineno*/)
+ {}
+
+ /* A hook for the RTL frontend to override, to record label names
+ for fixing up the JUMP_LABEL of an insn. */
+ virtual void add_fixup_jump_label (file_location /*loc*/, rtx /*insn*/,
+ int /*operand_idx*/,
+ const char */*label*/)
+ {}
+
+ /* A hook for the RTL frontend to override, to record textual tree
+ dumps for fix up the expr of an rtx (REG or MEM). */
+ virtual void add_fixup_expr (file_location /*loc*/, rtx /*x*/,
+ const char */*desc*/)
+ {}
+
+ file_location get_current_location () const;
+
+ int read_char (void);
+ void unread_char (int ch);
+
+ const char *get_top_level_filename () const { return m_toplevel_fname; }
+ const char *get_filename () const { return m_read_md_filename; }
+ int get_lineno () const { return m_read_md_lineno; }
+
+ private:
+ /* A singly-linked list of filenames. */
+ struct file_name_list {
+ struct file_name_list *next;
+ const char *fname;
+ };
+
+ private:
+ void handle_file ();
+ void handle_toplevel_file ();
+ void handle_include (file_location loc);
+ void add_include_path (const char *arg);
+
+ private:
+ /* The name of the toplevel file that indirectly included
+ m_read_md_file. */
+ const char *m_toplevel_fname;
+
+ /* The directory part of m_toplevel_fname
+ NULL if m_toplevel_fname is a bare filename. */
+ char *m_base_dir;
+
+ /* The file we are reading. */
+ FILE *m_read_md_file;
+
+ /* The filename of m_read_md_file. */
+ const char *m_read_md_filename;
+
+ /* The current line number in m_read_md_file. */
+ int m_read_md_lineno;
+
+ /* The first directory to search. */
+ file_name_list *m_first_dir_md_include;
+
+ /* A pointer to the null terminator of the md include chain. */
+ file_name_list **m_last_dir_md_include_ptr;
+};
+
+/* Global singleton. */
+extern rtx_reader *rtx_reader_ptr;
+
+/* An rtx_reader subclass which skips unknown directives. */
+
+class noop_reader : public rtx_reader
+{
+ public:
+ noop_reader () : rtx_reader () {}
+
+ /* A dummy implementation which skips unknown directives. */
+ void handle_unknown_directive (file_location, const char *);
+};
-extern const char *in_fname;
-extern FILE *read_md_file;
-extern int read_md_lineno;
-extern const char *read_md_filename;
extern struct obstack string_obstack;
extern void (*include_callback) (const char *);
@@ -108,12 +203,7 @@ extern void (*include_callback) (const char *);
static inline int
read_char (void)
{
- int ch;
-
- ch = getc (read_md_file);
- if (ch == '\n')
- read_md_lineno++;
- return ch;
+ return rtx_reader_ptr->read_char ();
}
/* Put back CH, which was the last character read from the MD file. */
@@ -121,11 +211,11 @@ read_char (void)
static inline void
unread_char (int ch)
{
- if (ch == '\n')
- read_md_lineno--;
- ungetc (ch, read_md_file);
+ rtx_reader_ptr->unread_char (ch);
}
+extern int peek_char (void);
+
extern hashval_t leading_string_hash (const void *);
extern int leading_string_eq_p (const void *, const void *);
extern void copy_md_ptr_loc (const void *, const void *);
@@ -141,7 +231,11 @@ extern void fatal_with_file_and_line (const char *, ...)
ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
extern void fatal_expected_char (int, int) ATTRIBUTE_NORETURN;
extern int read_skip_spaces (void);
-extern void read_name (struct md_name *);
+extern void require_char (char expected);
+extern void require_char_ws (char expected);
+extern void require_word_ws (const char *expected);
+extern file_location read_name (struct md_name *);
+extern file_location read_name_or_nil (struct md_name *);
extern char *read_quoted_string (void);
extern char *read_string (int);
extern int n_comma_elts (const char *);
@@ -150,7 +244,5 @@ extern void upcase_string (char *);
extern void traverse_md_constants (htab_trav, void *);
extern void traverse_enum_types (htab_trav, void *);
extern struct enum_type *lookup_enum_type (const char *);
-extern bool read_md_files (int, const char **, bool (*) (const char *),
- directive_handler_t);
#endif /* GCC_READ_MD_H */
@@ -17,7 +17,13 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+/* This file is compiled twice: once for the generator programs
+ once for the compiler. */
+#ifdef GENERATOR_FILE
#include "bconfig.h"
+#else
+#include "config.h"
+#endif
/* Disable rtl checking; it conflicts with the iterator handling. */
#undef ENABLE_RTL_CHECKING
@@ -30,6 +36,11 @@ along with GCC; see the file COPYING3. If not see
#include "read-md.h"
#include "gensupport.h"
+#ifndef GENERATOR_FILE
+#include "function.h"
+#include "emit-rtl.h"
+#endif
+
/* One element in a singly-linked list of (integer, string) pairs. */
struct map_value {
struct map_value *next;
@@ -106,7 +117,7 @@ htab_t subst_attr_to_iter_map = NULL;
const char *current_iterator_name;
static void validate_const_int (const char *);
-static rtx read_rtx_code (const char *);
+static void one_time_initialization (void);
static rtx read_nested_rtx (void);
static rtx read_rtx_variadic (rtx);
@@ -181,6 +192,8 @@ apply_int_iterator (void *loc, int value)
*(int *)loc = value;
}
+#ifdef GENERATOR_FILE
+
/* This routine adds attribute or does nothing depending on VALUE. When
VALUE is 1, it does nothing - the first duplicate of original
template is kept untouched when it's subjected to a define_subst.
@@ -252,6 +265,8 @@ bind_subst_iter_and_attr (const char *iter, const char *attr)
*slot = value;
}
+#endif /* #ifdef GENERATOR_FILE */
+
/* Return name of a subst-iterator, corresponding to subst-attribute ATTR. */
static char*
@@ -418,6 +433,8 @@ copy_rtx_for_iterators (rtx original)
return x;
}
+#ifdef GENERATOR_FILE
+
/* Return a condition that must satisfy both ORIGINAL and EXTRA. If ORIGINAL
has the form "&& ..." (as used in define_insn_and_splits), assume that
EXTRA is already satisfied. Empty strings are treated like "true". */
@@ -581,6 +598,7 @@ apply_iterators (rtx original, vec<rtx> *queue)
}
}
}
+#endif /* #ifdef GENERATOR_FILE */
/* Add a new "mapping" structure to hashtable TABLE. NAME is the name
of the mapping and GROUP is the group to which it belongs. */
@@ -655,7 +673,9 @@ initialize_iterators (void)
substs.iterators = htab_create (13, leading_string_hash,
leading_string_eq_p, 0);
substs.find_builtin = find_int; /* We don't use it, anyway. */
+#ifdef GENERATOR_FILE
substs.apply_iterator = apply_subst_iterator;
+#endif
lower = add_mapping (&modes, modes.attrs, "mode");
upper = add_mapping (&modes, modes.attrs, "MODE");
@@ -724,6 +744,8 @@ atoll (const char *p)
}
#endif
+
+#ifdef GENERATOR_FILE
/* Process a define_conditions directive, starting with the optional
space after the "define_conditions". The directive looks like this:
@@ -742,9 +764,7 @@ read_conditions (void)
{
int c;
- c = read_skip_spaces ();
- if (c != '[')
- fatal_expected_char ('[', c);
+ require_char_ws ('[');
while ( (c = read_skip_spaces ()) != ']')
{
@@ -759,18 +779,15 @@ read_conditions (void)
validate_const_int (name.string);
value = atoi (name.string);
- c = read_skip_spaces ();
- if (c != '"')
- fatal_expected_char ('"', c);
+ require_char_ws ('"');
expr = read_quoted_string ();
- c = read_skip_spaces ();
- if (c != ')')
- fatal_expected_char (')', c);
+ require_char_ws (')');
add_c_test (expr, value);
}
}
+#endif /* #ifdef GENERATOR_FILE */
static void
validate_const_int (const char *string)
@@ -867,6 +884,8 @@ record_potential_iterator_use (struct iterator_group *group, void *ptr,
}
}
+#ifdef GENERATOR_FILE
+
/* Finish reading a declaration of the form:
(define... <name> [<value1> ... <valuen>])
@@ -890,9 +909,7 @@ read_mapping (struct iterator_group *group, htab_t table)
read_name (&name);
m = add_mapping (group, table, name.string);
- c = read_skip_spaces ();
- if (c != '[')
- fatal_expected_char ('[', c);
+ require_char_ws ('[');
/* Read each value. */
end_ptr = &m->values;
@@ -912,9 +929,7 @@ read_mapping (struct iterator_group *group, htab_t table)
/* A "(name string)" pair. */
read_name (&name);
string = read_string (false);
- c = read_skip_spaces ();
- if (c != ')')
- fatal_expected_char (')', c);
+ require_char_ws (')');
}
number = group->find_builtin (name.string);
end_ptr = add_map_value (end_ptr, number, string);
@@ -1030,14 +1045,7 @@ check_code_iterator (struct mapping *iterator)
bool
read_rtx (const char *rtx_name, vec<rtx> *rtxen)
{
- static bool initialized = false;
-
- /* Do one-time initialization. */
- if (!initialized)
- {
- initialize_iterators ();
- initialized = true;
- }
+ one_time_initialization ();
/* Handle various rtx-related declarations that aren't themselves
encoded as rtxes. */
@@ -1092,16 +1100,187 @@ read_rtx (const char *rtx_name, vec<rtx> *rtxen)
return true;
}
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Do one-time initialization. */
+
+static void
+one_time_initialization (void)
+{
+ static bool initialized = false;
+
+ if (!initialized)
+ {
+ initialize_iterators ();
+ initialized = true;
+ }
+}
+
+#ifndef GENERATOR_FILE
+static int
+parse_reg_note_name (const char *string)
+{
+ for (int i = 0; i < REG_NOTE_MAX; i++)
+ if (0 == strcmp (string, GET_REG_NOTE_NAME (i)))
+ return i;
+ fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
+}
+
+static int
+parse_note_insn_name (const char *string)
+{
+ for (int i = 0; i < NOTE_INSN_MAX; i++)
+ if (0 == strcmp (string, GET_NOTE_INSN_NAME (i)))
+ return i;
+ fatal_with_file_and_line ("unrecognized NOTE_INSN name: `%s'", string);
+}
+
+/* Handle the optional location information written by print_rtx for
+ instructions. Specifically, operand 4 of instructions (of type "i')
+ is printed thus:
+
+ if (INSN_HAS_LOCATION (in_insn))
+ {
+ expanded_location xloc = insn_location (in_insn);
+ fprintf (outfile, " %s:%i", xloc.file, xloc.line);
+ }
+
+ Hence we need to speculatively read a location of the form
+ " %s:%i", and unread the content if there wasn't one.
+
+ Assume that filenames can't contain whitespace, and can't
+ contain ':'. */
+
+void maybe_read_location (int operand_idx, rtx insn)
+{
+ file_location loc = rtx_reader_ptr->get_current_location ();
+
+ /* Skip to first non-whitespace. */
+ int ch = read_skip_spaces ();
+ auto_vec<char> buf;
+ buf.safe_push (ch);
+ while (1)
+ {
+ int ch = read_char ();
+ /* If we see a ':', assume we have a filename. */
+ if (ch == ':')
+ {
+ buf.safe_push ('\0');
+ break;
+ }
+ buf.safe_push (ch);
+
+ /* If we see a space before ':', assume we don't have a
+ filename. */
+ if (ISSPACE (ch))
+ {
+ while (!buf.is_empty ())
+ unread_char (buf.pop ());
+ return;
+ }
+ }
+ char *filename = buf.address ();
+ struct md_name name;
+ read_name (&name);
+
+ rtx_reader_ptr->add_fixup_source_location (loc, insn, operand_idx,
+ filename, atoi(name.string));
+}
+
+/* Consume characters until encountering a character in TERMINATOR_CHARS,
+ consuming the terminator character if CONSUME_TERMINATOR is true.
+ Return all characters before the terminator as an allocated buffer. */
+
+static char *
+read_until (const char *terminator_chars, bool consume_terminator)
+{
+ int ch = read_skip_spaces ();
+ unread_char (ch);
+ auto_vec<char> buf;
+ while (1)
+ {
+ ch = read_char ();
+ if (strchr (terminator_chars, ch))
+ {
+ if (!consume_terminator)
+ unread_char (ch);
+ break;
+ }
+ buf.safe_push (ch);
+ }
+ buf.safe_push ('\0');
+ return xstrdup (buf.address ());
+}
+
+static void strip_trailing_whitespace (char *desc)
+{
+ char *terminator = desc + strlen (desc);
+ while (desc < terminator)
+ {
+ terminator--;
+ if (ISSPACE (*terminator))
+ *terminator = '\0';
+ else
+ break;
+ }
+}
+
+#endif /* #ifndef GENERATOR_FILE */
+
+/* Subroutine of read_rtx_code, for parsing zero or more flags. */
+
+static void
+read_flags (rtx return_rtx)
+{
+ while (1)
+ {
+ int ch = read_char ();
+ if (ch != '/')
+ {
+ unread_char (ch);
+ break;
+ }
+
+ int flag_char = read_char ();
+ switch (flag_char)
+ {
+ case 's':
+ RTX_FLAG (return_rtx, in_struct) = 1;
+ break;
+ case 'v':
+ RTX_FLAG (return_rtx, volatil) = 1;
+ break;
+ case 'u':
+ RTX_FLAG (return_rtx, unchanging) = 1;
+ break;
+ case 'f':
+ RTX_FLAG (return_rtx, frame_related) = 1;
+ break;
+ case 'j':
+ RTX_FLAG (return_rtx, jump) = 1;
+ break;
+ case 'c':
+ RTX_FLAG (return_rtx, call) = 1;
+ break;
+ case 'i':
+ RTX_FLAG (return_rtx, return_val) = 1;
+ break;
+ default:
+ fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char);
+ }
+ }
+}
+
/* Subroutine of read_rtx and read_nested_rtx. CODE_NAME is the name of
either an rtx code or a code iterator. Parse the rest of the rtx and
return it. */
-static rtx
+rtx
read_rtx_code (const char *code_name)
{
int i;
RTX_CODE code;
- struct mapping *iterator, *m;
+ struct mapping *iterator = NULL, *m;
const char *format_ptr;
struct md_name name;
rtx return_rtx;
@@ -1118,13 +1297,19 @@ read_rtx_code (const char *code_name)
rtx value; /* Value of this node. */
};
+ one_time_initialization ();
+
/* If this code is an iterator, build the rtx using the iterator's
first value. */
+#ifdef GENERATOR_FILE
iterator = (struct mapping *) htab_find (codes.iterators, &code_name);
if (iterator != 0)
code = (enum rtx_code) iterator->values->number;
else
code = (enum rtx_code) codes.find_builtin (code_name);
+#else
+ code = (enum rtx_code) codes.find_builtin (code_name);
+#endif
/* If we end up with an insn expression then we free this space below. */
return_rtx = rtx_alloc (code);
@@ -1135,6 +1320,27 @@ read_rtx_code (const char *code_name)
if (iterator)
record_iterator_use (iterator, return_rtx);
+ /* Check for flags. */
+ read_flags (return_rtx);
+
+ /* Read REG_NOTE names for EXPR_LIST and INSN_LIST. */
+#ifndef GENERATOR_FILE
+ if (GET_CODE (return_rtx) == EXPR_LIST
+ || GET_CODE (return_rtx) == INSN_LIST
+ || GET_CODE (return_rtx) == INT_LIST)
+ {
+ char ch = read_char ();
+ if (ch == ':')
+ {
+ read_name (&name);
+ PUT_MODE_RAW (return_rtx,
+ (machine_mode)parse_reg_note_name (name.string));
+ }
+ else
+ unread_char (ch);
+ }
+#endif
+
/* If what follows is `: mode ', read it and
store the mode in the rtx. */
@@ -1147,6 +1353,12 @@ read_rtx_code (const char *code_name)
else
unread_char (i);
+ if (INSN_CHAIN_CODE_P (code))
+ {
+ read_name (&name);
+ INSN_UID (return_rtx) = atoi (name.string);
+ }
+
for (i = 0; format_ptr[i] != 0; i++)
switch (format_ptr[i])
{
@@ -1155,11 +1367,65 @@ read_rtx_code (const char *code_name)
case '0':
if (code == REG)
ORIGINAL_REGNO (return_rtx) = REGNO (return_rtx);
+ else if (i == 3 && code == NOTE)
+ {
+ /* Note-specific data appears for operand 3, which annoyingly
+ is before the enum specifying which kind of note we have
+ (operand 4). */
+#ifndef GENERATOR_FILE
+ c = read_skip_spaces ();
+ if (c == '[')
+ {
+ /* Possibly data for a NOTE_INSN_BASIC_BLOCK, of the form:
+ [bb %d]. */
+ file_location bb_loc = read_name (&name);
+ if (strcmp (name.string, "bb"))
+ error_at (bb_loc, "was expecting `%s'", "bb");
+ read_name (&name);
+ int bb_idx = atoi (name.string);
+ rtx_reader_ptr->add_fixup_note_insn_basic_block (bb_loc,
+ return_rtx, i,
+ bb_idx);
+ require_char_ws (']');
+ }
+ else
+ unread_char (c);
+#endif /* #ifndef GENERATOR_FILE */
+ }
+ else if (i == 7 && JUMP_P (return_rtx))
+ {
+#ifndef GENERATOR_FILE
+ c = read_skip_spaces ();
+ if (c != '-')
+ {
+ unread_char (c);
+ break;
+ }
+ require_char ('>');
+ file_location loc = read_name (&name);
+ rtx_reader_ptr->add_fixup_jump_label (loc, return_rtx, i, name.string);
+#endif /* #ifndef GENERATOR_FILE */
+ }
break;
case 'e':
+ XEXP (return_rtx, i) = read_nested_rtx ();
+ break;
+
case 'u':
+#ifdef GENERATOR_FILE
XEXP (return_rtx, i) = read_nested_rtx ();
+#else
+ {
+ /* The RTL file recorded the ID of an insn (or 0 for NULL); we
+ must store this as a pointer, but the insn might not have
+ been loaded yet. Store the ID away for now. */
+ file_location loc = read_name (&name);
+ int insn_id = atoi (name.string);
+ if (insn_id)
+ rtx_reader_ptr->add_fixup_insn_uid (loc, return_rtx, i, insn_id);
+ }
+#endif
break;
case 'V':
@@ -1181,9 +1447,7 @@ read_rtx_code (const char *code_name)
int list_counter = 0;
rtvec return_vec = NULL_RTVEC;
- c = read_skip_spaces ();
- if (c != '[')
- fatal_expected_char ('[', c);
+ require_char_ws ('[');
/* Add expressions to a list, while keeping a count. */
obstack_init (&vector_stack);
@@ -1234,7 +1498,10 @@ read_rtx_code (const char *code_name)
star_if_braced = (format_ptr[i] == 'T');
stringbuf = read_string (star_if_braced);
+ if (!stringbuf)
+ break;
+#ifdef GENERATOR_FILE
/* For insn patterns, we want to provide a default name
based on the file and line, like "*foo.md:12", if the
given name is blank. These are only for define_insn and
@@ -1245,6 +1512,7 @@ read_rtx_code (const char *code_name)
|| GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
{
char line_name[20];
+ const char *read_md_filename = rtx_reader_ptr->get_filename ();
const char *fn = (read_md_filename ? read_md_filename : "rtx");
const char *slash;
for (slash = fn; *slash; slash ++)
@@ -1252,10 +1520,11 @@ read_rtx_code (const char *code_name)
fn = slash + 1;
obstack_1grow (&string_obstack, '*');
obstack_grow (&string_obstack, fn, strlen (fn));
- sprintf (line_name, ":%d", read_md_lineno);
+ sprintf (line_name, ":%d", rtx_reader_ptr->get_lineno ());
obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
stringbuf = XOBFINISH (&string_obstack, char *);
}
+#endif /* #ifdef GENERATOR_FILE */
/* Find attr-names in the string. */
ptr = &tmpstr[0];
@@ -1311,14 +1580,57 @@ read_rtx_code (const char *code_name)
#endif
#endif
XWINT (return_rtx, i) = tmp_wide;
+#ifndef GENERATOR_FILE
+ /* Strip away the redundant hex dump of the value. */
+ {
+ require_char_ws ('[');
+ read_name (&name);
+ require_char_ws (']');
+ }
+#endif
break;
case 'i':
case 'n':
+#ifdef GENERATOR_FILE
/* Can be an iterator or an integer constant. */
read_name (&name);
record_potential_iterator_use (&ints, &XINT (return_rtx, i),
name.string);
+#else
+ /* Handle some of the extra information that print_rtx
+ can write out for these cases. */
+ {
+ /* print_rtx only writes out operand 5 for notes
+ for NOTE_KIND values NOTE_INSN_DELETED_LABEL
+ and NOTE_INSN_DELETED_DEBUG_LABEL. */
+ if (i == 5 && NOTE_P (return_rtx))
+ break;
+
+ if (i == 4 && INSN_P (return_rtx))
+ {
+ maybe_read_location (i, return_rtx);
+ break;
+ }
+
+ read_name (&name);
+ int value;
+ if (format_ptr[i] == 'n')
+ value = parse_note_insn_name (name.string);
+ else
+ value = atoi (name.string);
+ XINT (return_rtx, i) = value;
+ }
+#endif
+ break;
+
+ case 'B':
+ {
+ file_location loc = read_name_or_nil (&name);
+ int bb_idx = atoi (name.string);
+ if (bb_idx)
+ rtx_reader_ptr->add_fixup_bb (loc, return_rtx, i, bb_idx);
+ }
break;
case 'r':
@@ -1326,12 +1638,166 @@ read_rtx_code (const char *code_name)
validate_const_int (name.string);
set_regno_raw (return_rtx, atoi (name.string), 1);
REG_ATTRS (return_rtx) = NULL;
+#ifndef GENERATOR_FILE
+ {
+ unsigned int regno = REGNO (return_rtx);
+ ORIGINAL_REGNO (return_rtx) = regno;
+
+ /* print_rtx can print a name for various registers
+ after the register number. Skip and discard it. */
+ if (regno < FIRST_PSEUDO_REGISTER
+ || regno <= LAST_VIRTUAL_REGISTER)
+ read_name (&name);
+
+ /* Parse extra stuff at end of 'r'.
+ We may have zero, one, or two sections marked by square
+ brackets. */
+ int ch = read_skip_spaces ();
+ bool expect_original_regno = false;
+ if (ch == '[')
+ {
+ file_location loc = rtx_reader_ptr->get_current_location ();
+ char *desc = read_until ("]", true);
+ strip_trailing_whitespace (desc);
+ const char *desc_start = desc;
+ /* If ORIGINAL_REGNO (rtx) != regno, we will have:
+ "orig:%i", ORIGINAL_REGNO (rtx).
+ Consume it, we don't set ORIGINAL_REGNO, since we can
+ get that from the 2nd copy later. */
+ if (0 == strncmp (desc, "orig:", 5))
+ {
+ expect_original_regno = true;
+ desc_start += 5;
+ /* Skip to any whitespace following the integer. */
+ const char *space = strchr (desc_start, ' ');
+ if (space)
+ desc_start = space + 1;
+ }
+ /* Any remaining text may be the REG_EXPR. Alternatively we have
+ no REG_ATTRS, and instead we have ORIGINAL_REGNO. */
+ if (ISDIGIT (*desc_start))
+ {
+ /* Assume we have ORIGINAL_REGNO. */
+ ORIGINAL_REGNO (return_rtx) = atoi (desc_start);
+ }
+ else
+ {
+ /* Assume we have REG_EXPR. */
+ rtx_reader_ptr->add_fixup_expr (loc, return_rtx, desc_start);
+ }
+ free (desc);
+ }
+ else
+ unread_char (ch);
+ if (expect_original_regno)
+ {
+ require_char_ws ('[');
+ char *desc = read_until ("]", true);
+ ORIGINAL_REGNO (return_rtx) = atoi (desc);
+ free (desc);
+ }
+ }
+#endif
break;
default:
gcc_unreachable ();
}
+#ifndef GENERATOR_FILE
+ /* Handle the various additional information that print-rtl.c can
+ write after the regular fields. */
+ switch (GET_CODE (return_rtx))
+ {
+ case MEM:
+ {
+ int ch;
+ require_char_ws ('[');
+ read_name (&name);
+ MEM_ALIAS_SET (return_rtx) = atoi (name.string);
+ /* We have either a MEM_EXPR, or a space. */
+ if (peek_char () != ' ')
+ {
+ file_location loc = rtx_reader_ptr->get_current_location ();
+ char *desc = read_until (" +", false);
+ rtx_reader_ptr->add_fixup_expr (loc, return_rtx, desc);
+ free (desc);
+ }
+ else
+ read_char ();
+
+ /* We may optionally have '+' for MEM_OFFSET_KNOWN_P. */
+ ch = read_skip_spaces ();
+ if (ch == '+')
+ {
+ read_name (&name);
+ MEM_OFFSET_KNOWN_P (return_rtx) = 1;
+ MEM_OFFSET (return_rtx) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ /* Handle optional " S" for MEM_SIZE. */
+ ch = read_skip_spaces ();
+ if (ch == 'S')
+ {
+ read_name (&name);
+ MEM_SIZE (return_rtx) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ /* Handle optional " A" for MEM_ALIGN. */
+ ch = read_skip_spaces ();
+ if (ch == 'A' && peek_char () != 'S')
+ {
+ read_name (&name);
+ MEM_ALIGN (return_rtx) = atoi (name.string);
+ }
+
+ /* Handle optional " AS" for MEM_ADDR_SPACE. */
+ ch = read_skip_spaces ();
+ if (ch == 'A' && peek_char () == 'S')
+ {
+ read_char ();
+ read_name (&name);
+ MEM_ADDR_SPACE (return_rtx) = atoi (name.string);
+ }
+ else
+ unread_char (ch);
+
+ require_char (']');
+ }
+ break;
+
+ case CODE_LABEL:
+ {
+ /* Parse LABEL_NUSES. */
+ require_char_ws ('[');
+ read_name (&name);
+ LABEL_NUSES (return_rtx) = atoi (name.string);
+ require_word_ws ("uses");
+ require_char_ws (']');
+ /* TODO: parse LABEL_KIND. */
+ /* For now, skip until closing ')'. */
+ do
+ {
+ char ch = read_char ();
+ if (ch == ')')
+ {
+ unread_char (ch);
+ break;
+ }
+ }
+ while (1);
+ }
+ break;
+
+ default:
+ break;
+ }
+#endif
+
if (CONST_WIDE_INT_P (return_rtx))
{
read_name (&name);
@@ -1392,18 +1858,146 @@ read_rtx_code (const char *code_name)
return return_rtx;
}
+#ifndef GENERATOR_FILE
+
+/* Helper function for consolidate_reg. */
+
+static rtx
+lookup_global_register (int regno)
+{
+ /* FIXME: do we need to check for Pmode? */
+ switch (regno)
+ {
+ case STACK_POINTER_REGNUM:
+ return stack_pointer_rtx;
+ case FRAME_POINTER_REGNUM:
+ return frame_pointer_rtx;
+ case HARD_FRAME_POINTER_REGNUM:
+ return hard_frame_pointer_rtx;
+ case ARG_POINTER_REGNUM:
+ return arg_pointer_rtx;
+ case VIRTUAL_INCOMING_ARGS_REGNUM:
+ return virtual_incoming_args_rtx;
+ case VIRTUAL_STACK_VARS_REGNUM:
+ return virtual_stack_vars_rtx;
+ case VIRTUAL_STACK_DYNAMIC_REGNUM:
+ return virtual_stack_dynamic_rtx;
+ case VIRTUAL_OUTGOING_ARGS_REGNUM:
+ return virtual_outgoing_args_rtx;
+ case VIRTUAL_CFA_REGNUM:
+ return virtual_cfa_rtx;
+ case VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM:
+ return virtual_preferred_stack_boundary_rtx;
+#ifdef return_ADDRESS_POINTER_REGNUM
+ case RETURN_ADDRESS_POINTER_REGNUM:
+ return return_address_pointer_rtx;
+#endif
+ }
+ return NULL;
+}
+
+/* Helper function for consolidate_singletons, for handling REG instances. */
+
+static rtx
+consolidate_reg (rtx x)
+{
+ gcc_assert (GET_CODE (x) == REG);
+
+ unsigned int regno = REGNO (x);
+
+ /* Normally REG instances are created by gen_reg_rtx which updates
+ regno_reg_rtx, growing it as necessary.
+ The REG instances created from the dumpfile weren't created this
+ way, so we need to manually update regno_reg_rtx. */
+ if (regno >= crtl->emit.regno_pointer_align_length)
+ {
+ int old_size = crtl->emit.regno_pointer_align_length;
+ int new_size = old_size * 2;
+ char *tmp;
+ rtx *new1;
+
+ tmp = XRESIZEVEC (char, crtl->emit.regno_pointer_align, new_size);
+ memset (tmp + old_size, 0, old_size);
+ crtl->emit.regno_pointer_align = (unsigned char *) tmp;
+
+ new1 = GGC_RESIZEVEC (rtx, regno_reg_rtx, new_size);
+ memset (new1 + old_size, 0, (new_size - old_size) * sizeof (rtx));
+ regno_reg_rtx = new1;
+
+ crtl->emit.regno_pointer_align_length = old_size * 2;
+ }
+ gcc_assert (regno < crtl->emit.regno_pointer_align_length);
+
+ if (reg_rtx_no < regno + 1)
+ reg_rtx_no = regno + 1;
+
+ /* Some register numbers have their rtx created in init_emit_regs
+ e.g. stack_pointer_rtx for STACK_POINTER_REGNUM.
+ Consolidate on this. */
+ rtx global_reg = lookup_global_register (regno);
+ if (global_reg)
+ return global_reg;
+
+ /* Populate regno_reg_rtx if necessary. */
+ if (regno_reg_rtx[regno] == NULL)
+ regno_reg_rtx[regno] = x;
+ /* Use it. */
+ gcc_assert (GET_CODE (regno_reg_rtx[regno]) == REG);
+ gcc_assert (REGNO (regno_reg_rtx[regno]) == regno);
+ if (GET_MODE (x) == GET_MODE (regno_reg_rtx[regno]))
+ return regno_reg_rtx[regno];
+
+ return x;
+}
+
+/* When running in the RTL frontend, we must consolidate some
+ rtx so that we use singletons where singletons are expected
+ (e.g. we don't want multiple "(const_int 0 [0])" rtx, since
+ these are tested via pointer equality against const0_rtx. */
+
+static rtx
+consolidate_singletons (rtx x)
+{
+ if (!x)
+ return x;
+
+ switch (GET_CODE (x))
+ {
+ /* FIXME: do we need to check for VOIDmode for these? */
+ case PC: return pc_rtx;
+ case RETURN: return ret_rtx;
+ case SIMPLE_RETURN: return simple_return_rtx;
+ case CC0: return cc0_rtx;
+
+ case REG:
+ return consolidate_reg (x);
+
+ case CONST_INT:
+ {
+ if (INTVAL (x) == 0)
+ return const0_rtx;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return x;
+}
+
+#endif /* #ifndef GENERATOR_FILE */
+
+
/* Read a nested rtx construct from the MD file and return it. */
static rtx
read_nested_rtx (void)
{
struct md_name name;
- int c;
rtx return_rtx;
- c = read_skip_spaces ();
- if (c != '(')
- fatal_expected_char ('(', c);
+ require_char_ws ('(');
read_name (&name);
if (strcmp (name.string, "nil") == 0)
@@ -1411,9 +2005,11 @@ read_nested_rtx (void)
else
return_rtx = read_rtx_code (name.string);
- c = read_skip_spaces ();
- if (c != ')')
- fatal_expected_char (')', c);
+ require_char_ws (')');
+
+#ifndef GENERATOR_FILE
+ return_rtx = consolidate_singletons (return_rtx);
+#endif /* #ifndef GENERATOR_FILE */
return return_rtx;
}
@@ -878,3 +878,5 @@ rtl_check_failed_flag (const char *name, const_rtx r, const char *file,
name, GET_RTX_NAME (GET_CODE (r)), func, trim_filename (file), line);
}
#endif /* ENABLE_RTL_FLAG_CHECKING */
+
+bool in_rtl_frontend_p = false;
@@ -3641,7 +3641,10 @@ extern void init_varasm_once (void);
extern rtx make_debug_expr_from_rtl (const_rtx);
/* In read-rtl.c */
+#ifdef GENERATOR_FILE
extern bool read_rtx (const char *, vec<rtx> *);
+#endif
+extern rtx read_rtx_code (const char *code_name);
/* In alias.c */
extern rtx canon_rtx (rtx);
@@ -3746,5 +3749,6 @@ struct GTY(()) cgraph_rtl_info {
unsigned function_used_regs_valid: 1;
};
+extern bool in_rtl_frontend_p;
#endif /* ! GCC_RTL_H */
new file mode 100644
@@ -0,0 +1,148 @@
+# Make-lang.in -- Top level -*- makefile -*- fragment for RTL frontend.
+
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This file is part of GCC.
+
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# This file provides the language dependent support in the main Makefile.
+
+# The name for selecting the RTL frontend in LANGUAGES.
+rtl: rtl1$(exeext)
+
+.PHONY: rtl
+
+# Use strict warnings.
+rtl-warn = $(STRICT_WARN)
+
+RTL_OBJS = \
+ rtl/rtl-errors.o \
+ rtl/rtl-frontend.o \
+ read-md.o \
+ read-rtl.o
+
+rtl1$(exeext): $(RTL_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
+ +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+ $(RTL_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
+
+# Build hooks:
+
+rtl.all.cross:
+rtl.start.encap:
+rtl.rest.encap:
+rtl.info:
+rtl.man:
+
+lang_checks += check-rtl
+lang_checks_parallelized += check-rtl
+check_rtl_parallelize = 10
+
+# Install hooks.
+
+rtl.install-common: installdirs
+ -rm -f $(DESTDIR)$(bindir)/$(GCCRTL_INSTALL_NAME)$(exeext)
+ $(INSTALL_PROGRAM) gccrtl$(exeext) $(DESTDIR)$(bindir)/$(GCCRTL_INSTALL_NAME)$(exeext)
+ -if test -f rtl1$(exeext); then \
+ if test -f gccrtl-cross$(exeext); then \
+ :; \
+ else \
+ rm -f $(DESTDIR)$(bindir)/$(GCCRTL_TARGET_INSTALL_NAME)$(exeext); \
+ ( cd $(DESTDIR)$(bindir) && \
+ $(LN) $(GCCRTL_INSTALL_NAME)$(exeext) $(GCCRTL_TARGET_INSTALL_NAME)$(exeext) ); \
+ fi; \
+ fi
+
+rtl.install-plugin:
+
+rtl.install-info: $(DESTDIR)$(infodir)/gccrtl.info
+
+rtl.install-pdf: doc/gccrtl.pdf
+ @$(NORMAL_INSTALL)
+ test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
+ @for p in doc/gccrtl.pdf; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(pdf__strip_dir) \
+ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
+ done
+
+rtl.install-html: $(build_htmldir)/rtl
+ @$(NORMAL_INSTALL)
+ test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
+ @for p in $(build_htmldir)/rtl; do \
+ if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
+ f=$(html__strip_dir) \
+ if test -d "$$d$$p"; then \
+ echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+ echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
+ else \
+ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
+ fi; \
+ done
+
+rtl.install-man: $(DESTDIR)$(man1dir)/$(GCCRTL_INSTALL_NAME)$(man1ext)
+
+$(DESTDIR)$(man1dir)/$(GCCRTL_INSTALL_NAME)$(man1ext): doc/gccrtl.1 installdirs
+ -rm -f $@
+ -$(INSTALL_DATA) $< $@
+ -chmod a-x $@
+
+rtl.uninstall:
+ rm -rf $(DESTDIR)$(bindir)/$(GCCRTL_INSTALL_NAME)$(exeext)
+ rm -rf $(DESTDIR)$(man1dir)/$(GCCRTL_INSTALL_NAME)$(man1ext)
+ rm -rf $(DESTDIR)$(bindir)/$(GCCRTL_TARGET_INSTALL_NAME)$(exeext)
+ rm -rf $(DESTDIR)$(infodir)/gccrtl.info*
+
+# Clean hooks.
+
+rtl.mostlyclean:
+ -rm -f rtl/*$(objext)
+ -rm -f rtl/*$(coverageexts)
+ -rm -f gccrtl$(exeext) gccrtl-cross$(exeext) rtl1$(exeext)
+rtl.clean:
+rtl.distclean:
+rtl.maintainer-clean:
+ -rm -f $(docobjdir)/gccrtl.1
+
+# Stage hooks.
+
+rtl.stage1: stage1-start
+ -mv rtl/*$(objext) stage1/rtl
+rtl.stage2: stage2-start
+ -mv rtl/*$(objext) stage2/rtl
+rtl.stage3: stage3-start
+ -mv rtl/*$(objext) stage3/rtl
+rtl.stage4: stage4-start
+ -mv rtl/*$(objext) stage4/rtl
+rtl.stageprofile: stageprofile-start
+ -mv rtl/*$(objext) stageprofile/rtl
+rtl.stagefeedback: stagefeedback-start
+ -mv rtl/*$(objext) stagefeedback/rtl
+
+CFLAGS-rtl/rtl-lang.o += -DDEFAULT_TARGET_VERSION=\"$(version)\" \
+ -DDEFAULT_TARGET_MACHINE=\"$(target_noncanonical)\"
+
+RTLINCLUDES = -I $(srcdir)/rtl -I $(srcdir)/rtl/rtlfrontend
+
+CFLAGS-rtl/rtl-gcc.o += $(RTLINCLUDES)
+CFLAGS-rtl/rtl-linemap.o += $(RTLINCLUDES)
+
+rtl/%.o: rtl/rtlfrontend/%.c
+ $(COMPILE) $(RTLINCLUDES) $<
+ $(POSTCOMPILE)
new file mode 100644
@@ -0,0 +1,36 @@
+# config-lang.in -- Top level configure fragment for RTL frontend.
+
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This file is part of GCC.
+
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language - name of language as it would appear in $(LANGUAGES)
+# compilers - value to add to $(COMPILERS)
+
+language="rtl"
+
+compilers="rtl1\$(exeext)"
+
+target_libs=""
+
+gtfiles="\$(srcdir)/rtl/rtl-frontend.c"
+
+# Do not build by default.
+build_by_default="no"
new file mode 100644
@@ -0,0 +1,25 @@
+/* lang-specs.h -- gcc driver specs for RTL frontend.
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* This is the contribution to the `default_compilers' array in gcc.c
+ for the RTL frontend. */
+
+{".rtl", "@RTL", 0, 1, 0},
+{"@RTL", "rtl1 %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}",
+ 0, 1, 0},
new file mode 100644
@@ -0,0 +1,38 @@
+; lang.opt -- Options for the gcc RTL front end.
+
+; Copyright (C) 2016 Free Software Foundation, Inc.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3. If not see
+; <http://www.gnu.org/licenses/>.
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Language
+RTL
+
+froundtrip=
+RTL Joined RejectNegative
+After loading the RTL input file, immediately dump it to the given path,
+for sanity-checking the loader.
+
+fsingle-pass=
+RTL Joined RejectNegative
+After loading the RTL input file, run the specified pass on it.
+
+
+; This comment is to ensure we retain the blank line above.
new file mode 100644
@@ -0,0 +1,201 @@
+RTL frontend
+============
+
+Purpose
+-------
+
+Historically GCC testing has been done by providing source files
+to be built with various command-line options (via DejaGnu
+directives), dumping state at pertinent places, and verifying
+properties of the state via these dumps.
+
+A strength of this approach is that we have excellent integration
+testing, as every test case exercises the toolchain as a whole, but
+it has the drawback that when testing a specific pass,
+we have little control of the input to that specific pass. We
+provide input, and the various passes transform the state
+of the internal representation::
+
+ INPUT -> PASS-1 -> STATE-1 -> PASS-2 -> STATE-2 -> ...
+ -> etc ->
+ -> ... -> PASS-n-1 -> STATE-n-1 -> PASS-n -> STATE-n
+ ^ ^ ^
+ | | Output from the pass
+ | The pass we care about
+ The actual input to the pass
+
+so the intervening passes before "PASS-n" could make changes to the
+IR that affect the input seen by our pass ("STATE-n-1" above). This
+can break our test cases, sometimes in a form that's visible,
+sometimes invisibly (e.g. where a test case silently stops providing
+coverage).
+
+The aim of the RTL frontend is to provide a convenient way to test
+individual passes in the backend, by loading dumps of specific RTL
+state (possibly edited by hand), and then running just one specific
+pass on them, so that we effectively have this::
+
+ INPUT -> PASS-n -> OUTPUT
+
+thus fixing the problem above.
+
+My hope is that this makes it easy to write more fine-grained and
+robust test coverage for the RTL phase of GCC. However I see this
+as *complementary* to the existing "integrated testing" approach:
+patches should include both RTL frontend tests *and* integrated tests,
+to avoid regressing the great integration testing we currently have.
+
+The idea is to use the existing dump format as a input format, since
+presumably existing GCC developers are very familiar with the dump
+format.
+
+One other potential benefit of this approach is to allow unit-testing
+of machine descriptions - we could provide specific RTL fragments,
+and have the rtl.dg testsuite directly verify that we recognize all
+instructions and addressing modes that a given target ought to support.
+
+Structure
+---------
+
+The RTL frontend is similar to a regular frontend: a ``gcc/rtl``
+subdirectory within the source tree contains frontend-specific hooks.
+These provide a new ``rtl`` frontend, which can be optionally
+enabled at configuration time within ``--enable-languages``.
+
+If enabled, it builds an ``rtl1`` binary, which is invoked by the
+``gcc`` driver on files with a ``.rtl`` extension.
+
+The testsuite is below ``gcc/testsuite/rtl.dg``. There's also
+a ``roundtrip`` subdirectory below this, in which every ``.rtl``
+file is loaded and then dumped; ``roundtrip.exp`` verifies that
+the dump is identical to the original file, thus ensuring that
+the RTL loaders faithfully rebuild the input dump.
+
+Limitations
+-----------
+
+* It's a work-in-progress. There will be bugs.
+
+* The existing RTL code is structured around a single function being
+ optimized, so, as a simplification, the RTL frontend can only handle
+ one function per input file. Also, the dump format currently uses
+ comments to separate functions::
+
+ ;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+ ... various pass-specific things, sometimes expressed as comments,
+ sometimes not
+
+ ;;
+ ;; Full RTL generated for this function:
+ ;;
+ (note 1 0 6 NOTE_INSN_DELETED)
+ ;; etc, insns for function "test_1" go here
+ (insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+ (nil))
+
+ ;; Function test_2 (test_2, funcdef_no=1, decl_uid=1765, cgraph_uid=1, symbol_order=1)
+ ... various pass-specific things, sometimes expressed as comments,
+ sometimes not
+ ;;
+ ;; Full RTL generated for this function:
+ ;;
+ (note 1 0 5 NOTE_INSN_DELETED)
+ ;; etc, insns for function "test_2" go here
+ (insn 59 58 0 8 (use (reg/i:SF 21 xmm0)) ../../src/gcc/testsuite/rtl.dg/test.c:31 -1
+ (nil))
+
+ so that there's no clear separation of the instructions between the
+ two functions (and no metadata e.g. function names).
+
+ This could be fixed by adding a new clause to the dump e.g.::
+
+ (function "test_1" [
+ (note 1 0 6 NOTE_INSN_DELETED)
+ ;; etc, insns for function "test_1" go here
+ (insn 27 26 0 6 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+ (nil))
+ ])
+
+ (function "test_2" [
+ (note 1 0 5 NOTE_INSN_DELETED)
+ ;; etc, insns for function "test_2" go here
+ (insn 59 58 0 8 (use (reg/i:SF 21 xmm0)) ../../src/gcc/testsuite/rtl.dg/test.c:31 -1
+ (nil))
+ ])
+
+ or somesuch (this wouldn't be an rtx code, just something in rtl-frontend.c).
+ The RTL frontend could then compile each function in turn after parsing each
+ one (probably the easiest way to deal with the global state in the RTL parts
+ of the compiler).
+
+* The RTL frontend doesn't have any knowledge of the name of the function,
+ of parameters, types, locals, globals, etc. It creates a single function.
+ The function is currently hardcoded to have this signature:
+
+ int test_1 (int, int, int);
+
+ since there's no syntax for specify otherwise, and we need to provide
+ a ``FUNCTION_DECL`` tree when building a function object (by calling
+ ``allocate_struct_function``).
+
+* Similarly, there are no types beyond the built-in ones; all expressions
+ are treated as being of type ``int``. I suspect that this approach
+ will be too simplistic when it comes to e.g. aliasing.
+
+* There's no support for running more than one pass; fixing this would
+ require being able to run passes from a certain point onwards.
+
+* Roundtripping of recognized instructions may be an issue (i.e. those
+ with ``INSN_CODE`` != -1), such as the ``667 {jump}`` in the following::
+
+ (jump_insn 50 49 51 10
+ (set (pc)
+ (label_ref:DI 59)) ../../src/test-switch.c:18 667 {jump}
+ (nil) -> 59)
+
+ since the integer ID can change when the .md files are changed
+ (and the associated pattern name is very much target-specific).
+ It may be best to reset them to -1 in the input files (and delete the
+ operation name), giving::
+
+ (jump_insn 50 49 51 10
+ (set (pc)
+ (label_ref:DI 59)) ../../src/test-switch.c:18 -1
+ (nil) -> 59)
+
+* Currently there's no explicit CFG edge information in the dumps.
+ The ``rtl1`` frontend reconstructs the edges based on jump instructions.
+ As I understand the `distinction between cfgrtl and cfglayout modes
+ https://gcc.gnu.org/wiki/cfglayout_mode`_ , this is OK for "cfgrtl" mode,
+ but isn't going to work for "cfglayout" mode - in the latter,
+ unconditional jumps are represented purely by edges in the CFG, and this
+ information isn't currently present in the dumps (perhaps we could add it
+ if it's an issue).
+
+Open Questions
+--------------
+
+* Register numbering: consider this fragment of RTL emitted during
+ expansion::
+
+ (reg/f:DI 82 virtual-stack-vars)
+
+ At the time of emission, register 82 is the ``VIRTUAL_STACK_VARS_REGNUM``,
+ and this value is effectively hardcoded into the dump. Presumably this
+ is baking in assumptions about the target into the test. Also, how likely is
+ this value to change? When we reload the dump, should we notice that this
+ is tagged with ``virtual-stack-vars`` and override the specific register
+ number to use the current value of ``VIRTUAL_STACK_VARS_REGNUM`` on the
+ target ``rtl1`` was built for?
+
+TODO items
+----------
+
+* test with other architectures
+
+* roundtrip.exp: strip out comments in source when comparing roundtrip
+
+* example with "-g"
+
+* implement a fuzzer (or use AFL on the existing test cases)
new file mode 100644
@@ -0,0 +1,35 @@
+/* rtl-error.c - Replacement for errors.c for use by RTL frontend
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "errors.h"
+
+/* FIXME. */
+
+void
+fatal (const char *, ...)
+{
+ // TODO
+ abort ();
+}
+
+int have_error;
+
new file mode 100644
@@ -0,0 +1,1219 @@
+/* rtl-frontend.c - Top-level of RTL frontend
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "stor-layout.h"
+#include "debug.h"
+#include "convert.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "common/common-target.h"
+#include "read-md.h"
+#include <mpfr.h>
+#include "rtl.h"
+#include "cfghooks.h"
+#include "stringpool.h"
+#include "function.h"
+#include "tree-cfg.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "cfgrtl.h"
+#include "deferred-locations.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "context.h"
+#include "pass_manager.h"
+#include "toplev.h"
+#include "bitmap.h"
+#include "df.h"
+#include "regs.h"
+#include "varasm.h"
+#include "insn-addr.h"
+
+/* Language-dependent contents of a type. */
+
+struct GTY(()) lang_type
+{
+ char dummy;
+};
+
+/* Language-dependent contents of a decl. */
+
+struct GTY(()) lang_decl
+{
+ char dummy;
+};
+
+/* Language-dependent contents of an identifier. This must include a
+ tree_identifier. */
+
+struct GTY(()) lang_identifier
+{
+ struct tree_identifier common;
+};
+
+/* The resulting tree type. */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+ chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+ union tree_node GTY((tag ("0"),
+ desc ("tree_node_structure (&%h)"))) generic;
+ struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function. */
+
+struct GTY(()) language_function
+{
+ int dummy;
+};
+
+/* Language hooks. */
+
+/* Implementation of LANG_HOOKS_INIT for the RTL frontend. */
+
+static bool
+rtl_langhook_init (void)
+{
+ in_rtl_frontend_p = true;
+
+ build_common_tree_nodes (false);
+
+ /* I don't know why this has to be done explicitly. */
+ void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+ build_common_builtin_nodes ();
+
+ /* The default precision for floating point numbers. This is used
+ for floating point constants with abstract type. This may
+ eventually be controllable by a command line option. */
+ mpfr_set_default_prec (256);
+
+ return true;
+}
+
+/* Implementation of LANG_HOOKS_OPTION_LANG_MASK for the RTL frontend. */
+
+static unsigned int
+rtl_langhook_option_lang_mask (void)
+{
+ return CL_RTL;
+}
+
+/* The value of "-froundtrip=", if any. */
+
+static const char *roundtrip_filename = NULL;
+
+/* The value of "-fsingle-pass=", if any. */
+
+static const char *single_pass_name = NULL;
+
+/* Implementation of LANG_HOOKS_HANDLE_OPTION for the RTL frontend. */
+
+static bool
+rtl_langhook_handle_option (
+ size_t scode,
+ const char *arg,
+ int value ATTRIBUTE_UNUSED,
+ int kind ATTRIBUTE_UNUSED,
+ location_t loc ATTRIBUTE_UNUSED,
+ const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
+ enum opt_code code = (enum opt_code) scode;
+
+ switch (code)
+ {
+ case OPT_froundtrip_:
+ roundtrip_filename = xstrdup (arg);
+ break;
+
+ case OPT_fsingle_pass_:
+ single_pass_name = xstrdup (arg);
+ break;
+
+ default:
+ break;
+ }
+ return true;
+}
+
+class function_reader;
+
+/* Abstract base class for recording post-processing steps that must be
+ done after reading a .rtl file. */
+
+class fixup
+{
+ public:
+ fixup (file_location loc, rtx x)
+ : m_loc (loc), m_rtx (x)
+ {}
+ virtual ~fixup () {}
+
+ virtual void apply (function_reader *reader) const = 0;
+
+ protected:
+ file_location m_loc;
+ rtx m_rtx;
+};
+
+/* An abstract subclass of fixup for post-processing steps that
+ act on a specific operand of a specific instruction. */
+
+class operand_fixup : public fixup
+{
+ public:
+ operand_fixup (file_location loc, rtx insn, int operand_idx)
+ : fixup (loc, insn), m_operand_idx (operand_idx)
+ {}
+
+ protected:
+ int m_operand_idx;
+};
+
+/* A concrete subclass of operand_fixup: fixup an rtx_insn *
+ field (NEXT_INSN/PREV_INSN) based on an integer UID. */
+
+class fixup_insn_uid : public operand_fixup
+{
+ public:
+ fixup_insn_uid (file_location loc, rtx insn, int operand_idx, int insn_uid)
+ : operand_fixup (loc, insn, operand_idx),
+ m_insn_uid (insn_uid)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ int m_insn_uid;
+};
+
+/* A concrete subclass of operand_fixup: fix up a basic_block
+ pointer field based on an integer block ID. */
+
+class fixup_bb : public operand_fixup
+{
+ public:
+ fixup_bb (file_location loc, rtx insn, int operand_idx, int bb_idx)
+ : operand_fixup (loc, insn, operand_idx),
+ m_bb_idx (bb_idx)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ int m_bb_idx;
+};
+
+/* A concrete subclass of operand_fixup: fix up a
+ NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
+
+class fixup_note_insn_basic_block : public operand_fixup
+{
+ public:
+ fixup_note_insn_basic_block (file_location loc, rtx insn, int operand_idx,
+ int bb_idx)
+ : operand_fixup (loc, insn, operand_idx),
+ m_bb_idx (bb_idx)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ int m_bb_idx;
+};
+
+/* A concrete subclass of operand_fixup: fix up the INSN_LOCATION
+ of the insn based on a deferred_location *. */
+
+class fixup_source_location : public operand_fixup
+{
+ public:
+ fixup_source_location (file_location loc, rtx insn,
+ int operand_idx,
+ deferred_location *dloc)
+ : operand_fixup (loc, insn, operand_idx),
+ m_dloc (dloc)
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ deferred_location *m_dloc;
+};
+
+/* A concrete subclass of operand_fixup: fix up the JUMP_LABEL
+ of an insn based on a label name. */
+
+class fixup_jump_label : public operand_fixup
+{
+ public:
+ fixup_jump_label (file_location loc, rtx insn,
+ int operand_idx,
+ const char *label)
+ : operand_fixup (loc, insn, operand_idx),
+ m_label (xstrdup (label))
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ const char *m_label;
+};
+
+/* A concrete subclass of fixup (not operand_fixup): fix up
+ the expr of an rtx (REG or MEM) based on a textual dump. */
+
+class fixup_expr : public fixup
+{
+ public:
+ fixup_expr (file_location loc, rtx x, const char *desc)
+ : fixup (loc, x),
+ m_desc (xstrdup (desc))
+ {}
+
+ void apply (function_reader *reader) const;
+
+ private:
+ char *m_desc;
+};
+
+/* Subclass of rtx_reader for reading function dumps. */
+
+class function_reader : public rtx_reader
+{
+ public:
+ function_reader ();
+ ~function_reader ();
+
+ void handle_unknown_directive (file_location, const char *);
+
+ void add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+ int insn_uid);
+
+ void add_fixup_bb (file_location loc, rtx insn,
+ int operand_idx, int bb_idx);
+
+ void add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+ int operand_idx, int bb_idx);
+
+ void add_fixup_source_location (file_location loc, rtx insn,
+ int operand_idx,
+ const char *filename, int lineno);
+
+ void add_fixup_jump_label (file_location loc, rtx insn,
+ int operand_idx,
+ const char *label);
+
+ void add_fixup_expr (file_location loc, rtx x,
+ const char *desc);
+
+ void create_function ();
+ void apply_fixups ();
+ void create_cfg_edges ();
+
+ rtx_insn **get_insn_by_uid (int uid);
+
+ rtx_insn *get_first_insn () const { return m_first_insn; }
+
+ tree parse_mem_expr (const char *desc);
+
+ private:
+ void create_cfg_and_basic_blocks ();
+
+ private:
+ struct uid_hash : int_hash <int, -1, -2> {};
+ hash_map<uid_hash, rtx_insn *> m_insns_by_uid;
+ auto_vec<fixup *> m_fixups;
+ bitmap_head m_bb_indices;
+ rtx_insn *m_first_insn;
+ deferred_locations m_deferred_locations;
+ auto_vec<tree> m_fake_scope;
+};
+
+/* Return a textual description of the given operand of the given rtx. */
+
+static const char *
+get_operand_name (rtx insn, int operand_idx)
+{
+ gcc_assert (is_a <rtx_insn *> (insn));
+ switch (operand_idx)
+ {
+ case 0:
+ return "PREV_INSN";
+ case 1:
+ return "NEXT_INSN";
+ default:
+ return NULL;
+ }
+}
+
+/* Fixup an rtx_insn * field (NEXT_INSN/PREV_INSN) based on an integer
+ UID. */
+
+void
+fixup_insn_uid::apply (function_reader *reader) const
+{
+ rtx_insn **insn_from_uid = reader->get_insn_by_uid (m_insn_uid);
+ if (insn_from_uid)
+ XEXP (m_rtx, m_operand_idx) = *insn_from_uid;
+ else
+ {
+ const char *op_name = get_operand_name (m_rtx, m_operand_idx);
+ if (op_name)
+ error_at (m_loc,
+ "insn with UID %i not found for operand %i (`%s') of insn %i",
+ m_insn_uid, m_operand_idx, op_name, INSN_UID (m_rtx));
+ else
+ error_at (m_loc,
+ "insn with UID %i not found for operand %i of insn %i",
+ m_insn_uid, m_operand_idx, INSN_UID (m_rtx));
+ }
+}
+
+/* Fix up a basic_block pointer field based on an integer block ID.
+ Update BB_HEAD and BB_END of the block as appropriate, as if the insn
+ was being added to the end of the block. */
+
+void
+fixup_bb::apply (function_reader */*reader*/) const
+{
+ basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+ gcc_assert (bb);
+ XBBDEF (m_rtx, m_operand_idx) = bb;
+
+ rtx_insn *insn = as_a <rtx_insn *> (m_rtx);
+ if (!BB_HEAD (bb))
+ BB_HEAD (bb) = insn;
+ BB_END (bb) = insn;
+}
+
+/* Fix up a NOTE_INSN_BASIC_BLOCK based on an integer block ID. */
+
+void
+fixup_note_insn_basic_block::apply (function_reader */*reader*/) const
+{
+ basic_block bb = BASIC_BLOCK_FOR_FN (cfun, m_bb_idx);
+ gcc_assert (bb);
+ NOTE_BASIC_BLOCK (m_rtx) = bb;
+}
+
+/* Fix up the INSN_LOCATION of the insn based on a deferred_location *. */
+
+void
+fixup_source_location::apply (function_reader */*reader*/) const
+{
+ INSN_LOCATION (as_a <rtx_insn *> (m_rtx)) = m_dloc->m_srcloc;
+}
+
+/* Fix up the JUMP_LABEL of an insn based on a label name. */
+
+void
+fixup_jump_label::apply (function_reader *reader) const
+{
+ if (0 == strcmp (m_label, "return"))
+ JUMP_LABEL (m_rtx) = ret_rtx;
+ else if (0 == strcmp (m_label, "simple_return"))
+ JUMP_LABEL (m_rtx) = simple_return_rtx;
+ else
+ {
+ int label_uid = atoi (m_label);
+ rtx_insn **insn_from_uid = reader->get_insn_by_uid (label_uid);
+ if (insn_from_uid)
+ JUMP_LABEL (m_rtx) = *insn_from_uid;
+ else
+ error_at (m_loc,
+ "insn with UID %i not found for operand %i (`%s') of insn %i",
+ label_uid, m_operand_idx, "JUMP_LABEL", INSN_UID (m_rtx));
+ }
+}
+
+/* Parse a tree dump for MEM_EXPR and turn it back into a tree.
+ We handle "<retval>", but for anything else we "cheat" by building a
+ global VAR_DECL of type "int" with that name (returning the same global
+ for a name if we see the same name more than once). */
+
+tree
+function_reader::parse_mem_expr (const char *desc)
+{
+ if (0 == strcmp (desc, "<retval>"))
+ {
+ tree fndecl = cfun->decl;
+ return DECL_RESULT (fndecl);
+ }
+
+ /* FIXME: use a hash rather than linear search. */
+ int i;
+ tree t;
+ FOR_EACH_VEC_ELT (m_fake_scope, i, t)
+ if (0 == strcmp (desc, IDENTIFIER_POINTER (DECL_NAME (t))))
+ return t;
+
+ /* Not found? Create it.
+ This allows mimicing of real data but avoids having to specify
+ e.g. names of locals, params etc.
+ Though this way we don't know if we have a PARM_DECL vs a VAR_DECL,
+ and we don't know the types. Fake it by making everything be
+ a VAR_DECL of "int" type. */
+ t = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (desc),
+ integer_type_node);
+ m_fake_scope.safe_push (t);
+ return t;
+}
+
+/* Fix up the expr of an rtx (REG or MEM) based on a textual dump. */
+
+void
+fixup_expr::apply (function_reader *reader) const
+{
+ tree expr = reader->parse_mem_expr (m_desc);
+ switch (GET_CODE (m_rtx))
+ {
+ case REG:
+ set_reg_attrs_for_decl_rtl (expr, m_rtx);
+ break;
+ case MEM:
+ set_mem_expr (m_rtx, expr);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* class function_reader : public rtx_reader */
+
+/* function_reader's constructor. */
+
+function_reader::function_reader () : rtx_reader (),
+ m_first_insn (NULL)
+{
+ bitmap_initialize (&m_bb_indices, NULL);
+ bitmap_set_bit (&m_bb_indices, ENTRY_BLOCK);
+ bitmap_set_bit (&m_bb_indices, EXIT_BLOCK);
+}
+
+/* function_reader's destructor. */
+
+function_reader::~function_reader ()
+{
+ int i;
+ fixup *f;
+ FOR_EACH_VEC_ELT (m_fixups, i, f)
+ delete f;
+}
+
+/* Implementation of rtx_reader::handle_unknown_directive.
+ Parse rtx instructions by calling read_rtx_code, calling
+ set_first_insn and set_last_insn as appropriate. */
+
+void
+function_reader::handle_unknown_directive (file_location /*start_loc*/,
+ const char *name)
+{
+ rtx x = read_rtx_code (name);
+ if (!x)
+ return;
+ rtx_insn *insn = as_a <rtx_insn *> (x);
+ set_last_insn (insn);
+ if (!m_first_insn)
+ {
+ m_first_insn = insn;
+ set_first_insn (insn);
+ }
+ m_insns_by_uid.put (INSN_UID (insn), insn);
+}
+
+/* Implementation of rtx_reader::add_fixup_insn_uid.
+ Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_insn_uid (file_location loc, rtx insn, int operand_idx,
+ int insn_uid)
+{
+ m_fixups.safe_push (new fixup_insn_uid (loc, insn, operand_idx, insn_uid));
+}
+
+/* Implementation of rtx_reader::add_fixup_bb.
+ Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_bb (file_location loc, rtx insn, int operand_idx,
+ int bb_idx)
+{
+ bitmap_set_bit (&m_bb_indices, bb_idx);
+ m_fixups.safe_push (new fixup_bb (loc, insn, operand_idx, bb_idx));
+}
+
+/* Implementation of rtx_reader::add_fixup_note_insn_basic_block.
+ Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_note_insn_basic_block (file_location loc, rtx insn,
+ int operand_idx, int bb_idx)
+{
+ m_fixups.safe_push (new fixup_note_insn_basic_block (loc, insn, operand_idx,
+ bb_idx));
+}
+
+/* Implementation of rtx_reader::add_fixup_source_location.
+ Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_source_location (file_location loc, rtx insn,
+ int operand_idx,
+ const char *filename, int lineno)
+{
+ source_file *file = m_deferred_locations.get_source_file (filename);
+ source_line *line = file->get_source_line (lineno);
+ deferred_location *dloc = line->get_location (NULL, 0);
+ m_fixups.safe_push (new fixup_source_location (loc, insn, operand_idx, dloc));
+}
+
+/* Implementation of rtx_reader::add_fixup_jump_label.
+ Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_jump_label (file_location loc, rtx insn,
+ int operand_idx,
+ const char *label)
+{
+ m_fixups.safe_push (new fixup_jump_label (loc, insn, operand_idx, label));
+}
+
+/* Implementation of rtx_reader::add_fixup_expr.
+ Record the information for later post-processing. */
+
+void
+function_reader::add_fixup_expr (file_location loc, rtx insn,
+ const char *desc)
+{
+ gcc_assert (desc);
+ /* Fail early if the RTL reader erroneously hands us an int. */
+ gcc_assert (!ISDIGIT (desc[0]));
+
+ m_fixups.safe_push (new fixup_expr (loc, insn, desc));
+}
+
+/* Set up state for the function *before* fixups are applied.
+
+ Create "cfun" and a decl for the function.
+ For the moment, every function decl is hardcoded as
+ int test_1 (int i, int j, int k);
+ Set up various other state:
+ - state set up by expand_function_start (e.g. crtl->return_rtx).
+ - the cfg and basic blocks (edges are created later, *after* fixups
+ are applied).
+ - add the function to the callgraph. */
+
+void
+function_reader::create_function ()
+{
+ /* Currently we assume cfgrtl mode, rather than cfglayout mode. */
+ if (0)
+ cfg_layout_rtl_register_cfg_hooks ();
+ else
+ rtl_register_cfg_hooks ();
+
+ /* Create cfun. */
+ tree fn_name = get_identifier ("test_1");
+ tree int_type = integer_type_node;
+ tree return_type = int_type;
+ tree arg_types[3] = {int_type, int_type, int_type};
+ tree fn_type = build_function_type_array (return_type, 3, arg_types);
+ tree fndecl = build_decl_stat (UNKNOWN_LOCATION, FUNCTION_DECL, fn_name,
+ fn_type);
+ tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
+ return_type);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_RESULT (fndecl) = resdecl;
+ allocate_struct_function (fndecl, false);
+ /* This sets cfun. */
+
+ /* Normally, various state gets set up by expand_function_start, e.g.
+ crtl->return_rtx, based on DECL_RESULT (fndecl).
+ We call it here to ensure the state is set up, with emit_insns as
+ false, so no new instructions are emitted. */
+ current_function_decl = fndecl;
+ expand_function_start (fndecl, false);
+
+ create_cfg_and_basic_blocks ();
+ cfun->curr_properties = (PROP_cfg | PROP_rtl);
+
+ /* Do we need this to force cgraphunit.c to output the function? */
+ DECL_EXTERNAL (fndecl) = 0;
+ DECL_PRESERVE_P (fndecl) = 1;
+
+ /* Add to cgraph. */
+ cgraph_node::add_new_function (fndecl, true /*lowered*/);
+
+ current_function_decl = NULL;
+}
+
+/* Apply all of the recorded fixups. */
+
+void
+function_reader::apply_fixups ()
+{
+ m_deferred_locations.add_to_line_table ();
+ /* line_table should now be populated; every deferred_location should
+ now have an m_srcloc. */
+
+ int i;
+ fixup *f;
+ FOR_EACH_VEC_ELT (m_fixups, i, f)
+ f->apply (this);
+}
+
+/* Given a UID value, try to locate a pointer to the corresponding
+ rtx_insn *, or NULL if if can't be found. */
+
+rtx_insn **
+function_reader::get_insn_by_uid (int uid)
+{
+ return m_insns_by_uid.get (uid);
+}
+
+/* Create cfun's CFG and populate with blocks, a helper
+ function for function_reader::create_function ().
+
+ The edges are created later on, after fixups are applied.
+
+ We can't call create_basic_block and use the regular RTL block-creation
+ hooks, since this creates NOTE_INSN_BASIC_BLOCK instances. We don't
+ want to do that; we want to use the notes we were provided with.
+
+ The term "index" has two meanings for basic blocks in a CFG:
+ (a) the "index" field within struct basic_block_def.
+ (b) the index of a basic_block within the cfg's x_basic_block_info
+ vector, as accessed via BASIC_BLOCK_FOR_FN.
+
+ These can get out-of-sync when basic blocks are optimized away.
+ They get back in sync by "compact_blocks".
+ We make the assumption that the CFG has been compacted, and
+ so we reconstruct cfun->cfg->x_basic_block_info->m_vecdata with NULL
+ values in it for any missing basic blocks, so that (a) == (b) for
+ all of the blocks we create. The doubly-linked list of basic
+ blocks (next_bb/prev_bb) skips over these "holes". */
+
+void
+function_reader::create_cfg_and_basic_blocks ()
+{
+ /* Create bare-bones cfg. This creates the entry and exit blocks. */
+ init_empty_tree_cfg_for_function (cfun);
+
+ /* Ensure that the vector of basic_block pointers is big enough. */
+ unsigned highest_bb_idx = bitmap_last_set_bit (&m_bb_indices);
+ size_t new_size = highest_bb_idx + 1;
+ if (basic_block_info_for_fn (cfun)->length () < new_size)
+ vec_safe_grow_cleared (basic_block_info_for_fn (cfun), new_size);
+
+ /* Populate the vector. */
+ unsigned bb_idx;
+ bitmap_iterator bi;
+ basic_block after = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ gcc_assert (after);
+ EXECUTE_IF_SET_IN_BITMAP (&m_bb_indices, 0, bb_idx, bi)
+ {
+ /* The entry and exit blocks were already created above. */
+ if (bb_idx == ENTRY_BLOCK || bb_idx == EXIT_BLOCK)
+ {
+ basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_idx);
+ init_rtl_bb_info (bb);
+ continue;
+ }
+ basic_block bb = alloc_block ();
+ init_rtl_bb_info (bb);
+ bb->index = bb_idx;
+ bb->flags = BB_NEW | BB_RTL;
+ link_block (bb, after);
+
+ n_basic_blocks_for_fn (cfun)++;
+ SET_BASIC_BLOCK_FOR_FN (cfun, bb_idx, bb);
+ BB_SET_PARTITION (bb, BB_UNPARTITIONED);
+
+ /* Tag the block so that we know it has been used when considering
+ other basic block notes. */
+ bb->aux = bb;
+
+ after = bb;
+ }
+
+ last_basic_block_for_fn (cfun) = highest_bb_idx + 1;
+}
+
+/* Visit every LABEL_REF within JUMP_INSN, calling CB on it, providing it
+ with USER_DATA.
+ FIXME: is there a preexisting way to do this? */
+
+static void
+for_each_label_ref (rtx_jump_insn *jump_insn,
+ void (*cb) (rtx_jump_insn *jump_insn,
+ rtx label_ref,
+ void *user_data),
+ void *user_data)
+{
+ if (any_condjump_p (jump_insn))
+ {
+ rtx label_ref = condjump_label (jump_insn);
+ cb (jump_insn, label_ref, user_data);
+ return;
+ }
+
+ if (simplejump_p (jump_insn))
+ {
+ rtx label_ref = SET_SRC (PATTERN (jump_insn));
+ cb (jump_insn, label_ref, user_data);
+ return;
+ }
+
+ rtx_jump_table_data *tablep;
+ if (tablejump_p (jump_insn, NULL, &tablep))
+ {
+ gcc_assert (tablep);
+ rtvec labels = tablep->get_labels ();
+ int i, veclen = GET_NUM_ELEM (labels);
+ for (i = 0; i < veclen; ++i)
+ {
+ rtx label_ref = RTVEC_ELT (labels, i);
+ cb (jump_insn, label_ref, user_data);
+ }
+ return;
+ }
+
+ if (ANY_RETURN_P (PATTERN (jump_insn)))
+ return;
+
+ /* TODO: something else? */
+ gcc_unreachable ();
+}
+
+/* Create an edge from SRC to DST, with the given flags. */
+
+static void
+add_edge (basic_block src, basic_block dst, int flags)
+{
+ if (0)
+ fprintf (stderr, "making edge %i->%i\n",
+ src->index, dst->index);
+ unchecked_make_edge (src, dst, flags);
+}
+
+/* Edge-creation callback for function_reader::create_cfg_edges. */
+
+static void
+add_edge_cb (rtx_jump_insn *jump_insn, rtx label_ref, void */*user_data*/)
+{
+ gcc_assert (jump_insn);
+ gcc_assert (label_ref);
+ rtx_insn *label_insn = as_a <rtx_insn *> (LABEL_REF_LABEL (label_ref));
+ add_edge (BLOCK_FOR_INSN (jump_insn), BLOCK_FOR_INSN (label_insn), 0);
+}
+
+/* Create edges within cfun's CFG, by examining instructions in the
+ basic blocks and reconstructing the edges accordingly.
+ This is done after fixups are applied, since the latter is responsible
+ for setting up BB_HEAD and BB_END within each basic block.
+
+ This assumes cfgrtl mode, in which the edges are implicit from
+ the jump instructions. It won't work for cfglayout mode, which
+ represents unconditional jumps purely as edges within the CFG,
+ without instructions, and this information isn't (currently)
+ written out to dumps. */
+
+void
+function_reader::create_cfg_edges ()
+{
+ /* Create edge from ENTRY_BLOCK to block of first insn. */
+ basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ add_edge (entry, entry->next_bb, EDGE_FALLTHRU);
+
+ /* Create other edges.
+
+ The edge from the block of last insn to EXIT_BLOCK is created
+ below, by fall-through from the end of its block. */
+ basic_block bb;
+ FOR_ALL_BB_FN (bb, cfun)
+ {
+ if (!BB_HEAD (bb))
+ continue;
+ rtx_insn *end_insn = BB_END (bb);
+ if (rtx_jump_insn *jump_insn = dyn_cast <rtx_jump_insn *> (end_insn))
+ {
+ if (0)
+ fprintf (stderr, "bb %i ends in jump\n", bb->index);
+ if (!any_uncondjump_p (end_insn))
+ {
+ /* Add fallthrough edge first. */
+ gcc_assert (bb->next_bb);
+ add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+ }
+ for_each_label_ref (jump_insn, add_edge_cb, NULL);
+ }
+ else
+ {
+ if (0)
+ fprintf (stderr, "bb %i ends in non-jump\n", bb->index);
+ if (bb->next_bb != NULL)
+ {
+ /* Add fallthrough edge. */
+ gcc_assert (bb->next_bb);
+ add_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+ }
+ }
+ }
+}
+
+/* Locate and run PASS_NAME on cfun. */
+
+static void
+run_one_pass_by_name (const char *pass_name)
+{
+ opt_pass *pass = g->get_passes ()->get_pass_by_name (pass_name);
+ if (!pass)
+ {
+ error_at (UNKNOWN_LOCATION, "unrecognized pass: %qs", pass_name);
+ return;
+ }
+
+ /* Forcibly create the dataflow instance. We'll need to do this on passes
+ that normally occur after pass_df_initialize/pass_df_initialize_no_opt. */
+ /* FIXME: better conditional logic here. */
+ if (0 == strcmp (pass_name, "rtl-ira")
+ || 0 == strcmp (pass_name, "rtl-reload")
+ || 0 == strcmp (pass_name, "rtl-pro_and_epilogue"))
+ {
+ opt_pass *df_pass = g->get_passes ()->get_pass_by_name ("rtl-dfinit");
+ gcc_assert (df_pass);
+ current_function_decl = cfun->decl;
+ df_pass->execute (cfun);
+
+ /* The dataflow instance should now exist. */
+ gcc_assert (df);
+
+ df_analyze ();
+ }
+
+ /* Ensure reg_renumber is set up. */
+ resize_reg_info ();
+
+ max_regno = max_reg_num ();
+
+ /* Pass "reload" sets the global "reload_completed", and many things
+ depend on this (e.g. instructions in .md files). */
+ /* FIXME: better conditional logic here. */
+ if (0 == strcmp (pass_name, "rtl-final"))
+ reload_completed = 1;
+
+ /* The INSN_ADDRESSES vec is normally set up by shorten_branches; we must
+ manually set it up for passes that run after this. */
+ /* FIXME: better conditional logic here. */
+ if (0 == strcmp (pass_name, "rtl-final"))
+ INSN_ADDRESSES_ALLOC (get_max_uid ());
+
+ /* Run the user-specified pass. */
+ bitmap_obstack_initialize (NULL);
+ bitmap_obstack_initialize (®_obstack);
+ pass_init_dump_file (pass);
+ current_function_decl = cfun->decl;
+ pass->execute (cfun);
+ current_function_decl = NULL;
+ if (dump_file)
+ print_rtl_with_bb (dump_file, get_insns (), dump_flags);
+ pass_fini_dump_file (pass);
+ bitmap_obstack_release (®_obstack);
+}
+
+/* Implementation of LANG_HOOKS_PARSE_FILE for the RTL frontend. */
+
+static void
+rtl_langhook_parse_file (void)
+{
+ in_rtl_frontend_p = true;
+
+ initialize_rtl ();
+ init_emit ();
+ init_varasm_status ();
+
+ auto_vec<const char *> argv (num_in_fnames + 1);
+ argv.safe_push (progname);
+ for (unsigned i = 0; i < num_in_fnames; i++)
+ argv.safe_push (in_fnames[i]);
+ function_reader reader;
+ if (!reader.read_md_files (argv.length (), argv.address (), NULL))
+ return;
+
+ reader.create_function ();
+ reader.apply_fixups ();
+ reader.create_cfg_edges ();
+
+ /* Ensure x_cur_insn_uid is 1 more than the biggest insn UID seen.
+ This is normally updated by the various make_*insn_raw functions. */
+ {
+ rtx_insn *insn;
+ int max_uid = 0;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ max_uid = MAX (max_uid, INSN_UID (insn));
+ crtl->emit.x_cur_insn_uid = max_uid + 1;
+ }
+
+ crtl->init_stack_alignment ();
+
+ /* If -froundtrip=FILENAME was provided, immediately dump the
+ result, so that the testsuite can compare it against the
+ input dump. */
+ if (roundtrip_filename)
+ {
+ FILE *out = fopen (roundtrip_filename, "w");
+ if (out)
+ {
+ print_rtl_with_bb (out, reader.get_first_insn (), 1024);
+ fclose (out);
+ }
+ else
+ error_at (UNKNOWN_LOCATION, "unable to open %qs for -froundtrip",
+ roundtrip_filename);
+ }
+
+/* If -fsingle-pass=PASS_NAME was provided, locate and run PASS_NAME
+ on cfun, as created above. */
+ if (single_pass_name)
+ run_one_pass_by_name (single_pass_name);
+}
+
+/* Implementation of LANG_HOOKS_TYPE_FOR_SIZE, taken from Go frontend. */
+
+static tree
+rtl_langhook_type_for_size (unsigned int bits, int unsignedp)
+{
+ tree type;
+ if (unsignedp)
+ {
+ if (bits == INT_TYPE_SIZE)
+ type = unsigned_type_node;
+ else if (bits == CHAR_TYPE_SIZE)
+ type = unsigned_char_type_node;
+ else if (bits == SHORT_TYPE_SIZE)
+ type = short_unsigned_type_node;
+ else if (bits == LONG_TYPE_SIZE)
+ type = long_unsigned_type_node;
+ else if (bits == LONG_LONG_TYPE_SIZE)
+ type = long_long_unsigned_type_node;
+ else
+ type = make_unsigned_type(bits);
+ }
+ else
+ {
+ if (bits == INT_TYPE_SIZE)
+ type = integer_type_node;
+ else if (bits == CHAR_TYPE_SIZE)
+ type = signed_char_type_node;
+ else if (bits == SHORT_TYPE_SIZE)
+ type = short_integer_type_node;
+ else if (bits == LONG_TYPE_SIZE)
+ type = long_integer_type_node;
+ else if (bits == LONG_LONG_TYPE_SIZE)
+ type = long_long_integer_type_node;
+ else
+ type = make_signed_type(bits);
+ }
+ return type;
+}
+
+/* Implementation of LANG_HOOKS_TYPE_FOR_MODE, taken from Go frontend. */
+
+static tree
+rtl_langhook_type_for_mode (machine_mode mode, int unsignedp)
+{
+ tree type;
+ /* Go has no vector types. Build them here. FIXME: It does not
+ make sense for the middle-end to ask the frontend for a type
+ which the frontend does not support. However, at least for now
+ it is required. See PR 46805. */
+ if (VECTOR_MODE_P (mode))
+ {
+ tree inner;
+
+ inner = rtl_langhook_type_for_mode (GET_MODE_INNER (mode), unsignedp);
+ if (inner != NULL_TREE)
+ return build_vector_type_for_mode (inner, mode);
+ return NULL_TREE;
+ }
+
+ // FIXME: This static_cast should be in machmode.h.
+ enum mode_class mc = static_cast<enum mode_class>(GET_MODE_CLASS(mode));
+ if (mc == MODE_INT)
+ return rtl_langhook_type_for_size(GET_MODE_BITSIZE(mode), unsignedp);
+ else if (mc == MODE_FLOAT)
+ {
+ switch (GET_MODE_BITSIZE (mode))
+ {
+ case 32:
+ return float_type_node;
+ case 64:
+ return double_type_node;
+ default:
+ // We have to check for long double in order to support
+ // i386 excess precision.
+ if (mode == TYPE_MODE(long_double_type_node))
+ return long_double_type_node;
+ }
+ }
+ else if (mc == MODE_COMPLEX_FLOAT)
+ {
+ switch (GET_MODE_BITSIZE (mode))
+ {
+ case 64:
+ return complex_float_type_node;
+ case 128:
+ return complex_double_type_node;
+ default:
+ // We have to check for long double in order to support
+ // i386 excess precision.
+ if (mode == TYPE_MODE(complex_long_double_type_node))
+ return complex_long_double_type_node;
+ }
+ }
+
+#if HOST_BITS_PER_WIDE_INT >= 64
+ /* The middle-end and some backends rely on TImode being supported
+ for 64-bit HWI. */
+ if (mode == TImode)
+ {
+ type = build_nonstandard_integer_type (GET_MODE_BITSIZE (TImode),
+ unsignedp);
+ if (type && TYPE_MODE (type) == TImode)
+ return type;
+ }
+#endif
+ return NULL_TREE;
+}
+
+/* Implementation of LANG_HOOKS_BUILTIN_FUNCTION. */
+
+static tree
+rtl_langhook_builtin_function (tree decl)
+{
+ return decl;
+}
+
+/* Implementation of LANG_HOOKS_GLOBAL_BINDINGS_P.
+ Return true if we are in the global binding level. */
+
+static bool
+rtl_langhook_global_bindings_p (void)
+{
+ return current_function_decl == NULL_TREE;
+}
+
+/* Implementation of LANG_HOOKS_PUSHDECL. */
+
+static tree
+rtl_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+ gcc_unreachable ();
+}
+
+/* Implementation of LANG_HOOKS_GETDECLS. */
+
+static tree
+rtl_langhook_getdecls (void)
+{
+ return NULL;
+}
+
+/* Functions called directly by the generic backend. */
+
+/* Implementation of "convert" taken from the Go frontend. */
+
+tree
+convert (tree type, tree expr)
+{
+ if (type == error_mark_node
+ || expr == error_mark_node
+ || TREE_TYPE (expr) == error_mark_node)
+ return error_mark_node;
+
+ if (type == TREE_TYPE (expr))
+ return expr;
+
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
+ return fold_convert (type, expr);
+
+ switch (TREE_CODE (type))
+ {
+ case VOID_TYPE:
+ case BOOLEAN_TYPE:
+ return fold_convert (type, expr);
+ case INTEGER_TYPE:
+ return fold (convert_to_integer (type, expr));
+ case POINTER_TYPE:
+ return fold (convert_to_pointer (type, expr));
+ case REAL_TYPE:
+ return fold (convert_to_real (type, expr));
+ case COMPLEX_TYPE:
+ return fold (convert_to_complex (type, expr));
+ default:
+ break;
+ }
+
+ gcc_unreachable ();
+}
+
+#undef LANG_HOOKS_NAME
+#undef LANG_HOOKS_INIT
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#undef LANG_HOOKS_HANDLE_OPTION
+#undef LANG_HOOKS_PARSE_FILE
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#undef LANG_HOOKS_PUSHDECL
+#undef LANG_HOOKS_GETDECLS
+
+#define LANG_HOOKS_NAME "GCC RTL frontend"
+#define LANG_HOOKS_INIT rtl_langhook_init
+#define LANG_HOOKS_OPTION_LANG_MASK rtl_langhook_option_lang_mask
+#define LANG_HOOKS_HANDLE_OPTION rtl_langhook_handle_option
+#define LANG_HOOKS_PARSE_FILE rtl_langhook_parse_file
+#define LANG_HOOKS_TYPE_FOR_MODE rtl_langhook_type_for_mode
+#define LANG_HOOKS_TYPE_FOR_SIZE rtl_langhook_type_for_size
+#define LANG_HOOKS_BUILTIN_FUNCTION rtl_langhook_builtin_function
+#define LANG_HOOKS_GLOBAL_BINDINGS_P rtl_langhook_global_bindings_p
+#define LANG_HOOKS_PUSHDECL rtl_langhook_pushdecl
+#define LANG_HOOKS_GETDECLS rtl_langhook_getdecls
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-rtl-rtl-frontend.h"
+#include "gtype-rtl.h"
new file mode 100644
@@ -0,0 +1,64 @@
+# Copyright (C) 1997, 1999, 2000, 2003, 2007 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Define rtl callbacks for dg.exp.
+
+# Load support procs.
+load_lib gcc-defs.exp
+
+proc rtl_target_compile { source dest type options } {
+ set result [target_compile $source $dest $type $options]
+ return $result
+}
+
+load_lib gcc-dg.exp
+
+proc rtl-dg-test { prog do_what extra_tool_flags } {
+ verbose "rtl-dg-test (rtl-dg.exp):" 3
+ verbose " prog: $prog" 3
+ verbose " do_what: $do_what" 3
+ verbose " extra_tool_flags: $extra_tool_flags" 3
+
+ return [gcc-dg-test-1 rtl_target_compile $prog $do_what $extra_tool_flags]
+}
+
+
+proc rtl-dg-prune { system text } {
+ return [gcc-dg-prune $system $text]
+}
+
+# Modified dg-runtest that runs tests in both C++98 and C++11 modes
+# unless they specifically specify one or the other.
+proc rtl-dg-runtest { testcases default-extra-flags } {
+ global runtests
+
+ foreach test $testcases {
+ # look if this is dg-do-run test, in which case
+ # we cycle through the option list, otherwise we don't
+ if [expr [search_for $test "dg-do run"]] {
+ set option_list $TORTURE_OPTIONS
+ } else {
+ set option_list [list { -O } ]
+ }
+
+ set nshort [file tail [file dirname $test]]/[file tail $test]
+
+ foreach flags $option_list {
+ verbose "Testing $nshort, $flags" 1
+ dg-test $test $flags ${default-extra-flags}
+ }
+ }
+}
new file mode 100644
@@ -0,0 +1,90 @@
+/* { dg-options "-fsingle-pass=rtl-dfinit -fdump-rtl-dfinit" } */
+
+/* Lightly-modified dump of test.c.247r.split1. */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 3 (set (reg:SI 90)
+ (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+ (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil))
+(insn 13 12 29 3 (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 20 frame)
+ (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+ (const_int 4 [0x4]))
+ (nil)))
+(jump_insn 29 13 30 3 (set (pc)
+ (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil)
+ -> 20)
+(barrier 30 29 16)
+(code_label 16 30 17 4 2 (nil) [1 uses])
+(note 17 16 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 4 (set (reg:SI 91)
+ (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+ (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+ (nil))
+(insn 19 18 20 4 (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 20 frame)
+ (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+ (nil)))
+(code_label 20 19 21 5 3 (nil) [1 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 5 (set (reg:SI 88 [ <retval> ])
+ (reg:SI 87 [ _1 ])) -1
+ (nil))
+(insn 26 22 27 5 (set (reg/i:SI 0 ax)
+ (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+ (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+ (nil))
+
+
+/* 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. 1 .dx. 4 .si. 5 .di. 17 .flags." "dfinit" } } */
new file mode 100644
@@ -0,0 +1,51 @@
+/* { dg-options "-fsingle-pass=rtl-final -fdump-rtl-final" } */
+
+/* Lightly-modified dump of test.c.289r.dwarf2. */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 32 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(note 32 6 5 2 NOTE_INSN_PROLOGUE_END)
+(note 5 32 31 2 NOTE_INSN_FUNCTION_BEG)
+(insn:TI 31 5 27 2 (set (reg:SI 0 ax [93])
+ (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+ (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil))
+(insn 27 31 28 2 (parallel [
+ (set (reg:SI 1 dx [92])
+ (neg:SI (reg/v:SI 1 dx [orig:90 k ] [90])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (expr_list:REG_UNUSED (reg:CC 17 flags)
+ (nil)))
+(insn 28 27 29 2 (set (reg:CCGC 17 flags)
+ (compare:CCGC (reg/v:SI 5 di [orig:88 i ] [88])
+ (reg/v:SI 4 si [orig:89 j ] [89]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (expr_list:REG_DEAD (reg/v:SI 5 di [orig:88 i ] [88])
+ (expr_list:REG_DEAD (reg/v:SI 4 si [orig:89 j ] [89])
+ (nil))))
+(insn:TI 29 28 23 2 (set (reg:SI 0 ax [orig:87 <retval> ] [87])
+ (if_then_else:SI (ge (reg:CCGC 17 flags)
+ (const_int 0 [0]))
+ (reg:SI 1 dx [92])
+ (reg:SI 0 ax [93]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (expr_list:REG_DEAD (reg:CCGC 17 flags)
+ (expr_list:REG_DEAD (reg:SI 1 dx [92])
+ (nil))))
+(insn 23 29 34 2 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+ (nil))
+(jump_insn:TI 34 23 33 2 (simple_return) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+ (nil)
+ -> simple_return)
+(barrier 33 34 30)
+(note 30 33 0 (nil) NOTE_INSN_DELETED)
+
+/* Verify that asm was emitted. */
+/* { dg-final { scan-assembler "test_1:" } } */
+/* { dg-final { scan-assembler ".cfi_startproc" } } */
+/* { dg-final { scan-assembler ".cfi_endproc" } } */
+
+/* Verify that the "simple_return" was recognized.
+ FIXME: this assumes i386.md. */
+/* { dg-final { scan-assembler "ret" } } */
new file mode 100644
@@ -0,0 +1,6 @@
+/* Verify that we can include fragments from another dump.
+ We give the included file a .md suffix to avoid it being
+ run by rtl.exp. */
+
+(include "good-includee.md")
+/* TODO: verify that we have the instruction from the above file. */
new file mode 100644
@@ -0,0 +1 @@
+(note 1 0 0 (nil) NOTE_INSN_DELETED)
new file mode 100644
@@ -0,0 +1,85 @@
+/* { dg-options "-fsingle-pass=rtl-into_cfglayout -fdump-rtl-into_cfglayout" } */
+(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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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))
+
+/* The conversion to cfglayout should eliminate unconditional jump
+ instructions... */
+/* { dg-final { scan-rtl-dump "Removing jump 14." "into_cfglayout" } } */
+/* { dg-final { scan-rtl-dump-not "jump_insn 14" "into_cfglayout" } } */
+/* { dg-final { scan-rtl-dump-not "barrier 15" "into_cfglayout" } } */
+
+/* ...but conditional jumps should be preserved. */
+/* { dg-final { scan-rtl-dump "jump_insn 10" "into_cfglayout" } } */
new file mode 100644
@@ -0,0 +1,84 @@
+/* { dg-options "-fsingle-pass=rtl-ira -fdump-rtl-ira" } */
+
+/* Lightly-modified dump of test.c.251r.asmcons. */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+
+(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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 20 frame)
+ (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 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
+(insn 12 11 13 3 (set (reg:SI 90)
+ (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+ (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil))
+(insn 13 12 29 3 (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 20 frame)
+ (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])
+ (const_int 4 [0x4]))
+ (nil)))
+(jump_insn 29 13 30 3 (set (pc)
+ (label_ref 20)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil)
+ -> 20)
+(barrier 30 29 16)
+(code_label 16 30 17 4 2 (nil) [1 uses])
+(note 17 16 18 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 18 17 19 4 (set (reg:SI 91)
+ (mem/c:SI (plus:DI (reg/f:DI 20 frame)
+ (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32])) ../../src/gcc/testsuite/rtl.dg/test.c:6 -1
+ (nil))
+(insn 19 18 20 4 (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 20 frame)
+ (const_int -12 [0xfffffffffffffff4])) [1 k+0 S4 A32]))
+ (nil)))
+(code_label 20 19 21 5 3 (nil) [1 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 26 5 (set (reg:SI 88 [ <retval> ])
+ (reg:SI 87 [ _1 ])) -1
+ (nil))
+(insn 26 22 27 5 (set (reg/i:SI 0 ax)
+ (reg:SI 88 [ <retval> ])) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+ (nil))
+(insn 27 26 0 5 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+ (nil))
+
+/* Verify that IRA was run. */
+/* { dg-final { scan-rtl-dump "Building IRA IR" "ira" } } */
new file mode 100644
@@ -0,0 +1 @@
+(include "does-not-exist.rtl") /* { dg-error "include file .does-not-exist.rtl. not found" } */
new file mode 100644
@@ -0,0 +1,38 @@
+/* { dg-options "-fsingle-pass=rtl-pro_and_epilogue -fdump-rtl-pro_and_epilogue" } */
+
+/* Lightly-modified dump of test.c.259r.split2. */
+
+;; Function test_1 (test_1, funcdef_no=0, decl_uid=1758, cgraph_uid=0, symbol_order=0)
+(note 1 0 6 (nil) NOTE_INSN_DELETED)
+(note 6 1 5 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(note 5 6 31 2 NOTE_INSN_FUNCTION_BEG)
+(insn 31 5 27 2 (set (reg:SI 0 ax [93])
+ (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+ (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil))
+(insn 27 31 28 2 (parallel [
+ (set (reg:SI 1 dx [92])
+ (neg:SI (reg/v:SI 1 dx [orig:90 k ] [90])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil))
+(insn 28 27 29 2 (set (reg:CCGC 17 flags)
+ (compare:CCGC (reg/v:SI 5 di [orig:88 i ] [88])
+ (reg/v:SI 4 si [orig:89 j ] [89]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil))
+(insn 29 28 23 2 (set (reg:SI 0 ax [orig:87 <retval> ] [87])
+ (if_then_else:SI (ge (reg:CCGC 17 flags)
+ (const_int 0 [0]))
+ (reg:SI 1 dx [92])
+ (reg:SI 0 ax [93]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil))
+(insn 23 29 30 2 (use (reg/i:SI 0 ax)) ../../src/gcc/testsuite/rtl.dg/test.c:7 -1
+ (nil))
+(note 30 23 0 (nil) NOTE_INSN_DELETED)
+
+/* Verify that the prologue and epilogue were added. */
+/* { dg-final { scan-rtl-dump-times "NOTE_INSN_PROLOGUE_END" 1 "pro_and_epilogue" } } */
+
+/* We expect a jump_insn to "simple_return". */
+/* { dg-final { scan-rtl-dump-times "simple_return" 2 "pro_and_epilogue" } } */
+
new file mode 100644
@@ -0,0 +1,2 @@
+(code_label 1 0 2 6 3 (nil) [0 uses])
+(code_label 2 1 0 6 3 ("some_label_name") [57 uses])
new file mode 100644
@@ -0,0 +1,4 @@
+(insn 1 0 0 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 ])) ../../src/gcc/testsuite/rtl.dg/test.c:2 -1
+ (nil))
new file mode 100644
@@ -0,0 +1,4 @@
+(insn:TI 31 0 0 2 (set (reg:SI 0 ax [93])
+ (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+ (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil))
new file mode 100644
@@ -0,0 +1,6 @@
+(jump_insn 1 0 2 4 (set (pc)
+ (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil)
+ -> 3)
+(barrier 2 1 3)
+(code_label 3 2 0 5 2 (nil) [1 uses])
new file mode 100644
@@ -0,0 +1,6 @@
+(jump_insn 1 0 2 4 (set (pc)
+ (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil)
+ -> return)
+(barrier 2 1 3)
+(code_label 3 2 0 5 2 (nil) [1 uses])
new file mode 100644
@@ -0,0 +1,6 @@
+(jump_insn 1 0 2 4 (set (pc)
+ (label_ref 3)) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil)
+ -> simple_return)
+(barrier 2 1 3)
+(code_label 3 2 0 5 2 (nil) [1 uses])
new file mode 100644
@@ -0,0 +1 @@
+(note 1 0 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
new file mode 100644
@@ -0,0 +1 @@
+(note 1 0 0 (nil) NOTE_INSN_DELETED)
new file mode 100644
@@ -0,0 +1,4 @@
+(insn 31 0 0 2 (set (reg:SI 0 ax [93])
+ (plus:SI (reg/v:SI 1 dx [orig:90 k ] [90])
+ (const_int 4 [0x4]))) ../../src/gcc/testsuite/rtl.dg/test.c:4 -1
+ (nil))
new file mode 100644
@@ -0,0 +1,99 @@
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Verify that all of the .rtl files in this directory
+# "round trip" i.e. that loading and then dumping them leads to
+# identical content.
+
+load_lib rtl-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_RTLFLAGS
+if ![info exists DEFAULT_RTLFLAGS] then {
+ set DEFAULT_RTLFLAGS ""
+ # -fdump-tree-rtl-raw
+}
+
+# Compare INPUT_FILE and OUTPUT_FILE, and issue pass/fail
+# results if they have equal/non-equal content.
+
+proc verify-roundtrip { input_file output_file } {
+ verbose "verify-roundtrip:" 3
+ verbose " input_file: $input_file" 3
+ verbose " output_file: $output_file" 3
+ # Use "diff" from DejaGnu's utils.exp
+ set diff_result [diff $input_file $output_file]
+ if { $diff_result == 1 } then {
+ pass "$input_file and $output_file are identical"
+ } else {
+ if { $diff_result == -1 } then {
+ fail "$input_file and $output_file are non-identical"
+ } else {
+ fail "problem comparing $input_file with $output_file"
+ }
+ }
+}
+
+# Override the default implementation of rtl-dg-test:
+
+rename rtl-dg-test saved-rtl-dg-test
+
+# Alternate implementation of rtl-dg-test which adds a -froundtrip=
+# argument, and verifies that the output is identical to the input.
+
+proc rtl-dg-test { prog do_what extra_tool_flags } {
+ verbose "rtl-dg-test (roundtrip.exp):" 3
+ verbose " prog: $prog" 3
+ verbose " do_what: $do_what" 3
+ verbose " extra_tool_flags: $extra_tool_flags" 3
+
+ # Generate an output filename by stripping off the path from
+ # $prog, and adding a ".roundtrip.rtl" suffix.
+ set output_file [file tail $prog]
+ set output_file "$output_file.roundtrip.rtl"
+
+ # Use it with -froundtrip=.
+ set options \
+ "$extra_tool_flags -froundtrip=$output_file"
+ verbose "options=$options" 3
+
+ set result [gcc-dg-test-1 rtl_target_compile $prog $do_what $options]
+
+ # Verify that the output file is identical to the input file.
+ verify-roundtrip $prog $output_file
+ remote_file build delete $output_file
+ return $result
+}
+
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests, with the exception of those in directories
+# that are handled specially.
+set tests [lsort [find $srcdir/$subdir *.rtl]]
+
+verbose "roundtrip.exp tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# Restore the default implementation of rtl-dg-test:
+rename rtl-dg-test ""
+rename saved-rtl-dg-test rtl-dg-test
+
+# All done.
+dg-finish
new file mode 100644
@@ -0,0 +1,75 @@
+(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))
new file mode 100644
@@ -0,0 +1,202 @@
+(note 1 0 7 (nil) NOTE_INSN_DELETED)
+(note 7 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
+(insn 2 7 3 2 (set (reg/v:SI 88 [ i ])
+ (reg:SI 5 di [ i ])) ../../src/test-switch.c:2 -1
+ (nil))
+(insn 3 2 4 2 (set (reg/v:SI 89 [ j ])
+ (reg:SI 4 si [ j ])) ../../src/test-switch.c:2 -1
+ (nil))
+(insn 4 3 5 2 (set (reg/v:SI 90 [ k ])
+ (reg:SI 1 dx [ k ])) ../../src/test-switch.c:2 -1
+ (nil))
+(note 5 4 9 2 NOTE_INSN_FUNCTION_BEG)
+(insn 9 5 10 2 (parallel [
+ (set (reg:SI 91)
+ (plus:SI (reg/v:SI 88 [ i ])
+ (const_int 1 [0x1])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/test-switch.c:3 -1
+ (nil))
+(insn 10 9 11 2 (set (reg:CC 17 flags)
+ (compare:CC (reg:SI 91)
+ (const_int 25 [0x19]))) ../../src/test-switch.c:3 -1
+ (nil))
+(jump_insn 11 10 67 2 (set (pc)
+ (if_then_else (gtu (reg:CC 17 flags)
+ (const_int 0 [0]))
+ (label_ref 52)
+ (pc))) ../../src/test-switch.c:3 -1
+ (int_list:REG_BR_PROB 625 (nil))
+ -> 52)
+(note 67 11 12 4 [bb 4] NOTE_INSN_BASIC_BLOCK)
+(insn 12 67 13 4 (set (reg:DI 92)
+ (zero_extend:DI (reg:SI 91))) ../../src/test-switch.c:3 -1
+ (nil))
+(insn 13 12 14 4 (set (reg/f:DI 93)
+ (label_ref:DI 17)) ../../src/test-switch.c:3 -1
+ (insn_list:REG_LABEL_OPERAND 17 (nil)))
+(insn 14 13 15 4 (set (reg:DI 94)
+ (mem/u/c:DI (plus:DI (ashift:DI (reg:DI 92)
+ (const_int 3 [0x3]))
+ (reg/f:DI 93)) [0 S8 A8])) ../../src/test-switch.c:3 -1
+ (nil))
+(jump_insn 15 14 16 4 (parallel [
+ (set (pc)
+ (reg:DI 94))
+ (use (label_ref 17))
+ ]) ../../src/test-switch.c:3 -1
+ (nil)
+ -> 17)
+(barrier 16 15 17)
+(code_label 17 16 18 (nil) 4 (nil) [2 uses])
+(jump_table_data 18 17 19 (nil) (addr_vec:DI [
+ (label_ref:DI 66)
+ (label_ref:DI 20)
+ (label_ref:DI 20)
+ (label_ref:DI 20)
+ (label_ref:DI 20)
+ (label_ref:DI 20)
+ (label_ref:DI 20)
+ (label_ref:DI 20)
+ (label_ref:DI 20)
+ (label_ref:DI 20)
+ (label_ref:DI 20)
+ (label_ref:DI 35)
+ (label_ref:DI 40)
+ (label_ref:DI 46)
+ (label_ref:DI 52)
+ (label_ref:DI 52)
+ (label_ref:DI 52)
+ (label_ref:DI 52)
+ (label_ref:DI 52)
+ (label_ref:DI 52)
+ (label_ref:DI 52)
+ (label_ref:DI 52)
+ (label_ref:DI 52)
+ (label_ref:DI 52)
+ (label_ref:DI 25)
+ (label_ref:DI 30)
+ ]))
+(barrier 19 18 20)
+(code_label 20 19 21 5 5 (nil) [10 uses])
+(note 21 20 22 5 [bb 5] NOTE_INSN_BASIC_BLOCK)
+(insn 22 21 23 5 (parallel [
+ (set (reg:SI 87 [ <retval> ])
+ (ashift:SI (reg/v:SI 88 [ i ])
+ (const_int 1 [0x1])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/test-switch.c:8 -1
+ (nil))
+(jump_insn 23 22 24 5 (set (pc)
+ (label_ref:DI 59)) ../../src/test-switch.c:8 -1
+ (nil)
+ -> 59)
+(barrier 24 23 25)
+(code_label 25 24 26 6 9 (nil) [1 uses])
+(note 26 25 27 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
+(insn 27 26 28 6 (parallel [
+ (set (reg:SI 87 [ <retval> ])
+ (plus:SI (reg/v:SI 89 [ j ])
+ (reg/v:SI 90 [ k ])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/test-switch.c:10 -1
+ (nil))
+(jump_insn 28 27 29 6 (set (pc)
+ (label_ref:DI 59)) ../../src/test-switch.c:10 -1
+ (nil)
+ -> 59)
+(barrier 29 28 30)
+(code_label 30 29 31 7 10 (nil) [1 uses])
+(note 31 30 32 7 [bb 7] NOTE_INSN_BASIC_BLOCK)
+(insn 32 31 33 7 (parallel [
+ (set (reg:SI 87 [ <retval> ])
+ (minus:SI (reg/v:SI 89 [ j ])
+ (reg/v:SI 90 [ k ])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/test-switch.c:12 -1
+ (nil))
+(jump_insn 33 32 34 7 (set (pc)
+ (label_ref:DI 59)) ../../src/test-switch.c:12 -1
+ (nil)
+ -> 59)
+(barrier 34 33 35)
+(code_label 35 34 36 8 6 (nil) [1 uses])
+(note 36 35 37 8 [bb 8] NOTE_INSN_BASIC_BLOCK)
+(insn 37 36 38 8 (parallel [
+ (set (reg:SI 87 [ <retval> ])
+ (mult:SI (reg/v:SI 89 [ j ])
+ (reg/v:SI 90 [ k ])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/test-switch.c:14 -1
+ (nil))
+(jump_insn 38 37 39 8 (set (pc)
+ (label_ref:DI 59)) ../../src/test-switch.c:14 -1
+ (nil)
+ -> 59)
+(barrier 39 38 40)
+(code_label 40 39 41 9 7 (nil) [1 uses])
+(note 41 40 42 9 [bb 9] NOTE_INSN_BASIC_BLOCK)
+(insn 42 41 43 9 (parallel [
+ (set (reg:SI 95)
+ (div:SI (reg/v:SI 89 [ j ])
+ (reg/v:SI 90 [ k ])))
+ (set (reg:SI 96)
+ (mod:SI (reg/v:SI 89 [ j ])
+ (reg/v:SI 90 [ k ])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/test-switch.c:16 -1
+ (nil))
+(insn 43 42 44 9 (set (reg:SI 87 [ <retval> ])
+ (reg:SI 95)) ../../src/test-switch.c:16 -1
+ (nil))
+(jump_insn 44 43 45 9 (set (pc)
+ (label_ref:DI 59)) ../../src/test-switch.c:16 -1
+ (nil)
+ -> 59)
+(barrier 45 44 46)
+(code_label 46 45 47 10 8 (nil) [1 uses])
+(note 47 46 48 10 [bb 10] NOTE_INSN_BASIC_BLOCK)
+(insn 48 47 49 10 (parallel [
+ (set (reg:SI 98)
+ (div:SI (reg/v:SI 89 [ j ])
+ (reg/v:SI 90 [ k ])))
+ (set (reg:SI 97)
+ (mod:SI (reg/v:SI 89 [ j ])
+ (reg/v:SI 90 [ k ])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/test-switch.c:18 -1
+ (nil))
+(insn 49 48 50 10 (set (reg:SI 87 [ <retval> ])
+ (reg:SI 97)) ../../src/test-switch.c:18 -1
+ (nil))
+(jump_insn 50 49 51 10 (set (pc)
+ (label_ref:DI 59)) ../../src/test-switch.c:18 -1
+ (nil)
+ -> 59)
+(barrier 51 50 52)
+(code_label 52 51 53 11 2 (nil) [11 uses])
+(note 53 52 54 11 [bb 11] NOTE_INSN_BASIC_BLOCK)
+(insn 54 53 63 11 (parallel [
+ (set (reg:SI 87 [ <retval> ])
+ (plus:SI (reg/v:SI 89 [ j ])
+ (reg/v:SI 90 [ k ])))
+ (clobber (reg:CC 17 flags))
+ ]) ../../src/test-switch.c:20 -1
+ (nil))
+(jump_insn 63 54 64 11 (set (pc)
+ (label_ref:DI 59)) ../../src/test-switch.c:20 -1
+ (nil)
+ -> 59)
+(barrier 64 63 66)
+(code_label 66 64 65 12 11 (nil) [1 uses])
+(note 65 66 6 12 [bb 12] NOTE_INSN_BASIC_BLOCK)
+(insn 6 65 59 12 (set (reg:SI 87 [ <retval> ])
+ (const_int 34 [0x22])) ../../src/test-switch.c:6 -1
+ (nil))
+(code_label 59 6 62 14 1 (nil) [7 uses])
+(note 62 59 60 14 [bb 14] NOTE_INSN_BASIC_BLOCK)
+(insn 60 62 61 14 (set (reg/i:SI 0 ax)
+ (reg:SI 87 [ <retval> ])) ../../src/test-switch.c:22 -1
+ (nil))
+(insn 61 60 0 14 (use (reg/i:SI 0 ax)) ../../src/test-switch.c:22 -1
+ (nil))
new file mode 100644
@@ -0,0 +1,43 @@
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib rtl-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_RTLFLAGS
+if ![info exists DEFAULT_RTLFLAGS] then {
+ set DEFAULT_RTLFLAGS ""
+ # -fdump-tree-rtl-raw
+}
+
+# Initialize `dg'.
+dg-init
+
+# Gather a list of all tests, with the exception of those in directories
+# that are handled specially.
+set tests [lsort [find $srcdir/$subdir *.rtl]]
+set tests [prune $tests $srcdir/$subdir/roundtrip/*]
+
+verbose "rtl.exp tests: $tests" 1
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_RTLFLAGS
+
+# All done.
+dg-finish
new file mode 100644
@@ -0,0 +1,31 @@
+int test_1 (int i, int j, int k)
+{
+ if (i < j)
+ return k + 4;
+ else
+ return -k;
+}
+
+/* Example showing:
+ - data structure
+ - loop
+ - call to "abort". */
+
+struct foo
+{
+ int count;
+ float *data;
+};
+
+float test_2 (struct foo *lhs, struct foo *rhs)
+{
+ float result = 0.0f;
+
+ if (lhs->count != rhs->count)
+ __builtin_abort ();
+
+ for (int i = 0; i < lhs->count; i++)
+ result += lhs->data[i] * rhs->data[i];
+
+ return result;
+}
new file mode 100644
@@ -0,0 +1,3 @@
+(note 6 1 0 2 [bb 2] NOTE_INSN_BASIC_BLOCK) ;; { dg-error "insn with UID 1 not found for operand 0 ..PREV_INSN.. of insn 6" }
+
+(note 7 0 3 2 [bb 2] NOTE_INSN_BASIC_BLOCK) ;; { dg-error "insn with UID 3 not found for operand 1 ..NEXT_INSN.. of insn 7" }
new file mode 100644
@@ -0,0 +1 @@
+(not-a-valid-kind-of-insn 1 0 0) ;; { dg-error "unknown rtx code" }
new file mode 100644
@@ -0,0 +1,80 @@
+/* { dg-options "-fsingle-pass=rtl-vregs -fdump-rtl-vregs" } */
+(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))
+
+/* The 9 instances of "virtual-stack-vars" should now all be "frame". */
+/* { dg-final { scan-rtl-dump-times "frame" 9 "vregs" } } */
+/* { dg-final { scan-rtl-dump-not "virtual-stack-vars" "vregs" } } */
@@ -473,6 +473,13 @@ compile_file (void)
if (flag_syntax_only || flag_wpa)
return;
+
+ /* The RTL frontend is currently only capable of running one pass; this
+ is done from within the parse_file langhook.
+ Hence we must return early here. Fixing this would require
+ being able to run passes from a certain point onwards. */
+ if (in_rtl_frontend_p)
+ return;
/* Reset maximum_field_alignment, it can be adjusted by #pragma pack
and this shouldn't influence any types built by the middle-end
@@ -305,6 +305,11 @@ ssa_default_def (struct function *fn, tree var)
gcc_assert (TREE_CODE (var) == VAR_DECL
|| TREE_CODE (var) == PARM_DECL
|| TREE_CODE (var) == RESULT_DECL);
+
+ /* Always NULL_TREE for rtl1. */
+ if (!fn->gimple_df)
+ return NULL_TREE;
+
in.var = (tree)&ind;
ind.uid = DECL_UID (var);
return DEFAULT_DEFS (fn)->find_with_hash ((tree)&in, DECL_UID (var));