From 9d2f8e16f5c514a0232698e12e6e5f8ffb72605d Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Mon, 1 Dec 2014 23:36:12 +0100 Subject: [PATCH] combine.c (is_parallel_of_n_reg_sets): New function. * combine.c (is_parallel_of_n_reg_sets): New function. (can_split_parallel_of_n_reg_sets): New function. (try_combine): If I2 is a PARALLEL of two SETs, split it into two insns if possible. From-SVN: r218248 --- gcc/ChangeLog | 7 +++++ gcc/combine.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 88cfeef98b2..fc5e2db1eec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2014-12-01 Segher Boessenkool + + * combine.c (is_parallel_of_n_reg_sets): New function. + (can_split_parallel_of_n_reg_sets): New function. + (try_combine): If I2 is a PARALLEL of two SETs, split it into + two insns if possible. + 2014-12-01 Tobias Burnus Jack Howarth diff --git a/gcc/combine.c b/gcc/combine.c index afcb91eedd0..b9319023c34 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -2461,6 +2461,59 @@ update_cfg_for_uncondjump (rtx_insn *insn) } } +/* Return whether INSN is a PARALLEL of exactly N register SETs followed + by an arbitrary number of CLOBBERs. */ +static bool +is_parallel_of_n_reg_sets (rtx_insn *insn, int n) +{ + rtx pat = PATTERN (insn); + + if (GET_CODE (pat) != PARALLEL) + return false; + + int len = XVECLEN (pat, 0); + if (len < n) + return false; + + int i; + for (i = 0; i < n; i++) + if (GET_CODE (XVECEXP (pat, 0, i)) != SET + || !REG_P (SET_DEST (XVECEXP (pat, 0, i)))) + return false; + for ( ; i < len; i++) + if (GET_CODE (XVECEXP (pat, 0, i)) != CLOBBER) + return false; + + return true; +} + +/* Return whether INSN, a PARALLEL of N register SETs (and maybe some + CLOBBERs), can be split into individual SETs in that order, without + changing semantics. */ +static bool +can_split_parallel_of_n_reg_sets (rtx_insn *insn, int n) +{ + if (!insn_nothrow_p (insn)) + return false; + + rtx pat = PATTERN (insn); + + int i, j; + for (i = 0; i < n; i++) + { + if (side_effects_p (SET_SRC (XVECEXP (pat, 0, i)))) + return false; + + rtx reg = SET_DEST (XVECEXP (pat, 0, i)); + + for (j = i + 1; j < n; j++) + if (reg_referenced_p (reg, XVECEXP (pat, 0, j))) + return false; + } + + return true; +} + /* Try to combine the insns I0, I1 and I2 into I3. Here I0, I1 and I2 appear earlier than I3. I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into @@ -2817,6 +2870,31 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, alloc_insn_link (i1, regno, LOG_LINKS (i2))); } } + + /* If I2 is a PARALLEL of two SETs of REGs (and perhaps some CLOBBERs), + make those two SETs separate I1 and I2 insns, and make an I0 that is + the original I1. */ + if (i0 == 0 + && is_parallel_of_n_reg_sets (i2, 2) + && can_split_parallel_of_n_reg_sets (i2, 2) + && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)), i2, i3) + && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 1)), i2, i3)) + { + /* If there is no I1, there is no I0 either. */ + i0 = i1; + + /* We make I1 with the same INSN_UID as I2. This gives it + the same DF_INSN_LUID for value tracking. Our fake I1 will + never appear in the insn stream so giving it the same INSN_UID + as I2 will not cause a problem. */ + + i1 = gen_rtx_INSN (VOIDmode, NULL, i2, BLOCK_FOR_INSN (i2), + XVECEXP (PATTERN (i2), 0, 0), INSN_LOCATION (i2), + -1, NULL_RTX); + INSN_UID (i1) = INSN_UID (i2); + + SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 1)); + } #endif /* Verify that I2 and I1 are valid for combining. */ -- 2.30.2