Hi, This patch is a minimal change to prevent (subreg(mem)) from being simplified to use the outer mode for WORD_REGISTER_OPERATIONS. There is high probability of refining and/or re-implementing this for GCC 8 but such a change would be too invasive. This change at least ensures correctness but may prevent simplification of some acceptable cases.
No testcase here but I will try to make one using the RTL frontend later. This fix is required for mips64el-linux-gnu bootstrap to succeed (in conjunction with patch 1 of this series). The specific file affected by this bug is building gcc/predict.c where a bad reload is created in predict_paths_for_bb. Register 300 in the following example is spilled to memory in SImode but reloaded as DImode. (insn 247 212 389 3 (set (reg:SI 300) (ne:SI (subreg/s/u:SI (reg/v:DI 231 [ taken ]) 0) (const_int 0 [0]))) "/home/mfortune/gcc/gcc/predict.c":2904 504 {*sne_zero_sisi} (nil)) ... (insn 250 256 251 40 (set (reg:DI 6 $6) (subreg:DI (reg:SI 300) 0)) "/home/mfortune/gcc/gcc/predict.c":2904 310 {*movdi_64bit} (nil)) Thanks, Matthew gcc/ PR target/78660 * lra-constraints.c (simplify_operand_subreg): Handle WORD_REGISTER_OPERATIONS targets. --- gcc/lra-constraints.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index 66ff2bb..484a70d 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -1541,11 +1541,18 @@ simplify_operand_subreg (int nop, machine_mode reg_mode) subregs as we don't substitute such equiv memory (see processing equivalences in function lra_constraints) and because for spilled pseudos we allocate stack memory enough for the biggest - corresponding paradoxical subreg. */ - if (!(MEM_ALIGN (subst) < GET_MODE_ALIGNMENT (mode) - && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (subst))) - || (MEM_ALIGN (reg) < GET_MODE_ALIGNMENT (innermode) - && SLOW_UNALIGNED_ACCESS (innermode, MEM_ALIGN (reg)))) + corresponding paradoxical subreg. + + However, never simplify a (subreg (mem ...)) for + WORD_REGISTER_OPERATIONS targets as this may lead to loading junk + data into a register when the inner is narrower than outer or + missing important data from memory when the inner is wider than + outer. */ + if (!WORD_REGISTER_OPERATIONS + && (!(MEM_ALIGN (subst) < GET_MODE_ALIGNMENT (mode) + && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (subst))) + || (MEM_ALIGN (reg) < GET_MODE_ALIGNMENT (innermode) + && SLOW_UNALIGNED_ACCESS (innermode, MEM_ALIGN (reg))))) return true; *curr_id->operand_loc[nop] = operand; -- 2.2.1