The following patch fixes http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60508
The patch was successfully bootstrapped and tested on x86-64. Committed as rev. 208570. 2014-03-14 Vladimir Makarov <vmaka...@redhat.com> PR rtl-optimization/60508 * lra-constraints.c (get_reload_reg): Add new parameter in_subreg_p. (process_addr_reg, simplify_operand_subreg, curr_insn_transform): Pass the new parameter values. 2014-03-14 Vladimir Makarov <vmaka...@redhat.com> PR rtl-optimization/60508 * gcc.target/i386/pr60508.c: New.
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index 288e24b..ba4d489 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -439,14 +439,16 @@ init_curr_insn_input_reloads (void) } /* Create a new pseudo using MODE, RCLASS, ORIGINAL or reuse already - created input reload pseudo (only if TYPE is not OP_OUT). The - result pseudo is returned through RESULT_REG. Return TRUE if we - created a new pseudo, FALSE if we reused the already created input - reload pseudo. Use TITLE to describe new registers for debug - purposes. */ + created input reload pseudo (only if TYPE is not OP_OUT). Don't + reuse pseudo if IN_SUBREG_P is true and the reused pseudo should be + wrapped up in SUBREG. The result pseudo is returned through + RESULT_REG. Return TRUE if we created a new pseudo, FALSE if we + reused the already created input reload pseudo. Use TITLE to + describe new registers for debug purposes. */ static bool get_reload_reg (enum op_type type, enum machine_mode mode, rtx original, - enum reg_class rclass, const char *title, rtx *result_reg) + enum reg_class rclass, bool in_subreg_p, + const char *title, rtx *result_reg) { int i, regno; enum reg_class new_class; @@ -471,6 +473,8 @@ get_reload_reg (enum op_type type, enum machine_mode mode, rtx original, Ensure we don't return *result_reg with wrong mode. */ if (GET_MODE (reg) != mode) { + if (in_subreg_p) + continue; if (GET_MODE_SIZE (GET_MODE (reg)) < GET_MODE_SIZE (mode)) continue; reg = lowpart_subreg (mode, reg, GET_MODE (reg)); @@ -1139,9 +1143,11 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl) rtx reg; rtx new_reg; enum machine_mode mode; - bool before_p = false; + bool subreg_p, before_p = false; - loc = strip_subreg (loc); + subreg_p = GET_CODE (*loc) == SUBREG; + if (subreg_p) + loc = &SUBREG_REG (*loc); reg = *loc; mode = GET_MODE (reg); if (! REG_P (reg)) @@ -1171,7 +1177,7 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl) { reg = *loc; if (get_reload_reg (after == NULL ? OP_IN : OP_INOUT, - mode, reg, cl, "address", &new_reg)) + mode, reg, cl, subreg_p, "address", &new_reg)) before_p = true; } else if (new_class != NO_REGS && rclass != new_class) @@ -1304,7 +1310,7 @@ simplify_operand_subreg (int nop, enum machine_mode reg_mode) = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS); if (get_reload_reg (curr_static_id->operand[nop].type, reg_mode, reg, - rclass, "subreg reg", &new_reg)) + rclass, TRUE, "subreg reg", &new_reg)) { bool insert_before, insert_after; bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg)); @@ -1365,7 +1371,7 @@ simplify_operand_subreg (int nop, enum machine_mode reg_mode) = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS); if (get_reload_reg (curr_static_id->operand[nop].type, mode, reg, - rclass, "paradoxical subreg", &new_reg)) + rclass, TRUE, "paradoxical subreg", &new_reg)) { rtx subreg; bool insert_before, insert_after; @@ -3573,7 +3579,7 @@ curr_insn_transform (void) new_reg = emit_inc (rclass, *loc, *loc, /* This value does not matter for MODIFY. */ GET_MODE_SIZE (GET_MODE (op))); - else if (get_reload_reg (OP_IN, Pmode, *loc, rclass, + else if (get_reload_reg (OP_IN, Pmode, *loc, rclass, FALSE, "offsetable address", &new_reg)) lra_emit_move (new_reg, *loc); before = get_insns (); @@ -3615,7 +3621,8 @@ curr_insn_transform (void) } } old = *loc; - if (get_reload_reg (type, mode, old, goal_alt[i], "", &new_reg) + if (get_reload_reg (type, mode, old, goal_alt[i], + loc != curr_id->operand_loc[i], "", &new_reg) && type != OP_OUT) { push_to_sequence (before); diff --git a/gcc/testsuite/gcc.target/i386/pr60508.c b/gcc/testsuite/gcc.target/i386/pr60508.c new file mode 100644 index 0000000..78dfb78 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr60508.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O -w" } */ +int a = 1, g, h = 1, d, e, *f; +char b; +static int c[] = { 0, 0 }; +void fn2 (void); + +void +fn1 (short x, int l) +{ +lab: + { + int k, m[0]; + long j = h ? 0 : 0 / 0; + unsigned char n = j; + unsigned char i = x >= 0 ? n : n >> x; + g = i; + for (;;) + { + if (a) + goto lab; + while (d) + { + e = b = c[l]; + fn2 (); + } + int o = m[0]; + f = &k; + } + } +}