On 12/7/18 8:57 AM, Andreas Krebbel wrote:
> Hi,
>
> debugging a problem with an older GCC (4.6). I've seen RTXs using
> ZERO_EXTRACT LHS operands on MEMs as in:
>
> (insn 7 6 0 (set (zero_extract:DI (mem/s/c:QI (plus:DI (reg/f:DI 39
> virtual-stack-vars)
> (const_int -5 [0xfffffffffffffffb])) [0+0 S1 A8])
> (const_int 24 [0x18])
> (const_int 0 [0]))
> (subreg:DI (reg:SI 45) 0)) t.c:19 -1
> (nil))
Yes. They're essentially a bitfield manipulation.
[ ... ]
>
> However, I still think that's a legal RTX which needs to be handled by
> DSE correctly. I couldn't find anything preventing that problem from
> occuring also with current GCCs. On the other hand I couldn't trigger
> it with anything in testsuite.I'd look for a target which can do a bitfield
> manipulation of a memory
object. So likely old targets nobody cares about :-) m68k, h8, etc.
>
> Perhaps something like that would be needed for current GCC:
>
> diff --git a/gcc/dse.c b/gcc/dse.c
> index 21d166d..d27fb54 100644
> --- a/gcc/dse.c
> +++ b/gcc/dse.c
> @@ -1346,6 +1346,47 @@ record_store (rtx body, bb_info_t bb_info)
>
> mem = SET_DEST (body);
>
> + /* Deal with (zero_extract:XX (mem:QI ...)). */
> + if (GET_CODE (mem) == ZERO_EXTRACT && MEM_P (XEXP (mem, 0)))
> + {
> + rtx size_op = XEXP (mem, 1);
> + rtx offset_op = XEXP (mem, 2);
> + enum machine_mode mode = GET_MODE (mem);
> + scalar_int_mode int_mode;
> +
> + /* Turn a (zero_extract:XX (mem:QI ...)) into a (mem:BLK with
> + the proper size and the adjusted address. */
> + if (CONST_INT_P (size_op)
> + && CONST_INT_P (offset_op)
> + && is_a <scalar_int_mode> (mode, &int_mode)
> + && INTVAL (size_op) + INTVAL (offset_op) <= GET_MODE_PRECISION
> (int_mode))
> + {
> + int size = INTVAL (size_op);
> + int offset = INTVAL (offset_op);
> +
> + mem = copy_rtx (XEXP (mem, 0));
> + if (BITS_BIG_ENDIAN)
> + mem = adjust_address (mem, BLKmode, offset / BITS_PER_UNIT);
> + else
> + mem = adjust_address (mem, BLKmode,
> + (GET_MODE_BITSIZE (int_mode) - size - offset)
> + / BITS_PER_UNIT);
> +
> + set_mem_size (mem, (size - 1) / BITS_PER_UNIT + 1);
> + }
> + else
> + {
> + if (find_reg_note (insn_info->insn, REG_UNUSED, mem) == NULL)
> + {
> + /* If the set or clobber is unused, then it does not effect our
> + ability to get rid of the entire insn. */
> + insn_info->cannot_delete = true;
> + clear_rhs_from_active_local_stores ();
> + }
> + return 0;
> + }
> + }
Looks sane at a high level. The trick is exercising it...
jeff