diff --git a/gcc/df-problems.c b/gcc/df-problems.c index 8fe58581f32..83b200baf9d 100644 --- a/gcc/df-problems.c +++ b/gcc/df-problems.c @@ -842,14 +842,54 @@ df_lr_bb_local_compute (unsigned int bb_index) df_insn_info *insn_info = DF_INSN_INFO_GET (insn); FOR_EACH_INSN_INFO_DEF (def, insn_info) - /* If the def is to only part of the reg, it does - not kill the other defs that reach here. */ - if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL))) - { - unsigned int dregno = DF_REF_REGNO (def); - bitmap_set_bit (&bb_info->def, dregno); + { + /* If the definition is to only part of the register, it will + usually have a corresponding use. For example, stores to one + word of a multiword register R have both a use and a partial + definition of R. + + In those cases, the LR confluence function: + + IN = (OUT & ~DEF) | USE + + is unaffected by whether we count the partial definition or not. + However, it's more convenient for consumers if DEF contains + *all* the registers defined in a block. + + The only current case in which we record a partial definition + without a corresponding use is if the destination is the + multi-register subreg of a hard register. An artificial + example of this is: + + (set (subreg:TI (reg:V8HI x0) 0) (const_int -1)) + + on AArch64. This is described as a DF_REF_PARTIAL + definition of x0 and x1 with no corresponding uses. + In previous versions of GCC, the instruction had no + effect on LR (that is, LR acted as though the instruction + didn't exist). + + It seems suspect that this case is treated differently. + Either the instruction should be a full definition of x0 and x1, + or the definition should be treated in the same way as other + partial definitions, such as strict_lowparts or subregs that + satisfy read_modify_subreg_p. + + Fortunately, multi-register subregs of hard registers should + be rare. They should be folded into a plain REG if the target + allows that (as AArch64 does for example above). + + Here we treat the cases alike by forcing a use even in the rare + case that no DF_REF_REG_USE is recorded. That is, we model all + partial definitions as both a use and a definition of the + register. */ + unsigned int dregno = DF_REF_REGNO (def); + bitmap_set_bit (&bb_info->def, dregno); + if (DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)) + bitmap_set_bit (&bb_info->use, dregno); + else bitmap_clear_bit (&bb_info->use, dregno); - } + } FOR_EACH_INSN_INFO_USE (use, insn_info) /* Add use to set of uses in this BB. */ diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/multi-subreg-1.c b/gcc/testsuite/gcc.dg/rtl/aarch64/multi-subreg-1.c new file mode 100644 index 00000000000..d7be5592e78 --- /dev/null +++ b/gcc/testsuite/gcc.dg/rtl/aarch64/multi-subreg-1.c @@ -0,0 +1,19 @@ +/* { dg-additional-options "-O -fdump-rtl-cse1-all" } */ + +__int128 __RTL (startwith ("vregs")) foo (void) +{ +(function "foo" + (insn-chain + (block 2 + (edge-from entry (flags "FALLTHRU")) + (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK) + (cnote 2 NOTE_INSN_FUNCTION_BEG) + (cinsn 3 (set (subreg:TI (reg:V8HI x0) 0) (const_int -1))) + (edge-to exit (flags "FALLTHRU")) + ) + ) + (crtl (return_rtx (reg/i:TI x0))) +) +} + +/* { dg-final { scan-rtl-dump {(?n)lr *def.*\[x0\].*\[x1\]} cse1 } } */