g:497498c878d48754318e486428e2aa30854020b9 caused lra to cycle on some SDmode reloads for power6. As explained in more detail in the PR comments, the problem was a conflict between two target hooks: rs6000_secondary_memory_needed_mode required SDmode FPR reloads to use DDmode memory (rightly, since using SDmode memory wouldn't make progress) but rs6000_can_change_mode_class didn't allow FPRs to change from SDmode to DDmode. Previously lra ignored that and changed the mode anyway.
>From what Segher says, it sounds like the "from_size < 8 || to_size < 8" check is mostly there for SF<->64-bit subregs, and that SDmode is stored in the way that target-independent code expects. This patch therefore allows SD<->DD changes. I wondered about checking for SD<->64-bit changes instead, but that seemed like an unnecessary generalisation for this stage. Bootstrapped and regression-tested on powerpc64le-unknown-linux-gnu, both with default settings and with --with-cpu=power6. (For power6 I reverted the lra patch to do the before testing, since the build hanged otherwise.) The patch fixed the regressing testcases and introduced no other test changes. Zdenek confirms that it also fixes powerpc-linux-gnu builds. OK to install? Richard 2020-03-23 Richard Sandiford <richard.sandif...@arm.com> gcc/ PR target/94254 * config/rs6000/rs6000.c (rs6000_can_change_mode_class): Allow FPRs to change between SDmode and DDmode. --- gcc/config/rs6000/rs6000.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 07f7cf516ba..2354aceb3f7 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -12307,6 +12307,15 @@ rs6000_can_change_mode_class (machine_mode from, if (!BYTES_BIG_ENDIAN && (to == TDmode || from == TDmode)) return false; + /* Allow SD<->DD changes, since SDmode values are stored in + the low half of the DDmode, just like target-independent + code expects. We need to allow at least SD->DD since + rs6000_secondary_memory_needed_mode asks for that change + to be made for SD reloads. */ + if ((to == DDmode && from == SDmode) + || (to == SDmode && from == DDmode)) + return true; + if (from_size < 8 || to_size < 8) return false;