gen_expand and gen_split have some fairly complex tests that really just repeat what's in classify_insn. This patch moves classify_insn to rtl.c, so that it's available to the generators. It also adds a generator-specific UNKNOWN return code for cases where we need to choose at (GCC) runtime.
This is preparing for a patch series that I'll post about soon. Bootstrapped & regression-tested on x86_64-linux-gnu. Also tested with config-list.mk. OK for the rtl bits? The test for whether a barrier is needed seems a little weak: what about indirect jumps, jumps with match_operand sources, or jumps in PARALLELs? That for another day though. At least this patch means we'll only have to update one place rather than two. Thanks, Richard gcc/ * rtl.h (classify_insn): Declare. * emit-rtl.c (classify_insn): Move to... * rtl.c: ...here and add generator support. * gensupport.h (get_emit_function, needs_barrier_p): Declare. * gensupport.c (get_emit_function, needs_barrier_p): New functions. * genemit.c (gen_emit_seq): New function. (gen_expand, gen_split): Use it. Index: gcc/rtl.h =================================================================== --- gcc/rtl.h 2015-06-13 10:37:47.781963830 +0100 +++ gcc/rtl.h 2015-06-13 10:38:55.640981540 +0100 @@ -2665,6 +2665,7 @@ extern rtvec rtvec_alloc (int); extern rtvec shallow_copy_rtvec (rtvec); extern bool shared_const_p (const_rtx); extern rtx copy_rtx (rtx); +extern enum rtx_code classify_insn (rtx); extern void dump_rtx_statistics (void); /* In emit-rtl.c */ Index: gcc/emit-rtl.c =================================================================== --- gcc/emit-rtl.c 2015-06-13 10:37:47.781963830 +0100 +++ gcc/emit-rtl.c 2015-06-13 10:38:55.638981628 +0100 @@ -5309,43 +5309,6 @@ set_dst_reg_note (rtx insn, enum reg_not return NULL_RTX; } -/* Return an indication of which type of insn should have X as a body. - The value is CODE_LABEL, INSN, CALL_INSN or JUMP_INSN. */ - -static enum rtx_code -classify_insn (rtx x) -{ - if (LABEL_P (x)) - return CODE_LABEL; - if (GET_CODE (x) == CALL) - return CALL_INSN; - if (ANY_RETURN_P (x)) - return JUMP_INSN; - if (GET_CODE (x) == SET) - { - if (SET_DEST (x) == pc_rtx) - return JUMP_INSN; - else if (GET_CODE (SET_SRC (x)) == CALL) - return CALL_INSN; - else - return INSN; - } - if (GET_CODE (x) == PARALLEL) - { - int j; - for (j = XVECLEN (x, 0) - 1; j >= 0; j--) - if (GET_CODE (XVECEXP (x, 0, j)) == CALL) - return CALL_INSN; - else if (GET_CODE (XVECEXP (x, 0, j)) == SET - && SET_DEST (XVECEXP (x, 0, j)) == pc_rtx) - return JUMP_INSN; - else if (GET_CODE (XVECEXP (x, 0, j)) == SET - && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL) - return CALL_INSN; - } - return INSN; -} - /* Emit the rtl pattern X as an appropriate kind of insn. If X is a label, it is simply added into the insn chain. */ Index: gcc/rtl.c =================================================================== --- gcc/rtl.c 2015-06-13 10:37:47.781963830 +0100 +++ gcc/rtl.c 2015-06-13 10:38:55.639981584 +0100 @@ -658,6 +658,54 @@ rtx_equal_p (const_rtx x, const_rtx y) return 1; } +/* Return an indication of which type of insn should have X as a body. + In generator files, this can be UNKNOWN if the answer is only known + at (GCC) runtime. Otherwise the value is CODE_LABEL, INSN, CALL_INSN + or JUMP_INSN. */ + +enum rtx_code +classify_insn (rtx x) +{ + if (LABEL_P (x)) + return CODE_LABEL; + if (GET_CODE (x) == CALL) + return CALL_INSN; + if (ANY_RETURN_P (x)) + return JUMP_INSN; + if (GET_CODE (x) == SET) + { + if (GET_CODE (SET_DEST (x)) == PC) + return JUMP_INSN; + else if (GET_CODE (SET_SRC (x)) == CALL) + return CALL_INSN; + else + return INSN; + } + if (GET_CODE (x) == PARALLEL) + { + int j; + for (j = XVECLEN (x, 0) - 1; j >= 0; j--) + if (GET_CODE (XVECEXP (x, 0, j)) == CALL) + return CALL_INSN; + else if (GET_CODE (XVECEXP (x, 0, j)) == SET + && GET_CODE (SET_DEST (XVECEXP (x, 0, j))) == PC) + return JUMP_INSN; + else if (GET_CODE (XVECEXP (x, 0, j)) == SET + && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL) + return CALL_INSN; + } +#ifdef GENERATOR_FILE + if (GET_CODE (x) == MATCH_OPERAND + || GET_CODE (x) == MATCH_OPERATOR + || GET_CODE (x) == MATCH_PARALLEL + || GET_CODE (x) == MATCH_OP_DUP + || GET_CODE (x) == MATCH_DUP + || GET_CODE (x) == PARALLEL) + return UNKNOWN; +#endif + return INSN; +} + void dump_rtx_statistics (void) { Index: gcc/gensupport.h =================================================================== --- gcc/gensupport.h 2015-06-13 10:38:52.370125288 +0100 +++ gcc/gensupport.h 2015-06-13 10:38:55.639981584 +0100 @@ -111,5 +111,7 @@ struct pattern_stats extern void get_pattern_stats (struct pattern_stats *ranges, rtvec vec); extern void compute_test_codes (rtx, int, char *); +extern const char *get_emit_function (rtx); +extern bool needs_barrier_p (rtx); #endif /* GCC_GENSUPPORT_H */ Index: gcc/gensupport.c =================================================================== --- gcc/gensupport.c 2015-06-13 10:38:52.370125288 +0100 +++ gcc/gensupport.c 2015-06-13 10:38:55.639981584 +0100 @@ -2983,3 +2983,37 @@ get_pattern_stats (struct pattern_stats MAX (stats->max_dup_opno, stats->max_scratch_opno)) + 1; } + +/* Return the emit_* function that should be used for pattern X. */ + +const char * +get_emit_function (rtx x) +{ + switch (classify_insn (x)) + { + case INSN: + return "emit_insn"; + + case CALL_INSN: + return "emit_call_insn"; + + case JUMP_INSN: + return "emit_jump_insn"; + + case UNKNOWN: + return "emit"; + + default: + gcc_unreachable (); + } +} + +/* 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); +} Index: gcc/genemit.c =================================================================== --- gcc/genemit.c 2015-06-13 10:38:52.369125332 +0100 +++ gcc/genemit.c 2015-06-13 10:38:55.639981584 +0100 @@ -268,6 +268,23 @@ gen_exp (rtx x, enum rtx_code subroutine } printf (")"); } + +/* Output code to emit the instruction patterns in VEC, with each element + becoming a separate instruction. USED is as for gen_exp. */ + +static void +gen_emit_seq (rtvec vec, char *used) +{ + for (int i = 0, len = GET_NUM_ELEM (vec); i < len; ++i) + { + rtx next = RTVEC_ELT (vec, i); + printf (" %s (", get_emit_function (next)); + gen_exp (next, DEFINE_EXPAND, used); + printf (");\n"); + if (needs_barrier_p (next)) + printf (" emit_barrier ();"); + } +} /* Generate the `gen_...' function for a DEFINE_INSN. */ @@ -475,49 +492,8 @@ gen_expand (rtx expand) printf (" }\n"); } - /* Output code to construct the rtl for the instruction bodies. - Use emit_insn to add them to the sequence being accumulated. - But don't do this if the user's code has set `no_more' nonzero. */ - used = XCNEWVEC (char, stats.num_operand_vars); - - for (i = 0; i < XVECLEN (expand, 1); i++) - { - rtx next = XVECEXP (expand, 1, i); - if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC) - || (GET_CODE (next) == PARALLEL - && ((GET_CODE (XVECEXP (next, 0, 0)) == SET - && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) - || ANY_RETURN_P (XVECEXP (next, 0, 0)))) - || ANY_RETURN_P (next)) - printf (" emit_jump_insn ("); - else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) - || GET_CODE (next) == CALL - || (GET_CODE (next) == PARALLEL - && GET_CODE (XVECEXP (next, 0, 0)) == SET - && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL) - || (GET_CODE (next) == PARALLEL - && GET_CODE (XVECEXP (next, 0, 0)) == CALL)) - printf (" emit_call_insn ("); - else if (LABEL_P (next)) - printf (" emit_label ("); - else if (GET_CODE (next) == MATCH_OPERAND - || GET_CODE (next) == MATCH_DUP - || GET_CODE (next) == MATCH_OPERATOR - || GET_CODE (next) == MATCH_OP_DUP - || GET_CODE (next) == MATCH_PARALLEL - || GET_CODE (next) == MATCH_PAR_DUP - || GET_CODE (next) == PARALLEL) - printf (" emit ("); - else - printf (" emit_insn ("); - gen_exp (next, DEFINE_EXPAND, used); - printf (");\n"); - if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC - && GET_CODE (SET_SRC (next)) == LABEL_REF) - printf (" emit_barrier ();"); - } - + gen_emit_seq (XVEC (expand, 1), used); XDELETEVEC (used); /* Call `get_insns' to extract the list of all the @@ -601,44 +577,7 @@ gen_split (rtx split) printf (" (void) operand%d;\n", i); } - /* Output code to construct the rtl for the instruction bodies. - Use emit_insn to add them to the sequence being accumulated. - But don't do this if the user's code has set `no_more' nonzero. */ - - for (i = 0; i < XVECLEN (split, 2); i++) - { - rtx next = XVECEXP (split, 2, i); - if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC) - || (GET_CODE (next) == PARALLEL - && GET_CODE (XVECEXP (next, 0, 0)) == SET - && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) - || ANY_RETURN_P (next)) - printf (" emit_jump_insn ("); - else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) - || GET_CODE (next) == CALL - || (GET_CODE (next) == PARALLEL - && GET_CODE (XVECEXP (next, 0, 0)) == SET - && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL) - || (GET_CODE (next) == PARALLEL - && GET_CODE (XVECEXP (next, 0, 0)) == CALL)) - printf (" emit_call_insn ("); - else if (LABEL_P (next)) - printf (" emit_label ("); - else if (GET_CODE (next) == MATCH_OPERAND - || GET_CODE (next) == MATCH_OPERATOR - || GET_CODE (next) == MATCH_PARALLEL - || GET_CODE (next) == MATCH_OP_DUP - || GET_CODE (next) == MATCH_DUP - || GET_CODE (next) == PARALLEL) - printf (" emit ("); - else - printf (" emit_insn ("); - gen_exp (next, GET_CODE (split), used); - printf (");\n"); - if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC - && GET_CODE (SET_SRC (next)) == LABEL_REF) - printf (" emit_barrier ();"); - } + gen_emit_seq (XVEC (split, 2), used); /* Call `get_insns' to make a list of all the insns emitted within this gen_... function. */