From: Segher Boessenkool Date: Tue, 12 May 2015 13:42:21 +0000 (+0200) Subject: combine.c (recog_for_combine_1): New function, factored out from recog_for_combine. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=45ce0f05e0d77adccc0d91fcc8404c6f37138526;p=gcc.git combine.c (recog_for_combine_1): New function, factored out from recog_for_combine. * combine.c (recog_for_combine_1): New function, factored out from recog_for_combine. (change_zero_ext): New function. (recog_for_combine): If recog fails, try again with the pattern modified by change_zero_ext; if that still fails, restore the pattern. From-SVN: r223067 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 58b5fc34b32..f084795cda9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2015-05-12 Segher Boessenkool + + * combine.c (recog_for_combine_1): New function, factored out + from recog_for_combine. + (change_zero_ext): New function. + (recog_for_combine): If recog fails, try again with the pattern + modified by change_zero_ext; if that still fails, restore the + pattern. + 2015-05-12 Segher Boessenkool * combine.c (get_undo_marker): New function. diff --git a/gcc/combine.c b/gcc/combine.c index 4b6e39f4442..1c1a74fdaa6 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -10879,21 +10879,11 @@ simplify_shift_const (rtx x, enum rtx_code code, machine_mode result_mode, } -/* Like recog, but we receive the address of a pointer to a new pattern. - We try to match the rtx that the pointer points to. - If that fails, we may try to modify or replace the pattern, - storing the replacement into the same pointer object. - - Modifications include deletion or addition of CLOBBERs. - - PNOTES is a pointer to a location where any REG_UNUSED notes added for - the CLOBBERs are placed. - - The value is the final insn code from the pattern ultimately matched, - or -1. */ +/* A subroutine of recog_for_combine. See there for arguments and + return value. */ static int -recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) +recog_for_combine_1 (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) { rtx pat = *pnewpat; rtx pat_without_clobbers; @@ -11040,6 +11030,110 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) return insn_code_number; } + +/* Change every ZERO_EXTRACT and ZERO_EXTEND of a SUBREG that can be + expressed as an AND and maybe an LSHIFTRT, to that formulation. + Return whether anything was so changed. */ + +static bool +change_zero_ext (rtx *src) +{ + bool changed = false; + + subrtx_ptr_iterator::array_type array; + FOR_EACH_SUBRTX_PTR (iter, array, src, NONCONST) + { + rtx x = **iter; + machine_mode mode = GET_MODE (x); + int size; + + if (GET_CODE (x) == ZERO_EXTRACT + && CONST_INT_P (XEXP (x, 1)) + && CONST_INT_P (XEXP (x, 2)) + && GET_MODE (XEXP (x, 0)) == mode) + { + size = INTVAL (XEXP (x, 1)); + + int start = INTVAL (XEXP (x, 2)); + if (BITS_BIG_ENDIAN) + start = GET_MODE_PRECISION (mode) - size - start; + + x = gen_rtx_LSHIFTRT (mode, XEXP (x, 0), GEN_INT (start)); + } + else if (GET_CODE (x) == ZERO_EXTEND + && GET_CODE (XEXP (x, 0)) == SUBREG + && GET_MODE (SUBREG_REG (XEXP (x, 0))) == mode + && subreg_lowpart_p (XEXP (x, 0))) + { + size = GET_MODE_PRECISION (GET_MODE (XEXP (x, 0))); + x = SUBREG_REG (XEXP (x, 0)); + } + else + continue; + + unsigned HOST_WIDE_INT mask = 1; + mask <<= size; + mask--; + + x = gen_rtx_AND (mode, x, GEN_INT (mask)); + + SUBST (**iter, x); + changed = true; + } + + return changed; +} + +/* Like recog, but we receive the address of a pointer to a new pattern. + We try to match the rtx that the pointer points to. + If that fails, we may try to modify or replace the pattern, + storing the replacement into the same pointer object. + + Modifications include deletion or addition of CLOBBERs. If the + instruction will still not match, we change ZERO_EXTEND and ZERO_EXTRACT + to the equivalent AND and perhaps LSHIFTRT patterns, and try with that + (and undo if that fails). + + PNOTES is a pointer to a location where any REG_UNUSED notes added for + the CLOBBERs are placed. + + The value is the final insn code from the pattern ultimately matched, + or -1. */ + +static int +recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes) +{ + rtx pat = PATTERN (insn); + int insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes); + if (insn_code_number >= 0 || check_asm_operands (pat)) + return insn_code_number; + + void *marker = get_undo_marker (); + bool changed = false; + + if (GET_CODE (pat) == SET) + changed = change_zero_ext (&SET_SRC (pat)); + else if (GET_CODE (pat) == PARALLEL) + { + int i; + for (i = 0; i < XVECLEN (pat, 0); i++) + { + rtx set = XVECEXP (pat, 0, i); + if (GET_CODE (set) == SET) + changed |= change_zero_ext (&SET_SRC (set)); + } + } + + if (changed) + { + insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes); + + if (insn_code_number < 0) + undo_to_marker (marker); + } + + return insn_code_number; +} /* Like gen_lowpart_general but for use by combine. In combine it is not possible to create any new pseudoregs. However, it is