The following patch solves https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114942
The patch was successfully bootstrapped and tested on x86-64, ppc64le, aarch64.
commit 9585317f0715699197b1313bbf939c6ea3c1ace6 Author: Vladimir N. Makarov <vmaka...@redhat.com> Date: Fri May 10 09:15:50 2024 -0400 [PR114942][LRA]: Don't reuse input reload reg of inout early clobber operand The insn in question has the same reg in inout operand and input operand. The inout operand is early clobber. LRA reused input reload reg of the inout operand for the input operand which is wrong. It were a good decision if the inout operand was not early clobber one. The patch rejects the reuse for the PR test case. gcc/ChangeLog: PR target/114942 * lra-constraints.cc (struct input_reload): Add new member early_clobber_p. (get_reload_reg): Add new arg early_clobber_p, don't reuse input reload with true early_clobber_p member value, use the arg for new element of curr_insn_input_reloads. (match_reload): Assign false to early_clobber_p member. (process_addr_reg, simplify_operand_subreg, curr_insn_transform): Adjust get_reload_reg calls. gcc/testsuite/ChangeLog: PR target/114942 * gcc.target/i386/pr114942.c: New. diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index 5b78fd0b7e5..e945a4da451 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -599,6 +599,8 @@ struct input_reload { /* True for input reload of matched operands. */ bool match_p; + /* True for input reload of inout earlyclobber operand. */ + bool early_clobber_p; /* Reloaded value. */ rtx input; /* Reload pseudo used. */ @@ -649,13 +651,15 @@ canonicalize_reload_addr (rtx addr) /* Create a new pseudo using MODE, RCLASS, EXCLUDE_START_HARD_REGS, ORIGINAL or reuse an existing reload pseudo. Don't reuse an existing reload pseudo if IN_SUBREG_P is true and the reused pseudo should be wrapped up in a SUBREG. + EARLY_CLOBBER_P is true for input reload of inout early clobber operand. The result pseudo is returned through RESULT_REG. Return TRUE if we created a new pseudo, FALSE if we reused an existing reload pseudo. Use TITLE to describe new registers for debug purposes. */ static bool get_reload_reg (enum op_type type, machine_mode mode, rtx original, enum reg_class rclass, HARD_REG_SET *exclude_start_hard_regs, - bool in_subreg_p, const char *title, rtx *result_reg) + bool in_subreg_p, bool early_clobber_p, + const char *title, rtx *result_reg) { int i, regno; enum reg_class new_class; @@ -703,6 +707,7 @@ get_reload_reg (enum op_type type, machine_mode mode, rtx original, for (i = 0; i < curr_insn_input_reloads_num; i++) { if (! curr_insn_input_reloads[i].match_p + && ! curr_insn_input_reloads[i].early_clobber_p && rtx_equal_p (curr_insn_input_reloads[i].input, original) && in_class_p (curr_insn_input_reloads[i].reg, rclass, &new_class)) { @@ -750,6 +755,8 @@ get_reload_reg (enum op_type type, machine_mode mode, rtx original, lra_assert (curr_insn_input_reloads_num < LRA_MAX_INSN_RELOADS); curr_insn_input_reloads[curr_insn_input_reloads_num].input = original; curr_insn_input_reloads[curr_insn_input_reloads_num].match_p = false; + curr_insn_input_reloads[curr_insn_input_reloads_num].early_clobber_p + = early_clobber_p; curr_insn_input_reloads[curr_insn_input_reloads_num++].reg = *result_reg; return true; } @@ -1189,6 +1196,7 @@ match_reload (signed char out, signed char *ins, signed char *outs, lra_assert (curr_insn_input_reloads_num < LRA_MAX_INSN_RELOADS); curr_insn_input_reloads[curr_insn_input_reloads_num].input = in_rtx; curr_insn_input_reloads[curr_insn_input_reloads_num].match_p = true; + curr_insn_input_reloads[curr_insn_input_reloads_num].early_clobber_p = false; curr_insn_input_reloads[curr_insn_input_reloads_num++].reg = new_in_reg; for (i = 0; (in = ins[i]) >= 0; i++) if (GET_MODE (*curr_id->operand_loc[in]) == VOIDmode @@ -1577,7 +1585,7 @@ process_addr_reg (rtx *loc, bool check_only_p, rtx_insn **before, rtx_insn **aft reg = *loc; if (get_reload_reg (after == NULL ? OP_IN : OP_INOUT, mode, reg, cl, NULL, - subreg_p, "address", &new_reg)) + subreg_p, false, "address", &new_reg)) before_p = true; } else if (new_class != NO_REGS && rclass != new_class) @@ -1733,7 +1741,7 @@ simplify_operand_subreg (int nop, machine_mode reg_mode) = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS); if (get_reload_reg (curr_static_id->operand[nop].type, innermode, reg, rclass, NULL, - true, "slow/invalid mem", &new_reg)) + true, false, "slow/invalid mem", &new_reg)) { bool insert_before, insert_after; bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg)); @@ -1753,7 +1761,7 @@ simplify_operand_subreg (int nop, 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, NULL, - true, "slow/invalid mem", &new_reg)) + true, false, "slow/invalid mem", &new_reg)) { bool insert_before, insert_after; bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg)); @@ -1854,7 +1862,7 @@ simplify_operand_subreg (int nop, machine_mode reg_mode) if (get_reload_reg (curr_static_id->operand[nop].type, reg_mode, reg, rclass, NULL, - true, "subreg reg", &new_reg)) + true, false, "subreg reg", &new_reg)) { bool insert_before, insert_after; bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg)); @@ -1928,7 +1936,7 @@ simplify_operand_subreg (int nop, machine_mode reg_mode) if (get_reload_reg (curr_static_id->operand[nop].type, mode, reg, rclass, NULL, - true, "paradoxical subreg", &new_reg)) + true, false, "paradoxical subreg", &new_reg)) { rtx subreg; bool insert_before, insert_after; @@ -4633,7 +4641,7 @@ curr_insn_transform (bool check_only_p) /* This value does not matter for MODIFY. */ GET_MODE_SIZE (GET_MODE (op))); else if (get_reload_reg (OP_IN, Pmode, *loc, rclass, - NULL, false, + NULL, false, false, "offsetable address", &new_reg)) { rtx addr = *loc; @@ -4719,7 +4727,10 @@ curr_insn_transform (bool check_only_p) old = *loc; if (get_reload_reg (type, mode, old, goal_alt[i], &goal_alt_exclude_start_hard_regs[i], - loc != curr_id->operand_loc[i], "", &new_reg) + loc != curr_id->operand_loc[i], + curr_static_id->operand_alternative + [goal_alt_number * n_operands + i].earlyclobber, + "", &new_reg) && type != OP_OUT) { push_to_sequence (before); diff --git a/gcc/testsuite/gcc.target/i386/pr114942.c b/gcc/testsuite/gcc.target/i386/pr114942.c new file mode 100644 index 00000000000..77dbb62be12 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr114942.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fno-tree-sra -fno-guess-branch-probability" } */ + +extern void a(); +struct b { + char c; + char d; +} e; +int main() { + struct b f = e; + char i = 0; + L1: + if (!f.c) + goto L2; + if (e.c) + a(); + else + return 0; + f.d = 0; + i = 1 % ((1 & f.c) - 2); + L2: + f.c = ~(i & ~f.d); + goto L1; +}