PR119966 showed that combine could generate unfoldable hardware subregs
for pru-unknown-elf. To fix, strengthen the checks performed by
validate_subreg.
The simplify_subreg_regno performs more validity checks than
the simple info.representable_p. Most importantly, the
targetm.hard_regno_mode_ok hook is called to ensure the hardware
register is valid in subreg's outer mode. This fixes the rootcause
for PR119966.
The checks for stack-related registers are bypassed because the i386
backend generates them, in this seemingly valid peephole optimization:
;; Attempt to always use XOR for zeroing registers (including FP modes).
(define_peephole2
[(set (match_operand 0 "general_reg_operand")
(match_operand 1 "const0_operand"))]
"GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
&& (! TARGET_USE_MOV0 || optimize_insn_for_size_p ())
&& peep2_regno_dead_p (0, FLAGS_REG)"
[(parallel [(set (match_dup 0) (const_int 0))
(clobber (reg:CC FLAGS_REG))])]
"operands[0] = gen_lowpart (word_mode, operands[0]);")
Testing done:
* No regressions were detected for C and C++ on x86_64-pc-linux-gnu.
* "contrib/compare-all-tests i386" showed no difference in code
generation.
* No regressions for pru-unknown-elf.
* Reverted
r16-809-gf725d6765373f7 to expose the now latent PR119966.
Then ensured pru-unknown-elf build is ok. Only two cases regressed
where rnreg pass transforms a valid hardware subreg into invalid
one. But I think that is not related to combine's PR119966:
gcc.c-torture/execute/
20040709-1.c
gcc.c-torture/execute/
20040709-2.c
PR target/119966
gcc/ChangeLog:
* emit-rtl.cc (validate_subreg): Call simplify_subreg_regno
instead of checking info.representable_p..
* rtl.h (simplify_subreg_regno): Add new argument
allow_stack_regs.
* rtlanal.cc (simplify_subreg_regno): Do not reject
stack-related registers if allow_stack_regs is true.
Co-authored-by: Richard Sandiford <richard.sandiford@arm.com>
Co-authored-by: Andrew Pinski <quic_apinski@quicinc.com>
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
/* Verify that the offset is representable. */
- /* For hard registers, we already have most of these rules collected in
- subreg_offset_representable_p. */
+ /* Ensure that subregs of hard registers can be folded. In other words,
+ the hardware register must be valid in the subreg's outer mode,
+ and consequently the subreg can be replaced with a hardware register. */
if (reg && REG_P (reg) && HARD_REGISTER_P (reg))
{
unsigned int regno = REGNO (reg);
else if (!REG_CAN_CHANGE_MODE_P (regno, imode, omode))
return false;
- return subreg_offset_representable_p (regno, imode, offset, omode);
+ /* Pass true to allow_stack_regs because targets like x86
+ expect to be able to take subregs of the stack pointer. */
+ return simplify_subreg_regno (regno, imode, offset, omode, true) >= 0;
}
/* Do not allow normal SUBREG with stricter alignment than the inner MEM.
poly_uint64, machine_mode);
extern unsigned int subreg_regno (const_rtx);
extern int simplify_subreg_regno (unsigned int, machine_mode,
- poly_uint64, machine_mode);
+ poly_uint64, machine_mode,
+ bool allow_stack_regs = false);
extern int lowpart_subreg_regno (unsigned int, machine_mode,
machine_mode);
extern unsigned int subreg_nregs (const_rtx);
can be simplified. Return -1 if the subreg can't be simplified.
- XREGNO is a hard register number. */
+ XREGNO is a hard register number. ALLOW_STACK_REGS is true if
+ we should allow subregs of stack_pointer_rtx, frame_pointer_rtx.
+ and arg_pointer_rtx (which are normally expected to be the unique
+ way of referring to their respective registers). */
+
int
simplify_subreg_regno (unsigned int xregno, machine_mode xmode,
- poly_uint64 offset, machine_mode ymode)
+ poly_uint64 offset, machine_mode ymode,
+ bool allow_stack_regs)
{
struct subreg_info info;
unsigned int yregno;
&& !REG_CAN_CHANGE_MODE_P (xregno, xmode, ymode))
return -1;
- /* We shouldn't simplify stack-related registers. */
- if ((!reload_completed || frame_pointer_needed)
- && xregno == FRAME_POINTER_REGNUM)
- return -1;
+ if (!allow_stack_regs)
+ {
+ /* We shouldn't simplify stack-related registers. */
+ if ((!reload_completed || frame_pointer_needed)
+ && xregno == FRAME_POINTER_REGNUM)
+ return -1;
- if (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
- && xregno == ARG_POINTER_REGNUM)
- return -1;
+ if (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ && xregno == ARG_POINTER_REGNUM)
+ return -1;
- if (xregno == STACK_POINTER_REGNUM
- /* We should convert hard stack register in LRA if it is
- possible. */
- && ! lra_in_progress)
- return -1;
+ if (xregno == STACK_POINTER_REGNUM
+ /* We should convert hard stack register in LRA if it is
+ possible. */
+ && ! lra_in_progress)
+ return -1;
+ }
/* Try to get the register offset. */
subreg_get_info (xregno, xmode, offset, ymode, &info);