summaryrefslogtreecommitdiff
path: root/gcc/read-rtl.c
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2017-01-05 19:32:09 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2017-01-05 19:32:09 +0000
commit51b861137ed73ae73e15a136949301fbaaf89202 (patch)
treefd9bdb64e3920b3c35272969864ac5576f4fdad5 /gcc/read-rtl.c
parent7f86d7de6b80f68a47fc48f82af1a3ec9dbda21a (diff)
Introduce RTL function reader
This is the combination of these patches: - [8a/9] Introduce class function_reader (v8) - Add ASSERT_RTX_PTR_EQ - [8b/9] Add target-independent selftests of RTL function reader (v2) - [8c/9] Add aarch64-specific selftests for RTL function reader (v2) - [8d/9] Add x86_64-specific selftests for RTL function reader (v2) gcc/ChangeLog: * Makefile.in (OBJS): Add read-md.o, read-rtl.o, read-rtl-function.o, and selftest-rtl.o. * config/aarch64/aarch64.c: Include selftest.h and selftest-rtl.h. (selftest::aarch64_test_loading_full_dump): New function. (selftest::aarch64_run_selftests): New function. (TARGET_RUN_TARGET_SELFTESTS): Wire it up to selftest::aarch64_run_selftests. * config/i386/i386.c (selftest::ix86_test_loading_dump_fragment_1): New function. (selftest::ix86_test_loading_call_insn): New function. (selftest::ix86_test_loading_full_dump): New function. (selftest::ix86_test_loading_unspec): New function. (selftest::ix86_run_selftests): Call the new functions. * emit-rtl.c (maybe_set_max_label_num): New function. * emit-rtl.h (maybe_set_max_label_num): New decl. * function.c (instantiate_decls): Guard call to instantiate_decls_1 with if (DECL_INITIAL (fndecl)). * function-tests.c (selftest::verify_three_block_rtl_cfg): Remove "static". * gensupport.c (gen_reader::gen_reader): Pass "false" for new "compact" param of rtx_reader. * print-rtl.c (rtx_writer::print_rtx_operand): Print "(nil)" rather than an empty string for NULL strings. * read-md.c: Potentially include config.h rather than bconfig.h. Wrap include of errors.h with #ifdef GENERATOR_FILE. (have_error): New global, copied from errors.c. (md_reader::read_name): Rename to... (md_reader::read_name_1): ...this, adding "out_loc" param, and converting "missing name or number" to returning false, rather than failing. (md_reader::read_name): Reimplement in terms of read_name_1. (md_reader::read_name_or_nil): New function. (md_reader::read_string): Handle "(nil)" by returning NULL. (md_reader::md_reader): Add new param "compact". (md_reader::read_md_files): Wrap with #ifdef GENERATOR_FILE. (md_reader::read_file): New method. * read-md.h (md_reader::md_reader): Add new param "compact". (md_reader::read_file): New method. (md_reader::is_compact): New accessor. (md_reader::read_name): Convert return type from void to file_location. (md_reader::read_name_or_nil): New decl. (md_reader::read_name_1): New decl. (md_reader::m_compact): New field. (noop_reader::noop_reader): Pass "false" for new "compact" param of rtx_reader. (rtx_reader::rtx_reader): Add new "compact" param. (rtx_reader::read_rtx_operand): Make virtual and convert return type from void to rtx. (rtx_reader::read_until): New decl. (rtx_reader::handle_any_trailing_information): New virtual function. (rtx_reader::postprocess): New virtual function. (rtx_reader::finalize_string): New virtual function. (rtx_reader::m_in_call_function_usage): New field. (rtx_reader::m_reuse_rtx_by_id): New field. * read-rtl-function.c: New file. * selftest-rtl.c (selftest::assert_rtx_ptr_eq_at): New function. * selftest-rtl.h (ASSERT_RTX_PTR_EQ): New macro. (selftest::verify_three_block_rtl_cfg): New decl. * read-rtl-function.h: New file. * read-rtl.c: Potentially include config.h rather than bconfig.h. For host, include function.h, memmodel.h, and emit-rtl.h. (one_time_initialization): New function. (struct compact_insn_name): New struct. (compact_insn_names): New array. (find_code): Handle insn codes in compact dumps. (apply_subst_iterator): Wrap with #ifdef GENERATOR_FILE. (bind_subst_iter_and_attr): Likewise. (add_condition_to_string): Likewise. (add_condition_to_rtx): Likewise. (apply_attribute_uses): Likewise. (add_current_iterators): Likewise. (apply_iterators): Likewise. (initialize_iterators): Guard usage of apply_subst_iterator with #ifdef GENERATOR_FILE. (read_conditions): Wrap with #ifdef GENERATOR_FILE. (md_reader::read_mapping): Likewise. (add_define_attr_for_define_subst): Likewise. (add_define_subst_attr): Likewise. (read_subst_mapping): Likewise. (check_code_iterator): Likewise. (rtx_reader::read_rtx): Likewise. Move one-time initialization logic to... (one_time_initialization): New function. (rtx_reader::read_until): New method. (read_flags): New function. (parse_reg_note_name): New function. (rtx_reader::read_rtx_code): Initialize "iterator" to NULL. Handle reuse_rtx ids. Wrap iterator lookup within #ifdef GENERATOR_FILE. Add parsing support for RTL dumps, mirroring the special-cases in print_rtx, by calling read_flags, reading REG_NOTE names, INSN_UID values, and calling handle_any_trailing_information. (rtx_reader::read_rtx_operand): Convert return type from void to rtx, returning return_rtx. Handle case 'e'. Call finalize_string on XSTR and XTMPL fields. (rtx_reader::read_nested_rtx): Handle dumps in which trailing "(nil)" values were omitted. Call the postprocess vfunc on the return_rtx. (rtx_reader::rtx_reader): Add new "compact" param and pass to base class ctor. Initialize m_in_call_function_usage. Call one_time_initialization. * rtl-tests.c (selftest::test_uncond_jump): Call set_new_first_and_last_insn. * rtl.h (read_rtx): Wrap decl with #ifdef GENERATOR_FILE. * selftest-rtl.c: New file. * selftest-rtl.h (class selftest::rtl_dump_test): New class. (selftest::get_insn_by_uid): New decl. * selftest-run-tests.c (selftest::run_tests): Call read_rtl_function_c_tests. * selftest.h (selftest::read_rtl_function_c_tests): New decl. * tree-dfa.c (ssa_default_def): Return NULL_TREE for rtl function dumps. gcc/testsuite/ChangeLog: * selftests/asr_div1.rtl: New file. * selftests/aarch64: New subdirectory. * selftests/aarch64/times-two.rtl: New file. * selftests/bb-index.rtl: New file. * selftests/cfg-test.rtl: New file. * selftests/const-int.rtl: New file. * selftests/example-labels.rtl: New file. * selftests/insn-with-mode.rtl: New file. * selftests/jump-to-label-ref.rtl: New file. * selftests/jump-to-return.rtl: New file. * selftests/jump-to-simple-return.rtl: New file. * selftests/mem.rtl: New file. * selftests/note-insn-deleted.rtl: New file. * selftests/note_insn_basic_block.rtl: New file. * selftests/simple-cse.rtl: New file. * selftests/symbol-ref.rtl: New file. * selftests/x86_64: New subdirectory. * selftests/x86_64/call-insn.rtl: New file. * selftests/x86_64/copy-hard-reg-into-frame.rtl: New file. * selftests/x86_64/times-two.rtl: New file. * selftests/x86_64/unspec.rtl: New file. From-SVN: r244110
Diffstat (limited to 'gcc/read-rtl.c')
-rw-r--r--gcc/read-rtl.c260
1 files changed, 242 insertions, 18 deletions
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index a08ce5c9f08..e9c80682800 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -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,12 @@ along with GCC; see the file COPYING3. If not see
#include "read-md.h"
#include "gensupport.h"
+#ifndef GENERATOR_FILE
+#include "function.h"
+#include "memmodel.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,6 +118,7 @@ htab_t subst_attr_to_iter_map = NULL;
const char *current_iterator_name;
static void validate_const_int (const char *);
+static void one_time_initialization (void);
/* Global singleton. */
rtx_reader *rtx_reader_ptr = NULL;
@@ -142,6 +155,25 @@ apply_mode_iterator (void *loc, int mode)
PUT_MODE ((rtx) loc, (machine_mode) mode);
}
+/* In compact dumps, the code of insns is prefixed with "c", giving "cinsn",
+ "cnote" etc, and CODE_LABEL is special-cased as "clabel". */
+
+struct compact_insn_name {
+ RTX_CODE code;
+ const char *name;
+};
+
+static const compact_insn_name compact_insn_names[] = {
+ { DEBUG_INSN, "cdebug_insn" },
+ { INSN, "cinsn" },
+ { JUMP_INSN, "cjump_insn" },
+ { CALL_INSN, "ccall_insn" },
+ { JUMP_TABLE_DATA, "cjump_table_data" },
+ { BARRIER, "cbarrier" },
+ { CODE_LABEL, "clabel" },
+ { NOTE, "cnote" }
+};
+
/* Implementations of the iterator_group callbacks for codes. */
static int
@@ -153,6 +185,10 @@ find_code (const char *name)
if (strcmp (GET_RTX_NAME (i), name) == 0)
return i;
+ for (i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++)
+ if (strcmp (compact_insn_names[i].name, name) == 0)
+ return compact_insn_names[i].code;
+
fatal_with_file_and_line ("unknown rtx code `%s'", name);
}
@@ -181,6 +217,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 +290,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 +458,8 @@ md_reader::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 +623,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 +698,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 +769,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:
@@ -765,6 +812,7 @@ md_reader::read_conditions ()
add_c_test (expr, value);
}
}
+#endif /* #ifdef GENERATOR_FILE */
static void
validate_const_int (const char *string)
@@ -861,6 +909,8 @@ md_reader::record_potential_iterator_use (struct iterator_group *group,
}
}
+#ifdef GENERATOR_FILE
+
/* Finish reading a declaration of the form:
(define... <name> [<value1> ... <valuen>])
@@ -1020,15 +1070,6 @@ check_code_iterator (struct mapping *iterator)
bool
rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
{
- static bool initialized = false;
-
- /* Do one-time initialization. */
- if (!initialized)
- {
- initialize_iterators ();
- initialized = true;
- }
-
/* Handle various rtx-related declarations that aren't themselves
encoded as rtxes. */
if (strcmp (rtx_name, "define_conditions") == 0)
@@ -1082,6 +1123,103 @@ rtx_reader::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;
+ }
+}
+
+/* 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. */
+
+char *
+rtx_reader::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 ());
+}
+
+/* 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);
+ }
+ }
+}
+
+/* Return the numeric value n for GET_REG_NOTE_NAME (n) for STRING,
+ or fail if STRING isn't recognized. */
+
+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);
+}
+
/* 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. */
@@ -1090,11 +1228,12 @@ rtx
rtx_reader::read_rtx_code (const char *code_name)
{
RTX_CODE code;
- struct mapping *iterator;
+ struct mapping *iterator = NULL;
const char *format_ptr;
struct md_name name;
rtx return_rtx;
int c;
+ long reuse_id = -1;
/* Linked list structure for making RTXs: */
struct rtx_list
@@ -1103,13 +1242,37 @@ rtx_reader::read_rtx_code (const char *code_name)
rtx value; /* Value of this node. */
};
+ /* Handle reuse_rtx ids e.g. "(0|scratch:DI)". */
+ if (ISDIGIT (code_name[0]))
+ {
+ reuse_id = atoi (code_name);
+ while (char ch = *code_name++)
+ if (ch == '|')
+ break;
+ }
+
+ /* Handle "reuse_rtx". */
+ if (strcmp (code_name, "reuse_rtx") == 0)
+ {
+ read_name (&name);
+ long idx = atoi (name.string);
+ /* Look it up by ID. */
+ gcc_assert (idx < m_reuse_rtx_by_id.length ());
+ return_rtx = m_reuse_rtx_by_id[idx];
+ return return_rtx;
+ }
+
/* 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);
@@ -1117,9 +1280,36 @@ rtx_reader::read_rtx_code (const char *code_name)
memset (return_rtx, 0, RTX_CODE_SIZE (code));
PUT_CODE (return_rtx, code);
+ if (reuse_id != -1)
+ {
+ /* Store away for later reuse. */
+ m_reuse_rtx_by_id.safe_grow_cleared (reuse_id + 1);
+ m_reuse_rtx_by_id[reuse_id] = return_rtx;
+ }
+
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. */
+ if ((GET_CODE (return_rtx) == EXPR_LIST
+ || GET_CODE (return_rtx) == INSN_LIST
+ || GET_CODE (return_rtx) == INT_LIST)
+ && !m_in_call_function_usage)
+ {
+ 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);
+ }
+
/* If what follows is `: mode ', read it and
store the mode in the rtx. */
@@ -1132,8 +1322,19 @@ rtx_reader::read_rtx_code (const char *code_name)
else
unread_char (c);
+ if (INSN_CHAIN_CODE_P (code))
+ {
+ read_name (&name);
+ INSN_UID (return_rtx) = atoi (name.string);
+ }
+
+ /* Use the format_ptr to parse the various operands of this rtx. */
for (int idx = 0; format_ptr[idx] != 0; idx++)
- read_rtx_operand (return_rtx, idx);
+ return_rtx = read_rtx_operand (return_rtx, idx);
+
+ /* Handle any additional information that after the regular fields
+ (e.g. when parsing function dumps). */
+ handle_any_trailing_information (return_rtx);
if (CONST_WIDE_INT_P (return_rtx))
{
@@ -1197,9 +1398,11 @@ rtx_reader::read_rtx_code (const char *code_name)
/* Subroutine of read_rtx_code. Parse operand IDX within RETURN_RTX,
based on the corresponding format character within GET_RTX_FORMAT
- for the GET_CODE (RETURN_RTX). */
+ for the GET_CODE (RETURN_RTX), and return RETURN_RTX.
+ This is a virtual function, so that function_reader can override
+ some parsing, and potentially return a different rtx. */
-void
+rtx
rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
{
RTX_CODE code = GET_CODE (return_rtx);
@@ -1217,6 +1420,9 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
break;
case 'e':
+ XEXP (return_rtx, idx) = read_nested_rtx ();
+ break;
+
case 'u':
XEXP (return_rtx, idx) = read_nested_rtx ();
break;
@@ -1273,7 +1479,6 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
{
char *stringbuf;
int star_if_braced;
- struct obstack *string_obstack = get_string_obstack ();
c = read_skip_spaces ();
unread_char (c);
@@ -1293,7 +1498,10 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
star_if_braced = (format_ptr[idx] == '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
@@ -1303,6 +1511,7 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
&& (GET_CODE (return_rtx) == DEFINE_INSN
|| GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
{
+ struct obstack *string_obstack = get_string_obstack ();
char line_name[20];
const char *read_md_filename = get_filename ();
const char *fn = (read_md_filename ? read_md_filename : "rtx");
@@ -1348,11 +1557,14 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
if (m != 0)
record_iterator_use (m, return_rtx);
}
+#endif /* #ifdef GENERATOR_FILE */
+
+ const char *string_ptr = finalize_string (stringbuf);
if (star_if_braced)
- XTMPL (return_rtx, idx) = stringbuf;
+ XTMPL (return_rtx, idx) = string_ptr;
else
- XSTR (return_rtx, idx) = stringbuf;
+ XSTR (return_rtx, idx) = string_ptr;
}
break;
@@ -1398,6 +1610,8 @@ rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
default:
gcc_unreachable ();
}
+
+ return return_rtx;
}
/* Read a nested rtx construct from the MD file and return it. */
@@ -1408,6 +1622,11 @@ rtx_reader::read_nested_rtx ()
struct md_name name;
rtx return_rtx;
+ /* In compact dumps, trailing "(nil)" values can be omitted.
+ Handle such dumps. */
+ if (peek_char () == ')')
+ return NULL_RTX;
+
require_char_ws ('(');
read_name (&name);
@@ -1418,6 +1637,8 @@ rtx_reader::read_nested_rtx ()
require_char_ws (')');
+ return_rtx = postprocess (return_rtx);
+
return return_rtx;
}
@@ -1454,11 +1675,14 @@ rtx_reader::read_rtx_variadic (rtx form)
/* Constructor for class rtx_reader. */
-rtx_reader::rtx_reader ()
-: md_reader ()
+rtx_reader::rtx_reader (bool compact)
+: md_reader (compact),
+ m_in_call_function_usage (false)
{
/* Set the global singleton pointer. */
rtx_reader_ptr = this;
+
+ one_time_initialization ();
}
/* Destructor for class rtx_reader. */