genemit has traditionally used open-coded gen_rtx_FOO sequences to build up the instruction pattern. This is now the source of quite a bit of bloat in the binary, and also a source of slow compile times.
Two obvious ways of trying to deal with this are: (1) Try to identify rtxes that have a similar form and use shared routines to generate rtxes of that form. (2) Use a static table to encode the rtx and call a common routine to expand it. I did briefly look at (1). However, it's more complex than (2), and I think suffers from being the worst of both worlds, for reasons that I'll explain below. This patch therefore does (2). In theory, one of the advantages of open-coding the calls to gen_rtx_FOO is that the rtx can be populated using stores of known constants (for the rtx code, mode, unspec number, etc). However, the time spent constructing an rtx is likely to be dominated by the call to rtx_alloc, rather than by the stores to the fields. Option (1) above loses this advantage of storing constants. The shared routines would parameterise an rtx according to things like the modes on the rtx and its suboperands, so the code would need to fetch the parameters. In a sense, the rtx structure would be open-coded but the parameters would be table-encoded (albeit in a simple way). The expansion code also shouldn't be particularly hot. Anything that treats expand/discard cycles as very cheap would be misconceived, since each discarded expansion generates garbage memory that needs to be cleaned up later. Option (2) turns out to be pretty simple -- certainly simpler than (1) -- and seems to give a reasonable saving. Some numbers, all for --enable-checking=yes,rtl,extra: [A] size of the @progbits sections in insn-emit-*.o, new / old [B] size of the load segments in cc1, new / old [C] time to compile a typical insn-emit*.cc, new / old Target [A] [B] [C] -------------------------------------------- native aarch64 0.5627 0.9585 0.5677 native x86_64 0.5925 0.9467 0.6377 aarch64-x-riscv64 0.5555 0.9066 0.2762 To get an idea of the effect on the final compiler, I tried compiling fold-const.ii with -O0 (no -g), since that should give any slowdown less room to hide. I couldn't measure any difference in compile time before or after the patch for any of the three variants above. gcc/ * gensupport.h (needs_barrier_p): Delete. * gensupport.cc (needs_barrier_p): Likewise. * rtl.h (always_void_p): Return true for PC, RETURN and SIMPLE_RETURN. (expand_opcode): New enum class. (expand_rtx, complete_seq): Declare. * emit-rtl.cc (rtx_expander): New class. (expand_rtx, complete_seq): New functions. * gengenrtl.cc (special_rtx, excluded_rtx): Add a cross-reference comment. * genemit.cc (FIRST_CODE): New constant. (print_code): Delete. (generator::file, generator::used, generator::sequence_type): Delete. (generator::bytes): New member variable. (generator::generator): Update accordingly. (generator::gen_rtx_scratch): Delete. (generator::add_uint, generator::add_opcode, generator::add_code) (generator::add_match_operator, generator::add_exp) (generator::add_vec, generator::gen_table): New member functions. (generator::gen_exp): Rewrite to use a bytecode expansion. (generator::gen_emit_seq): Likewise. (start_gen_insn): Return the C++ expression for the operands array. (gen_insn, gen_expand, gen_split): Update callers accordingly. (emit_c_code): Remove use of _val. --- gcc/emit-rtl.cc | 292 ++++++++++++++++++++++++++++++++++++++ gcc/genemit.cc | 346 +++++++++++++++++++--------------------------- gcc/gengenrtl.cc | 10 +- gcc/gensupport.cc | 10 -- gcc/gensupport.h | 1 - gcc/rtl.h | 42 +++++- 6 files changed, 480 insertions(+), 221 deletions(-) diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc index fc7b6c7e297..57021fbb5ff 100644 --- a/gcc/emit-rtl.cc +++ b/gcc/emit-rtl.cc @@ -64,6 +64,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" #include "gimple-ssa.h" #include "gimplify.h" +#include "bbitmap.h" struct target_rtl default_target_rtl; #if SWITCHABLE_TARGET @@ -6777,6 +6778,297 @@ gen_int_shift_amount (machine_mode, poly_int64 value) return gen_int_mode (value, shift_mode); } +namespace { +/* Helper class for expanding an rtx using the encoding generated by + genemit.cc. The code needs to be kept in sync with there. */ + +class rtx_expander +{ +public: + rtx_expander (const uint8_t *, rtx *); + + rtx get_rtx (); + rtvec get_rtvec (); + void expand_seq (); + +protected: + uint64_t get_uint (); + machine_mode get_mode () { return machine_mode (get_uint ()); } + char *get_string (); + rtx get_shared_operand (); + rtx get_unshared_operand (); + + rtx get_rtx (expand_opcode); + rtx get_rtx (rtx_code, machine_mode); + + /* Points to the first unread byte. */ + const uint8_t *m_seq; + + /* The operands passed to the gen_* function. */ + rtx *m_operands; + + /* A bitmap of operands that have already been used to replace a + MATCH_OPERAND or MATCH_DUP. In order to ensure correct sharing, + further replacements need to use a copy of the operand, rather than + the original rtx. */ + bbitmap<MAX_RECOG_OPERANDS> m_used; +}; +} + +rtx_expander::rtx_expander (const uint8_t *seq, rtx *operands) + : m_seq (seq), m_operands (operands), m_used () +{} + +/* Read and return the next encoded "BEB128" integer. */ + +inline uint64_t +rtx_expander::get_uint () +{ + const uint8_t *seq = m_seq; + uint64_t res = 0; + do + res = (res << 7) | (*seq & 127); + while (*seq++ >= 128); + m_seq = seq; + return res; +} + +/* Read an operand number and return the associated operand rtx, + without copying it. */ + +rtx +rtx_expander::get_shared_operand () +{ + return m_operands[get_uint ()]; +} + +/* Read an operand number and return a correctly-shared instance of + the associated operand rtx. This can be either the original rtx + or a copy. */ + +rtx +rtx_expander::get_unshared_operand () +{ + auto opno = get_uint (); + auto mask = m_used.from_index (opno); + if (m_used & mask) + return copy_rtx (m_operands[opno]); + + m_used |= mask; + return m_operands[opno]; +} + +/* Read an encoded rtx. */ + +rtx +rtx_expander::get_rtx () +{ + auto FIRST_CODE = (unsigned) expand_opcode::FIRST_CODE; + auto opcode = get_uint (); + if (opcode < FIRST_CODE) + return get_rtx (expand_opcode (opcode)); + return get_rtx (rtx_code (opcode - FIRST_CODE), NUM_MACHINE_MODES); +} + +/* Read an encoded rtx that starts with the given opcode. */ + +rtx +rtx_expander::get_rtx (expand_opcode opcode) +{ + switch (opcode) + { + case expand_opcode::NO_RTX: + return NULL_RTX; + + case expand_opcode::MATCH_OPERAND: + return get_unshared_operand (); + + case expand_opcode::MATCH_OPERATOR_WITH_MODE: + { + auto mode = get_mode (); + auto op = get_shared_operand (); + return get_rtx (GET_CODE (op), mode); + } + + case expand_opcode::MATCH_OPERATOR: + { + auto op = get_shared_operand (); + return get_rtx (GET_CODE (op), GET_MODE (op)); + } + + case expand_opcode::MATCH_PARALLEL: + return get_shared_operand (); + + case expand_opcode::CLOBBER_REG: + { + auto mode = get_mode (); + auto regno = get_uint (); + return gen_hard_reg_clobber (mode, regno); + } + + case expand_opcode::FIRST_CODE: + break; + } + gcc_unreachable (); +} + +/* Read the rest of an rtx of code CODE. If such rtxes are not always + VOIDmode, MODE is the mode that the rtx should have, or NUM_MACHINE_MODES + if the mode is encoded at the current iterator position. */ + +rtx +rtx_expander::get_rtx (rtx_code code, machine_mode mode) +{ + switch (code) + { + /* Please keep the cases below in sync with gengenrtl.cc:special_rtx. */ + + case EXPR_LIST: + case INSN_LIST: + case INSN: + gcc_unreachable (); + + case CONST_INT: + return GEN_INT (get_uint ()); + + case REG: + if (mode == NUM_MACHINE_MODES) + mode = get_mode (); + return gen_rtx_REG (mode, get_uint ()); + + case SUBREG: + { + if (mode == NUM_MACHINE_MODES) + mode = get_mode (); + auto reg = get_rtx (); + auto byte = get_uint (); + return gen_rtx_SUBREG (mode, reg, byte); + } + + case MEM: + if (mode == NUM_MACHINE_MODES) + mode = get_mode (); + return gen_rtx_MEM (mode, get_rtx ()); + + case PC: + return pc_rtx; + + case RETURN: + return ret_rtx; + + case SIMPLE_RETURN: + return simple_return_rtx; + + case CONST_VECTOR: + if (mode == NUM_MACHINE_MODES) + mode = get_mode (); + return gen_rtx_CONST_VECTOR (mode, get_rtvec ()); + + /* Please keep the cases below in sync with + gengenrtl.cc:excluded_rtx. */ + + case VAR_LOCATION: + gcc_unreachable (); + + case CONST_DOUBLE: + /* genemit.cc only accepts zero const_doubles. */ + if (mode == NUM_MACHINE_MODES) + mode = get_mode (); + return CONST0_RTX (mode); + + case CONST_WIDE_INT: + case CONST_POLY_INT: + case CONST_FIXED: + gcc_unreachable (); + + default: + break; + } + + rtx x = rtx_alloc (code); + if (!always_void_p (code)) + { + if (mode == NUM_MACHINE_MODES) + mode = get_mode (); + PUT_MODE_RAW (x, mode); + } + + const char *fmt = GET_RTX_FORMAT (code); + for (unsigned int i = 0; fmt[i]; ++i) + switch (fmt[i]) + { + /* Please keep these cases in sync with + gengenrtl.cc:type_from_format. */ + + case 'i': + XINT (x, i) = get_uint (); + break; + + case 'L': + case 'w': + case 'p': + case 's': + gcc_unreachable (); + + case 'e': case 'u': + XEXP (x, i) = get_rtx (); + break; + + case 'E': + XVEC (x, i) = get_rtvec (); + break; + + case 't': + case 'B': + default: + gcc_unreachable (); + } + + return x; +} + +/* Read an encoded rtvec. */ + +rtvec +rtx_expander::get_rtvec () +{ + unsigned int len = get_uint (); + rtvec v = rtvec_alloc (len); + for (unsigned int i = 0; i < len; ++i) + RTVEC_ELT (v, i) = get_rtx (); + return v; +} + +/* Read and emit an encoded sequence of instructions. */ + +void +rtx_expander::expand_seq () +{ + unsigned int len = get_uint (); + for (unsigned int i = 0; i < len; ++i) + emit (get_rtx (), i < len - 1); +} + +/* Read an rtx from the bytecode in SEQ, which was generated by genemit.cc. + Replace operand placeholders with the values given in OPERANDS. */ + +rtx +expand_rtx (const uint8_t *seq, rtx *operands) +{ + return rtx_expander (seq, operands).get_rtx (); +} + +/* Read and emit a sequence of instructions from the bytecode in SEQ, + which was generated by genemit.cc. Replace operand placeholders with + the values given in OPERANDS. */ + +rtx_insn * +complete_seq (const uint8_t *seq, rtx *operands) +{ + rtx_expander (seq, operands).expand_seq (); + return end_sequence (); +} + /* Initialize fields of rtl_data related to stack alignment. */ void diff --git a/gcc/genemit.cc b/gcc/genemit.cc index 7cdd9eb1d37..9ed82029391 100644 --- a/gcc/genemit.cc +++ b/gcc/genemit.cc @@ -57,178 +57,132 @@ static bool nofail_optabs[NUM_OPTABS]; /* A list of the md constructs that need a gen_* function. */ static vec<md_rtx_info> queue; -static void -print_code (RTX_CODE code, FILE *file) -{ - const char *p1; - for (p1 = GET_RTX_NAME (code); *p1; p1++) - fprintf (file, "%c", TOUPPER (*p1)); -} +unsigned FIRST_CODE = (unsigned) expand_opcode::FIRST_CODE; /* A structure used to generate code for a particular expansion. */ struct generator { - generator (rtx_code, char *, const md_rtx_info &, FILE *); + generator (const md_rtx_info &info) : info (info) {} - void gen_rtx_scratch (rtx); - void gen_exp (rtx); - void gen_emit_seq (rtvec); + void add_uint (uint64_t); + void add_opcode (expand_opcode opcode) { add_uint ((unsigned) opcode); } + void add_code (rtx_code code) { add_uint (FIRST_CODE + (unsigned) code); } + void add_match_operator (machine_mode, int, rtvec); + void add_exp (rtx); + void add_vec (rtvec); - /* The type of subroutine that we're expanding. */ - rtx_code subroutine_type; - - /* Index N indicates that the original operand N has already been used to - replace a MATCH_OPERATOR or MATCH_DUP, and so any further replacements - must make a copy. */ - char *used; + const char *gen_table (FILE *, const char *); + const char *gen_exp (FILE *, rtx); + const char *gen_emit_seq (FILE *, rtvec); /* The construct that we're expanding. */ const md_rtx_info info; - /* The output file. */ - FILE *file; + /* Used to build up the encoding of the expanded rtx sequence. */ + auto_vec<uint8_t> bytes; }; -generator::generator (rtx_code subroutine_type, char *used, - const md_rtx_info &info, FILE *file) - : subroutine_type (subroutine_type), - used (used), - info (info), - file (file) -{} +/* Add VALUE to the encoding using "BEB128" (big-endian version of LEB128). + This is slightly easier for the consumer. */ void -generator::gen_rtx_scratch (rtx x) +generator::add_uint (uint64_t value) { - if (subroutine_type == DEFINE_PEEPHOLE2) + int shift = 0; + while ((value >> shift >> 7) > 0) + shift += 7; + do { - fprintf (file, "operands[%d]", XINT (x, 0)); + bytes.safe_push (((value >> shift) & 127) | (shift > 0 ? 128 : 0)); + shift -= 7; } - else + while (shift >= 0); +} + +/* Add the rtx expansion of a MATCH_OPERATOR or MATCH_OP_DUP. OPNO is the + number of the matched operand. MODE is the mode that the rtx should have, + or NUM_MACHINE_MODES if the operand's original mode should be retained. + VEC is the vector of suboperands, which replace those of the original + operand. */ + +void +generator::add_match_operator (machine_mode mode, int opno, rtvec vec) +{ + if (mode != NUM_MACHINE_MODES) { - fprintf (file, "gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x))); + add_opcode (expand_opcode::MATCH_OPERATOR_WITH_MODE); + add_uint (mode); } + else + add_opcode (expand_opcode::MATCH_OPERATOR); + add_uint (opno); + for (int i = 0; i < GET_NUM_ELEM (vec); i++) + add_exp (RTVEC_ELT (vec, i)); } -/* Print a C expression to construct an RTX just like X, - substituting any operand references appearing within. */ +/* Add the expansion of X to the encoding. */ void -generator::gen_exp (rtx x) +generator::add_exp (rtx x) { - RTX_CODE code; - int i; - int len; - const char *fmt; - const char *sep = ""; - if (x == 0) { - fprintf (file, "NULL_RTX"); + add_opcode (expand_opcode::NO_RTX); return; } - code = GET_CODE (x); - + auto code = GET_CODE (x); switch (code) { case MATCH_OPERAND: case MATCH_DUP: - if (used[XINT (x, 0)]) - { - fprintf (file, "copy_rtx (operands[%d])", XINT (x, 0)); - return; - } - used[XINT (x, 0)] = 1; - fprintf (file, "operands[%d]", XINT (x, 0)); + add_opcode (expand_opcode::MATCH_OPERAND); + add_uint (XINT (x, 0)); return; case MATCH_OP_DUP: - fprintf (file, "gen_rtx_fmt_"); - for (i = 0; i < XVECLEN (x, 1); i++) - fprintf (file, "e"); - fprintf (file, " (GET_CODE (operands[%d]), ", XINT (x, 0)); if (GET_MODE (x) == VOIDmode) - fprintf (file, "GET_MODE (operands[%d])", XINT (x, 0)); + add_match_operator (NUM_MACHINE_MODES, XINT (x, 0), XVEC (x, 1)); else - fprintf (file, "%smode", GET_MODE_NAME (GET_MODE (x))); - for (i = 0; i < XVECLEN (x, 1); i++) - { - fprintf (file, ",\n\t\t"); - gen_exp (XVECEXP (x, 1, i)); - } - fprintf (file, ")"); + add_match_operator (GET_MODE (x), XINT (x, 0), XVEC (x, 1)); return; case MATCH_OPERATOR: - fprintf (file, "gen_rtx_fmt_"); - for (i = 0; i < XVECLEN (x, 2); i++) - fprintf (file, "e"); - fprintf (file, " (GET_CODE (operands[%d])", XINT (x, 0)); - fprintf (file, ", %smode", GET_MODE_NAME (GET_MODE (x))); - for (i = 0; i < XVECLEN (x, 2); i++) - { - fprintf (file, ",\n\t\t"); - gen_exp (XVECEXP (x, 2, i)); - } - fprintf (file, ")"); + add_match_operator (GET_MODE (x), XINT (x, 0), XVEC (x, 2)); return; case MATCH_PARALLEL: case MATCH_PAR_DUP: - fprintf (file, "operands[%d]", XINT (x, 0)); + add_opcode (expand_opcode::MATCH_PARALLEL); + add_uint (XINT (x, 0)); return; case MATCH_SCRATCH: - gen_rtx_scratch (x); + add_code (SCRATCH); + add_uint (GET_MODE (x)); return; - case PC: - fprintf (file, "pc_rtx"); - return; - case RETURN: - fprintf (file, "ret_rtx"); - return; - case SIMPLE_RETURN: - fprintf (file, "simple_return_rtx"); - return; case CLOBBER: if (REG_P (XEXP (x, 0))) { - fprintf (file, "gen_hard_reg_clobber (%smode, %i)", - GET_MODE_NAME (GET_MODE (XEXP (x, 0))), - REGNO (XEXP (x, 0))); + add_opcode (expand_opcode::CLOBBER_REG); + add_uint (GET_MODE (XEXP (x, 0))); + add_uint (REGNO (XEXP (x, 0))); return; } break; case CONST_INT: - if (INTVAL (x) == 0) - fprintf (file, "const0_rtx"); - else if (INTVAL (x) == 1) - fprintf (file, "const1_rtx"); - else if (INTVAL (x) == -1) - fprintf (file, "constm1_rtx"); - else if (-MAX_SAVED_CONST_INT <= INTVAL (x) - && INTVAL (x) <= MAX_SAVED_CONST_INT) - fprintf (file, "const_int_rtx[MAX_SAVED_CONST_INT + (%d)]", - (int) INTVAL (x)); - else if (INTVAL (x) == STORE_FLAG_VALUE) - fprintf (file, "const_true_rtx"); - else - { - fprintf (file, "GEN_INT ("); - fprintf (file, HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x)); - fprintf (file, ")"); - } + add_code (CONST_INT); + add_uint (UINTVAL (x)); return; case CONST_DOUBLE: /* Handle `const_double_zero' rtx. */ if (CONST_DOUBLE_REAL_VALUE (x)->cl == rvc_zero) { - fprintf (file, "CONST_DOUBLE_ATOF (\"0\", %smode)", - GET_MODE_NAME (GET_MODE (x))); + add_code (CONST_DOUBLE); + add_uint (GET_MODE (x)); return; } /* Fall through. */ @@ -242,30 +196,24 @@ generator::gen_exp (rtx x) break; } - fprintf (file, "gen_rtx_"); - print_code (code, file); - fprintf (file, " ("); + add_code (code); if (!always_void_p (code)) - { - fprintf (file, "%smode", GET_MODE_NAME (GET_MODE (x))); - sep = ",\n\t"; - } + add_uint (GET_MODE (x)); - fmt = GET_RTX_FORMAT (code); - len = GET_RTX_LENGTH (code); - for (i = 0; i < len; i++) + auto fmt = GET_RTX_FORMAT (code); + unsigned int len = GET_RTX_LENGTH (code); + for (unsigned int i = 0; i < len; i++) { if (fmt[i] == '0') break; - fputs (sep, file); switch (fmt[i]) { case 'e': case 'u': - gen_exp (XEXP (x, i)); + add_exp (XEXP (x, i)); break; case 'i': - fprintf (file, "%u", XINT (x, i)); + add_uint (XUINT (x, i)); break; case 'L': @@ -275,61 +223,69 @@ generator::gen_exp (rtx x) break; case 'r': - fprintf (file, "%u", REGNO (x)); + add_uint (REGNO (x)); break; case 'p': /* We don't have a way of parsing polynomial offsets yet, and hopefully never will. */ - fprintf (file, "%d", SUBREG_BYTE (x).to_constant ()); + add_uint (SUBREG_BYTE (x).to_constant ()); break; case 'E': - { - int j; - fprintf (file, "gen_rtvec (%d", XVECLEN (x, i)); - for (j = 0; j < XVECLEN (x, i); j++) - { - fprintf (file, ",\n\t\t"); - gen_exp (XVECEXP (x, i, j)); - } - fprintf (file, ")"); - break; - } + add_vec (XVEC (x, i)); + break; default: gcc_unreachable (); } - sep = ",\n\t"; } - fprintf (file, ")"); } -/* Output code to emit the instruction patterns in VEC, with each element - becoming a separate instruction. */ +/* Add the expansion of rtx vector VEC to the encoding. */ void -generator::gen_emit_seq (rtvec vec) +generator::add_vec (rtvec vec) { - for (int i = 0, len = GET_NUM_ELEM (vec); i < len; ++i) - { - bool last_p = (i == len - 1); - rtx next = RTVEC_ELT (vec, i); - if (const char *name = get_emit_function (next)) - { - fprintf (file, " %s (", name); - gen_exp (next); - fprintf (file, ");\n"); - if (!last_p && needs_barrier_p (next)) - fprintf (file, " emit_barrier ();"); - } - else - { - fprintf (file, " emit ("); - gen_exp (next); - fprintf (file, ", %s);\n", last_p ? "false" : "true"); - } - } + add_uint (GET_NUM_ELEM (vec)); + for (int i = 0; i < GET_NUM_ELEM (vec); ++i) + add_exp (RTVEC_ELT (vec, i)); +} + +/* Emit the encoding as a static C++ array called NAME. Return NAME. */ + +const char * +generator::gen_table (FILE *file, const char *name) +{ + fprintf (file, " static const uint8_t %s[] = {", name); + for (size_t i = 0; i < bytes.length (); ++i) + fprintf (file, "%s%s 0x%02x", + i == 0 ? "" : ",", + i % 8 == 0 ? "\n " : "", + bytes[i]); + fprintf (file, "\n };\n"); + return name; +} + +/* Output the code necessary for generating rtx X and return the name + of the C++ array that contains the encoding. */ + +const char * +generator::gen_exp (FILE *file, rtx x) +{ + add_exp (x); + return gen_table (file, "expand_encoding"); +} + +/* Output the code necessary for emitting each element of VEC as a separate + instruction. Return the name of the C++ array that contains the + encoding. */ + +const char * +generator::gen_emit_seq (FILE *file, rtvec vec) +{ + add_vec (vec); + return gen_table (file, "expand_encoding"); } /* Emit the given C code to the output file. The code is allowed to @@ -340,12 +296,11 @@ static void emit_c_code (const char *code, bool can_fail_p, const char *name, FILE *file) { if (can_fail_p) - fprintf (file, "#define FAIL return (end_sequence (), _val)\n"); + fprintf (file, "#define FAIL return (end_sequence (), nullptr)\n"); else fprintf (file, "#define FAIL _Pragma (\"GCC error \\\"%s cannot FAIL\\\"\")" " (void)0\n", name); - fprintf (file, "#define DONE return (_val = get_insns (), " - "end_sequence (), _val)\n"); + fprintf (file, "#define DONE return end_sequence ()\n"); rtx_reader_ptr->print_md_ptr_loc (code, file); fprintf (file, "%s\n", code); @@ -453,9 +408,9 @@ maybe_queue_insn (const md_rtx_info &info) /* Output the function name, argument declarations, and initial function body for a pattern called NAME, given that it has the properties - in STATS. */ + in STATS. Return the C++ expression for the operands array. */ -static void +static const char * start_gen_insn (FILE *file, const char *name, const pattern_stats &stats) { fprintf (file, "rtx\ngen_%s (", name); @@ -473,10 +428,17 @@ start_gen_insn (FILE *file, const char *name, const pattern_stats &stats) for (int i = 0; i < stats.num_generator_args; i++) fprintf (file, "%s operand%d", i == 0 ? "" : ",", i); fprintf (file, " };\n"); + return "operands"; + } + + if (stats.num_operand_vars != 0) + { + fprintf (file, " rtx operands[%d] ATTRIBUTE_UNUSED;\n", + stats.num_operand_vars); + return "operands"; } - else if (stats.num_operand_vars != 0) - fprintf (file, " rtx operands[%d] ATTRIBUTE_UNUSED;\n", - stats.num_operand_vars); + + return "nullptr"; } /* Generate the `gen_...' function for a DEFINE_INSN. */ @@ -493,16 +455,13 @@ gen_insn (const md_rtx_info &info, FILE *file) fatal_at (info.loc, "match_dup operand number has no match_operand"); /* Output the function name and argument declarations. */ - start_gen_insn (file, XSTR (insn, 0), stats); + const char *operands = start_gen_insn (file, XSTR (insn, 0), stats); /* Output code to construct and return the rtl for the instruction body. */ rtx pattern = add_implicit_parallel (XVEC (insn, 1)); - char *used = XCNEWVEC (char, stats.num_generator_args); - fprintf (file, " return "); - generator (DEFINE_INSN, used, info, file).gen_exp (pattern); - fprintf (file, ";\n}\n\n"); - XDELETEVEC (used); + const char *table = generator (info).gen_exp (file, pattern); + fprintf (file, " return expand_rtx (%s, %s);\n}\n\n", table, operands); } /* Process and queue the DEFINE_EXPAND in INFO. */ @@ -525,7 +484,6 @@ static void gen_expand (const md_rtx_info &info, FILE *file) { struct pattern_stats stats; - char *used; /* Find out how many operands this function has. */ rtx expand = info.def; @@ -536,7 +494,7 @@ gen_expand (const md_rtx_info &info, FILE *file) "numbers above all other operands", XSTR (expand, 0)); /* Output the function name and argument declarations. */ - start_gen_insn (file, XSTR (expand, 0), stats); + const char *operands = start_gen_insn (file, XSTR (expand, 0), stats); /* If we don't have any C code to write, only one insn is being written, and no MATCH_DUPs are present, we can just return the desired insn @@ -545,16 +503,12 @@ gen_expand (const md_rtx_info &info, FILE *file) && stats.max_opno >= stats.max_dup_opno && XVECLEN (expand, 1) == 1) { - used = XCNEWVEC (char, stats.num_operand_vars); - fprintf (file, " return "); - generator (DEFINE_EXPAND, used, info, file) - .gen_exp (XVECEXP (expand, 1, 0)); - fprintf (file, ";\n}\n\n"); - XDELETEVEC (used); + rtx pattern = XVECEXP (expand, 1, 0); + const char *table = generator (info).gen_exp (file, pattern); + fprintf (file, " return expand_rtx (%s, %s);\n}\n\n", table, operands); return; } - fprintf (file, " rtx_insn *_val = 0;\n"); fprintf (file, " start_sequence ();\n"); /* The fourth operand of DEFINE_EXPAND is some code to be executed @@ -582,16 +536,8 @@ gen_expand (const md_rtx_info &info, FILE *file) fprintf (file, " }\n"); } - used = XCNEWVEC (char, stats.num_operand_vars); - generator (DEFINE_EXPAND, used, info, file).gen_emit_seq (XVEC (expand, 1)); - XDELETEVEC (used); - - /* Call `get_insns' to extract the list of all the - insns emitted within this gen_... function. */ - - fprintf (file, " _val = get_insns ();\n"); - fprintf (file, " end_sequence ();\n"); - fprintf (file, " return _val;\n}\n\n"); + const char *table = generator (info).gen_emit_seq (file, XVEC (expand, 1)); + fprintf (file, " return complete_seq (%s, %s);\n}\n\n", table, operands); } /* Process and queue the DEFINE_SPLIT or DEFINE_PEEPHOLE2 in INFO. */ @@ -621,13 +567,11 @@ gen_split (const md_rtx_info &info, FILE *file) const char *const name = ((GET_CODE (split) == DEFINE_PEEPHOLE2) ? "peephole2" : "split"); const char *unused; - char *used; /* Find out how many operands this function has. */ get_pattern_stats (&stats, XVEC (split, 2)); unused = (stats.num_operand_vars == 0 ? " ATTRIBUTE_UNUSED" : ""); - used = XCNEWVEC (char, stats.num_operand_vars); /* Output the prototype, function name and argument declarations. */ if (GET_CODE (split) == DEFINE_PEEPHOLE2) @@ -648,9 +592,6 @@ gen_split (const md_rtx_info &info, FILE *file) } fprintf (file, "{\n"); - /* Declare all local variables. */ - fprintf (file, " rtx_insn *_val = NULL;\n"); - if (GET_CODE (split) == DEFINE_PEEPHOLE2) output_peephole2_scratches (split, file); @@ -671,17 +612,8 @@ gen_split (const md_rtx_info &info, FILE *file) if (XSTR (split, 3)) emit_c_code (XSTR (split, 3), true, name, file); - generator (GET_CODE (split), used, info, file) - .gen_emit_seq (XVEC (split, 2)); - - /* Call `get_insns' to make a list of all the - insns emitted within this gen_... function. */ - - fprintf (file, " _val = get_insns ();\n"); - fprintf (file, " end_sequence ();\n"); - fprintf (file, " return _val;\n}\n\n"); - - free (used); + const char *table = generator (info).gen_emit_seq (file, XVEC (split, 2)); + fprintf (file, " return complete_seq (%s, %s);\n}\n\n", table, "operands"); } /* Write a function, `add_clobbers', that is given a PARALLEL of sufficient diff --git a/gcc/gengenrtl.cc b/gcc/gengenrtl.cc index 8cd9d2832d0..4c1c287ecd7 100644 --- a/gcc/gengenrtl.cc +++ b/gcc/gengenrtl.cc @@ -136,7 +136,10 @@ always_void_p (int idx) /* Return nonzero if the RTL code given by index IDX is one that we should generate a gen_rtx_raw_FOO macro for, not gen_rtx_FOO (because gen_rtx_FOO - is a wrapper in emit-rtl.cc). */ + is a wrapper in emit-rtl.cc). + + This list of codes needs to be kept in sync with the switch statement + in emit-rtl.cc:rtx_expander::get_rtx. */ static int special_rtx (int idx) @@ -156,7 +159,10 @@ special_rtx (int idx) /* Return nonzero if the RTL code given by index IDX is one that we should generate no macro for at all (because gen_rtx_FOO is never used or - cannot have the obvious interface). */ + cannot have the obvious interface). + + This list of codes needs to be kept in sync with the switch statement + in emit-rtl.cc:rtx_expander::get_rtx. */ static int excluded_rtx (int idx) diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc index ac0132860a9..b4a2b2b21fc 100644 --- a/gcc/gensupport.cc +++ b/gcc/gensupport.cc @@ -3764,16 +3764,6 @@ get_emit_function (rtx x) } } -/* Return true if we must emit a barrier after pattern X. */ - -bool -needs_barrier_p (rtx x) -{ - return (GET_CODE (x) == SET - && GET_CODE (SET_DEST (x)) == PC - && GET_CODE (SET_SRC (x)) == LABEL_REF); -} - #define NS "NULL" #define ZS "'\\0'" #define OPTAB_CL(o, p, c, b, l) { #o, p, #b, ZS, #l, o, c, UNKNOWN, 1 }, diff --git a/gcc/gensupport.h b/gcc/gensupport.h index 7a59dd357b0..c9b07991c09 100644 --- a/gcc/gensupport.h +++ b/gcc/gensupport.h @@ -229,7 +229,6 @@ extern void get_pattern_stats (struct pattern_stats *ranges, rtvec vec); extern void compute_test_codes (rtx, file_location, char *); extern file_location get_file_location (rtx); extern const char *get_emit_function (rtx); -extern bool needs_barrier_p (rtx); extern bool find_optab (optab_pattern *, const char *); extern FILE *choose_output (const vec<FILE *> &, unsigned &); diff --git a/gcc/rtl.h b/gcc/rtl.h index 5623a4b06b4..7049ed775e8 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2074,7 +2074,17 @@ const_vector_encoded_nelts (const_rtx x) inline bool always_void_p (enum rtx_code code) { - return code == SET; + switch (code) + { + case SET: + case PC: + case RETURN: + case SIMPLE_RETURN: + return true; + + default: + return false; + } } /* A structure to hold all available cost information about an rtl @@ -3020,6 +3030,36 @@ extern enum rtx_code classify_insn (rtx); extern void dump_rtx_statistics (void); /* In emit-rtl.cc */ + +/* Opcodes used in the bytecode generated by genemit.cc. */ +enum class expand_opcode { + /* NULL_RTX. */ + NO_RTX, + + /* A (match_operand N) or (match_dup N). Followed by the operand number. */ + MATCH_OPERAND, + + /* A (match_operator N) or (match_op_dup N) that preserves the original mode. + Followed by the operand number. */ + MATCH_OPERATOR, + + /* A (match_operator N) or (match_op_dup N) that overrides the original mode. + Followed by the new mode and by the operand number. */ + MATCH_OPERATOR_WITH_MODE, + + /* A (match_parallel N) or (match_par_dup N). Followed by the operand + number. */ + MATCH_PARALLEL, + + /* A (clobber (reg:M R)). Followed by M and R. */ + CLOBBER_REG, + + /* FIRST_CODE + X represents a normal rtx with code X. */ + FIRST_CODE +}; + +extern rtx expand_rtx (const uint8_t *, rtx *); +extern rtx_insn *complete_seq (const uint8_t *, rtx *); extern rtx copy_rtx_if_shared (rtx); /* In rtl.cc */ -- 2.43.0