From: "dragan.mladjenovic" <dragan.mladjeno...@rt-rk.com> The fwprop1 introduces a new use of Y by replacing the (subreg:QI (reg:SI X)) with (reg:QI Y) preventing the optimization of zero_extend later during the combine. This patch prevents this replacement in two new cases.
A: (set (subreg:SI (reg:QI Y)) (zero_extract:SI Z (const_int 8) (const_int ?))) B: (set (reg:SI X) (zero_extend:SI (reg:QI Y))) C: (... (subreg:QI (reg:SI X)) ...) D: (... (reg:SI X) ...) A: (set (reg:SI Y) (zero_extract:SI Z (const_int 8) (const_int ?))) B: (set (reg:SI X) (zero_extend:SI (reg:QI Y))) C: (... (subreg:QI (reg:SI X)) ...) D: (... (reg:SI X) ...) gcc/ * fwprop.cc (free_load_extend): Renamed to ... (free_extend): Handle zero/sign_extract sources. (forward_propagate_subreg): Use free_extend. gcc/testsuite/ * gcc.target/mips/union-zext.c: New. Cherry-picked a76808b917661f102d4b5f6256f76a1a1e580676 from https://github.com/MIPS/gcc Signed-off-by: Dragan Mladjenovic <dragan.mladjeno...@rt-rk.com> Signed-off-by: Faraz Shahbazker <fshahbaz...@wavecomp.com> Signed-off-by: Aleksandar Rakic <aleksandar.ra...@htecgroup.com> --- gcc/fwprop.cc | 38 ++++++++++++++++++---- gcc/testsuite/gcc.target/mips/union-zext.c | 29 +++++++++++++++++ 2 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.target/mips/union-zext.c diff --git a/gcc/fwprop.cc b/gcc/fwprop.cc index 8cba6b7ce9f..717415a4fb6 100644 --- a/gcc/fwprop.cc +++ b/gcc/fwprop.cc @@ -614,15 +614,14 @@ try_fwprop_subst (use_info *use, set_info *def, /* For the given single_set INSN, containing SRC known to be a ZERO_EXTEND or SIGN_EXTEND of a register, return true if INSN - is redundant due to the register being set by a LOAD_EXTEND_OP - load from memory. */ + is redundant due to the register being set by ZERO_EXTRACT or + SIGN_EXTRACT of appropriate size or by LOAD_EXTEND_OP load + from memory. */ static bool -free_load_extend (rtx src, insn_info *insn) +free_extend (rtx src, insn_info *insn) { rtx reg = XEXP (src, 0); - if (load_extend_op (GET_MODE (reg)) != GET_CODE (src)) - return false; def_info *def = nullptr; for (use_info *use : insn->uses ()) @@ -644,10 +643,35 @@ free_load_extend (rtx src, insn_info *insn) { rtx patt = PATTERN (def_rtl); - if (GET_CODE (patt) == SET + if (GET_CODE (patt) != SET) + return false; + +#ifdef LOAD_EXTEND_OP + if (LOAD_EXTEND_OP (GET_MODE (reg)) == GET_CODE (src) && GET_CODE (SET_SRC (patt)) == MEM && rtx_equal_p (SET_DEST (patt), reg)) return true; +#endif + + int extract_code = GET_CODE (src) == ZERO_EXTEND + ? ZERO_EXTRACT : SIGN_EXTRACT; + + if (GET_CODE (SET_SRC (patt)) == extract_code + && GET_MODE (SET_SRC (patt)) == GET_MODE (src) + && INTVAL (XEXP (SET_SRC (patt), 1)) + <= GET_MODE_BITSIZE (GET_MODE (reg)).to_constant ()) + { + if (GET_CODE (SET_DEST (patt)) == SUBREG + && GET_MODE (SET_DEST (patt)) == GET_MODE (src) + && rtx_equal_p (XEXP (SET_DEST (patt), 0), reg)) + return true; + + if (REG_P (SET_DEST (patt)) + && GET_MODE (SET_DEST (patt)) == GET_MODE (src) + && REGNO (SET_DEST (patt)) == REGNO (reg)) + return true; + } + } return false; } @@ -709,7 +733,7 @@ forward_propagate_subreg (use_info *use, set_info *def, && REG_P (XEXP (src, 0)) && REGNO (XEXP (src, 0)) >= FIRST_PSEUDO_REGISTER && GET_MODE (XEXP (src, 0)) == use_mode - && !free_load_extend (src, def->insn ()) + && !free_extend (src, def->insn ()) && (targetm.mode_rep_extended (int_use_mode, src_mode) != (int) GET_CODE (src))) return try_fwprop_subst (use, def, loc, use_reg, XEXP (src, 0)); diff --git a/gcc/testsuite/gcc.target/mips/union-zext.c b/gcc/testsuite/gcc.target/mips/union-zext.c new file mode 100644 index 00000000000..6728d415f5a --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/union-zext.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "(HAS_INS) -mgp32" } */ +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */ +/* { dg-final { scan-assembler-not "\tandi\t"} } */ + +typedef struct bits +{ + unsigned B0:8, B1:8, B2:8, B3:8; +} bits_t; + +typedef union +{ + unsigned v; + bits_t b; +} bitfields_t; + +void * +strcpy (void *__restrict__ dst, const void *__restrict__ _a) +{ + unsigned x = *(unsigned *) _a; + bitfields_t bx; + bx.v = x; + + unsigned char v2 = (unsigned char) bx.b.B2; + ((unsigned char *) (dst))[2] = (v2); + if (v2 == 0) + return 0; + return dst; +} -- 2.34.1