The following patch fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70689
The patch was successfully tested and bootstrapped on x86/x86-64. Committed to the trunk as rev. 235184.
Index: ChangeLog =================================================================== --- ChangeLog (revision 235182) +++ ChangeLog (working copy) @@ -1,3 +1,11 @@ +2016-04-18 Vladimir Makarov <vmaka...@redhat.com> + + PR middle-end/70689 + * lra-constraints.c (equiv_substition_p): New. + (process_alt_operands): Use it. + (swap_operands): Swap it. + (curr_insn_transform): Update it. + 2016-04-18 Michael Matz <m...@suse.de> * tree.h (TYPE_ALIGN, DECL_ALIGN): Return shifted amount. Index: testsuite/ChangeLog =================================================================== --- testsuite/ChangeLog (revision 235182) +++ testsuite/ChangeLog (working copy) @@ -1,3 +1,8 @@ +2016-04-18 Vladimir Makarov <vmaka...@redhat.com> + + PR middle-end/70689 + * testsuite/gcc.target/i386/pr70689.c: New. + 2016-04-18 H.J. Lu <hongjiu...@intel.com> PR target/70708 Index: lra-constraints.c =================================================================== --- lra-constraints.c (revision 235176) +++ lra-constraints.c (working copy) @@ -1258,6 +1258,10 @@ static bool goal_alt_swapped; /* The chosen insn alternative. */ static int goal_alt_number; +/* True if the corresponding operand is the result of an equivalence + substitution. */ +static bool equiv_substition_p[MAX_RECOG_OPERANDS]; + /* The following five variables are used to choose the best insn alternative. They reflect final characteristics of the best alternative. */ @@ -2064,7 +2068,10 @@ process_alt_operands (int only_alternati memory, or make other memory by reloading the address like for 'o'. */ if (CONST_POOL_OK_P (mode, op) - || MEM_P (op) || REG_P (op)) + || MEM_P (op) || REG_P (op) + /* We can restore the equiv insn by a + reload. */ + || equiv_substition_p[nop]) badop = false; constmemok = true; offmemok = true; @@ -3371,6 +3378,7 @@ swap_operands (int nop) std::swap (curr_operand_mode[nop], curr_operand_mode[nop + 1]); std::swap (original_subreg_reg_mode[nop], original_subreg_reg_mode[nop + 1]); std::swap (*curr_id->operand_loc[nop], *curr_id->operand_loc[nop + 1]); + std::swap (equiv_substition_p[nop], equiv_substition_p[nop + 1]); /* Swap the duplicates too. */ lra_update_dup (curr_id, nop); lra_update_dup (curr_id, nop + 1); @@ -3473,8 +3481,10 @@ curr_insn_transform (bool check_only_p) old = SUBREG_REG (old); subst = get_equiv_with_elimination (old, curr_insn); original_subreg_reg_mode[i] = VOIDmode; + equiv_substition_p[i] = false; if (subst != old) { + equiv_substition_p[i] = true; subst = copy_rtx (subst); lra_assert (REG_P (old)); if (GET_CODE (op) != SUBREG) Index: testsuite/gcc.target/i386/pr70689.c =================================================================== --- testsuite/gcc.target/i386/pr70689.c (revision 0) +++ testsuite/gcc.target/i386/pr70689.c (working copy) @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target ia32 } */ +/* { dg-options "-O1" } */ + +struct S +{ + int f; +}; + +double a; +int c; + +static +void fn1 (struct S *p1) +{ + for (; c; ) + if (p1->f++) + a = (int) p1; +} + +int +main () +{ + struct S b = { 0 }; + fn1 (&b); + return 0; +}