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
This commit is contained in:
parent
1bcc1e4102
commit
45ce0f05e0
|
@ -1,3 +1,12 @@
|
|||
2015-05-12 Segher Boessenkool <segher@kernel.crashing.org>
|
||||
|
||||
* 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 <segher@kernel.crashing.org>
|
||||
|
||||
* combine.c (get_undo_marker): New function.
|
||||
|
|
120
gcc/combine.c
120
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
|
||||
|
|
Loading…
Reference in New Issue