The following patch fixes http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60769
The patch was bootstrapped and tested on x86/x86-64. Committed as rev. 209285. 2014-04-10 Vladimir Makarov <vmaka...@redhat.com> PR rtl-optimization/60769 * lra-constraints.c (simplify_operand_subreg): Force reload of paradoxical subreg if it is not in the class contents. 2014-04-10 Vladimir Makarov <vmaka...@redhat.com> PR rtl-optimization/60769 * g++.dg/pr60769.C: New.
Index: lra-constraints.c =================================================================== --- lra-constraints.c (revision 209283) +++ lra-constraints.c (working copy) @@ -1156,6 +1156,8 @@ simplify_operand_subreg (int nop, enum m enum machine_mode mode; rtx reg, new_reg; rtx operand = *curr_id->operand_loc[nop]; + enum reg_class regclass; + enum op_type type; before = after = NULL_RTX; @@ -1164,6 +1166,7 @@ simplify_operand_subreg (int nop, enum m mode = GET_MODE (operand); reg = SUBREG_REG (operand); + type = curr_static_id->operand[nop].type; /* If we change address for paradoxical subreg of memory, the address might violate the necessary alignment or the access might be slow. So take this into consideration. We should not worry @@ -1236,6 +1239,55 @@ simplify_operand_subreg (int nop, enum m "Inserting subreg reload"); return true; } + /* Force a reload for a paradoxical subreg. For paradoxical subreg, + IRA allocates hardreg to the inner pseudo reg according to its mode + instead of the outermode, so the size of the hardreg may not be enough + to contain the outermode operand, in that case we may need to insert + reload for the reg. For the following two types of paradoxical subreg, + we need to insert reload: + 1. If the op_type is OP_IN, and the hardreg could not be paired with + other hardreg to contain the outermode operand + (checked by in_hard_reg_set_p), we need to insert the reload. + 2. If the op_type is OP_OUT or OP_INOUT. */ + else if (REG_P (reg) + && REGNO (reg) >= FIRST_PSEUDO_REGISTER + && (hard_regno = lra_get_regno_hard_regno (REGNO (reg))) >= 0 + && (hard_regno_nregs[hard_regno][GET_MODE (reg)] + < hard_regno_nregs[hard_regno][mode]) + && (regclass = lra_get_allocno_class (REGNO (reg))) + && (type != OP_IN + || !in_hard_reg_set_p (reg_class_contents[regclass], + mode, hard_regno))) + { + /* The class will be defined later in curr_insn_transform. */ + enum reg_class rclass + = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS); + rtx subreg; + + new_reg = lra_create_new_reg_with_unique_value (mode, reg, rclass, + "paradoxical subreg"); + PUT_MODE (new_reg, mode); + subreg = simplify_gen_subreg (GET_MODE (reg), new_reg, mode, 0); + if (type != OP_OUT) + { + push_to_sequence (before); + lra_emit_move (subreg, reg); + before = get_insns (); + end_sequence (); + } + if (type != OP_IN) + { + start_sequence (); + lra_emit_move (reg, subreg); + emit_insn (after); + after = get_insns (); + end_sequence (); + } + SUBREG_REG (operand) = new_reg; + lra_process_new_insns (curr_insn, before, after, + "Inserting paradoxical subreg reload"); + return true; + } return false; } Index: testsuite/g++.dg/pr60769.C =================================================================== --- testsuite/g++.dg/pr60769.C (revision 0) +++ testsuite/g++.dg/pr60769.C (working copy) @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-O" } */ + +template <class T> void fun(T); +struct B {}; +struct R { + int *x; + B f; +}; +R v(int &, R); +void rfun(R &); +struct A { + void m_fn2(R p1) { + R a = p1; + rfun(p1); + fun(this); + fun(a); + } +}; +struct J { + A ep; + A ap; + int c2a; + void m_fn1(R &p2) { + R d, e, b; + v(c2a, p2); + e = v(c2a, b); + ap.m_fn2(e); + v(c2a, p2); + d = v(c2a, b); + ep.m_fn2(d); + } +}; +struct N { + int &p_; + J cfo; +}; +void fn3(N&n) { + R h; + n.cfo.m_fn1(h); +} +extern N &c; +void fn1() { fn3(c); }