diff options
Diffstat (limited to 'gcc/combine.c')
-rw-r--r-- | gcc/combine.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/gcc/combine.c b/gcc/combine.c index 5c763b4..24418df 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -2620,6 +2620,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, int i; int ngood = 0; int nshift = 0; + rtx set0, set3; if (!flag_expensive_optimizations) return 0; @@ -2643,6 +2644,34 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, || GET_CODE (src) == LSHIFTRT) nshift++; } + + /* If I0 loads a memory and I3 sets the same memory, then I2 and I3 + are likely manipulating its value. Ideally we'll be able to combine + all four insns into a bitfield insertion of some kind. + + Note the source in I0 might be inside a sign/zero extension and the + memory modes in I0 and I3 might be different. So extract the address + from the destination of I3 and search for it in the source of I0. + + In the event that there's a match but the source/dest do not actually + refer to the same memory, the worst that happens is we try some + combinations that we wouldn't have otherwise. */ + if ((set0 = single_set (i0)) + /* Ensure the source of SET0 is a MEM, possibly buried inside + an extension. */ + && (GET_CODE (SET_SRC (set0)) == MEM + || ((GET_CODE (SET_SRC (set0)) == ZERO_EXTEND + || GET_CODE (SET_SRC (set0)) == SIGN_EXTEND) + && GET_CODE (XEXP (SET_SRC (set0), 0)) == MEM)) + && (set3 = single_set (i3)) + /* Ensure the destination of SET3 is a MEM. */ + && GET_CODE (SET_DEST (set3)) == MEM + /* Would it be better to extract the base address for the MEM + in SET3 and look for that? I don't have cases where it matters + but I could envision such cases. */ + && rtx_referenced_p (XEXP (SET_DEST (set3), 0), SET_SRC (set0))) + ngood += 2; + if (ngood < 2 && nshift < 2) return 0; } @@ -9272,6 +9301,13 @@ make_field_assignment (rtx x) to the appropriate position, force it to the required mode, and make the extraction. Check for the AND in both operands. */ + /* One or more SUBREGs might obscure the constant-position field + assignment. The first one we are likely to encounter is an outer + narrowing SUBREG, which we can just strip for the purposes of + identifying the constant-field assignment. */ + if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)) + src = SUBREG_REG (src); + if (GET_CODE (src) != IOR && GET_CODE (src) != XOR) return x; @@ -9282,10 +9318,38 @@ make_field_assignment (rtx x) && CONST_INT_P (XEXP (rhs, 1)) && rtx_equal_for_field_assignment_p (XEXP (rhs, 0), dest)) c1 = INTVAL (XEXP (rhs, 1)), other = lhs; + /* The second SUBREG that might get in the way is a paradoxical + SUBREG around the first operand of the AND. We want to + pretend the operand is as wide as the destination here. We + do this by creating a new MEM in the wider mode for the sole + purpose of the call to rtx_equal_for_field_assignment_p. Also + note this trick only works for MEMs. */ + else if (GET_CODE (rhs) == AND + && paradoxical_subreg_p (XEXP (rhs, 0)) + && GET_CODE (SUBREG_REG (XEXP (rhs, 0))) == MEM + && CONST_INT_P (XEXP (rhs, 1)) + && rtx_equal_for_field_assignment_p (gen_rtx_MEM (GET_MODE (dest), + XEXP (SUBREG_REG (XEXP (rhs, 0)), 0)), + dest)) + c1 = INTVAL (XEXP (rhs, 1)), other = lhs; else if (GET_CODE (lhs) == AND && CONST_INT_P (XEXP (lhs, 1)) && rtx_equal_for_field_assignment_p (XEXP (lhs, 0), dest)) c1 = INTVAL (XEXP (lhs, 1)), other = rhs; + /* The second SUBREG that might get in the way is a paradoxical + SUBREG around the first operand of the AND. We want to + pretend the operand is as wide as the destination here. We + do this by creating a new MEM in the wider mode for the sole + purpose of the call to rtx_equal_for_field_assignment_p. Also + note this trick only works for MEMs. */ + else if (GET_CODE (lhs) == AND + && paradoxical_subreg_p (XEXP (lhs, 0)) + && GET_CODE (SUBREG_REG (XEXP (lhs, 0))) == MEM + && CONST_INT_P (XEXP (lhs, 1)) + && rtx_equal_for_field_assignment_p (gen_rtx_MEM (GET_MODE (dest), + XEXP (SUBREG_REG (XEXP (lhs, 0)), 0)), + dest)) + c1 = INTVAL (XEXP (lhs, 1)), other = rhs; else return x; |