Hi! As mentioned in the PR, adjust_address in certain cases forces the address into a register. This doesn't work if there is a matching MEM, where we need rtx_equal_p before the splitting as well as after the splitting.
The following patch fixes that by checking for the matching MEM (looks just for one, that should be enough for x86 backend IMHO) and reusing the adjust_address results in that case instead of calling it again. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2019-09-03 Jakub Jelinek <ja...@redhat.com> PR target/91604 * config/i386/i386-expand.c (split_double_mode): If there is more than one MEM operand and they are rtx_equal_p, reuse lo_half/hi_half from already split matching MEM operand instead of calling adjust_address again. * gcc.target/i386/pr91604.c: New test. --- gcc/config/i386/i386-expand.c.jj 2019-08-29 11:22:21.897593027 +0200 +++ gcc/config/i386/i386-expand.c 2019-09-02 18:31:10.362812352 +0200 @@ -106,6 +106,8 @@ split_double_mode (machine_mode mode, rt { machine_mode half_mode; unsigned int byte; + rtx mem_op = NULL_RTX; + int mem_num = 0; switch (mode) { @@ -129,8 +131,18 @@ split_double_mode (machine_mode mode, rt but we still have to handle it. */ if (MEM_P (op)) { - lo_half[num] = adjust_address (op, half_mode, 0); - hi_half[num] = adjust_address (op, half_mode, byte); + if (mem_op && rtx_equal_p (op, mem_op)) + { + lo_half[num] = lo_half[mem_num]; + hi_half[num] = hi_half[mem_num]; + } + else + { + mem_op = op; + mem_num = num; + lo_half[num] = adjust_address (op, half_mode, 0); + hi_half[num] = adjust_address (op, half_mode, byte); + } } else { --- gcc/testsuite/gcc.target/i386/pr91604.c.jj 2019-09-02 18:35:24.399989307 +0200 +++ gcc/testsuite/gcc.target/i386/pr91604.c 2019-09-02 18:32:29.409622762 +0200 @@ -0,0 +1,11 @@ +/* PR target/91604 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -msse2 --param max-gcse-memory=0 -fno-rerun-cse-after-loop" } */ + +long long v; + +void +foo (void) +{ + v = ~v; +} Jakub