Message ID | f90ce09e-a2e5-46c9-b37c-ec046ef06e5e@linux.ibm.com |
---|---|
State | New |
Headers | show |
Series | [PATCH-1v3] fwprop: Replace rtx_cost with insn_cost in try_fwprop_subst_pattern [PR113325] | expand |
Missing CC to Jeff Law. Sorry. 在 2024/6/12 10:41, HAO CHEN GUI 写道: > Hi, > This patch replaces rtx_cost with insn_cost in forward propagation. > In the PR, one constant vector should be propagated and replace a > pseudo in a store insn if we know it's a duplicated constant vector. > It reduces the insn cost but not rtx cost. In this case, the cost is > determined by destination operand (memory or pseudo). Unfortunately, > rtx cost can't help. > > The test case is added in the second rs6000 specific patch. > > Compared to previous version, the main changes are: > 1. Invoke change_is_worthwhile to judge if the cost is reduced and > the replacement is worthwhile. > 2. Invalidate recog data before getting the insn cost for the new > rtl as insn cost might call extract_constrain_insn_cached and > extract_insn_cached to cache the recog data. The cache data is > invalid for the new rtl and it causes ICE. > 3. Check if the insn cost of new rtl is zero which means unknown > cost. The replacement should be rejected at this situation. > > Previous version > https://gcc.gnu.org/pipermail/gcc-patches/2024-May/651233.html > > The patch causes a regression cases on i386 as the pattern cost > regulation has a bug. Please refer the patch and discussion here. > https://gcc.gnu.org/pipermail/gcc-patches/2024-May/651363.html > > Bootstrapped and tested on powerpc64-linux BE and LE with no > regressions. Is it OK for the trunk? > > ChangeLog > fwprop: invoke change_is_worthwhile to judge if a replacement is worthwhile > > gcc/ > * fwprop.cc (try_fwprop_subst_pattern): Invoke change_is_worthwhile > to judge if a replacement is worthwhile. > * rtl-ssa/changes.cc (rtl_ssa::changes_are_worthwhile): Invalidate > recog data before getting the insn cost for the new rtl. Check if > the insn cost of new rtl is unknown and fail the replacement. > > patch.diff > diff --git a/gcc/fwprop.cc b/gcc/fwprop.cc > index de543923b92..975de0eec7f 100644 > --- a/gcc/fwprop.cc > +++ b/gcc/fwprop.cc > @@ -471,29 +471,19 @@ try_fwprop_subst_pattern (obstack_watermark &attempt, insn_change &use_change, > redo_changes (0); > } > > - /* ??? In theory, it should be better to use insn costs rather than > - set_src_costs here. That would involve replacing this code with > - change_is_worthwhile. */ > bool ok = recog (attempt, use_change); > - if (ok && !prop.changed_mem_p () && !use_insn->is_asm ()) > - if (rtx use_set = single_set (use_rtl)) > - { > - bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_rtl)); > - temporarily_undo_changes (0); > - auto old_cost = set_src_cost (SET_SRC (use_set), > - GET_MODE (SET_DEST (use_set)), speed); > - redo_changes (0); > - auto new_cost = set_src_cost (SET_SRC (use_set), > - GET_MODE (SET_DEST (use_set)), speed); > - if (new_cost > old_cost > - || (new_cost == old_cost && !prop.likely_profitable_p ())) > - { > - if (dump_file) > - fprintf (dump_file, "change not profitable" > - " (cost %d -> cost %d)\n", old_cost, new_cost); > - ok = false; > - } > - } > + if (ok && !prop.changed_mem_p () && !use_insn->is_asm () > + && single_set (use_rtl)) > + { > + if (!change_is_worthwhile (use_change, false) > + || (!prop.likely_profitable_p () > + && !change_is_worthwhile (use_change, true))) > + { > + if (dump_file) > + fprintf (dump_file, "change not profitable"); > + ok = false; > + } > + } > > if (!ok) > { > diff --git a/gcc/rtl-ssa/changes.cc b/gcc/rtl-ssa/changes.cc > index 11639e81bb7..9bad6c2070c 100644 > --- a/gcc/rtl-ssa/changes.cc > +++ b/gcc/rtl-ssa/changes.cc > @@ -185,7 +185,18 @@ rtl_ssa::changes_are_worthwhile (array_slice<insn_change *const> changes, > * change->old_cost ()); > if (!change->is_deletion ()) > { > + /* Invalidate recog data as insn_cost may call > + extract_insn_cached. */ > + INSN_CODE (change->rtl ()) = -1; > change->new_cost = insn_cost (change->rtl (), for_speed); > + /* If the cost is unknown, replacement is not worthwhile. */ > + if (!change->new_cost) > + { > + if (dump_file && (dump_flags & TDF_DETAILS)) > + fprintf (dump_file, > + "Reject replacement due to unknown insn cost.\n"); > + return false; > + } > new_cost += change->new_cost; > if (for_speed) > weighted_new_cost += (cfg_bb->count.to_sreal_scale (entry_count)
HAO CHEN GUI <guihaoc@linux.ibm.com> writes: > Hi, > This patch replaces rtx_cost with insn_cost in forward propagation. > In the PR, one constant vector should be propagated and replace a > pseudo in a store insn if we know it's a duplicated constant vector. > It reduces the insn cost but not rtx cost. In this case, the cost is > determined by destination operand (memory or pseudo). Unfortunately, > rtx cost can't help. > > The test case is added in the second rs6000 specific patch. > > Compared to previous version, the main changes are: > 1. Invoke change_is_worthwhile to judge if the cost is reduced and > the replacement is worthwhile. > 2. Invalidate recog data before getting the insn cost for the new > rtl as insn cost might call extract_constrain_insn_cached and > extract_insn_cached to cache the recog data. The cache data is > invalid for the new rtl and it causes ICE. > 3. Check if the insn cost of new rtl is zero which means unknown > cost. The replacement should be rejected at this situation. > > Previous version > https://gcc.gnu.org/pipermail/gcc-patches/2024-May/651233.html > > The patch causes a regression cases on i386 as the pattern cost > regulation has a bug. Please refer the patch and discussion here. > https://gcc.gnu.org/pipermail/gcc-patches/2024-May/651363.html > > Bootstrapped and tested on powerpc64-linux BE and LE with no > regressions. Is it OK for the trunk? > > ChangeLog > fwprop: invoke change_is_worthwhile to judge if a replacement is worthwhile > > gcc/ > * fwprop.cc (try_fwprop_subst_pattern): Invoke change_is_worthwhile > to judge if a replacement is worthwhile. > * rtl-ssa/changes.cc (rtl_ssa::changes_are_worthwhile): Invalidate > recog data before getting the insn cost for the new rtl. Check if > the insn cost of new rtl is unknown and fail the replacement. > > patch.diff > diff --git a/gcc/fwprop.cc b/gcc/fwprop.cc > index de543923b92..975de0eec7f 100644 > --- a/gcc/fwprop.cc > +++ b/gcc/fwprop.cc > @@ -471,29 +471,19 @@ try_fwprop_subst_pattern (obstack_watermark &attempt, insn_change &use_change, > redo_changes (0); > } > > - /* ??? In theory, it should be better to use insn costs rather than > - set_src_costs here. That would involve replacing this code with > - change_is_worthwhile. */ > bool ok = recog (attempt, use_change); > - if (ok && !prop.changed_mem_p () && !use_insn->is_asm ()) > - if (rtx use_set = single_set (use_rtl)) > - { > - bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_rtl)); > - temporarily_undo_changes (0); > - auto old_cost = set_src_cost (SET_SRC (use_set), > - GET_MODE (SET_DEST (use_set)), speed); > - redo_changes (0); > - auto new_cost = set_src_cost (SET_SRC (use_set), > - GET_MODE (SET_DEST (use_set)), speed); > - if (new_cost > old_cost > - || (new_cost == old_cost && !prop.likely_profitable_p ())) > - { > - if (dump_file) > - fprintf (dump_file, "change not profitable" > - " (cost %d -> cost %d)\n", old_cost, new_cost); > - ok = false; > - } > - } > + if (ok && !prop.changed_mem_p () && !use_insn->is_asm () > + && single_set (use_rtl)) > + { > + if (!change_is_worthwhile (use_change, false) > + || (!prop.likely_profitable_p () > + && !change_is_worthwhile (use_change, true))) > + { > + if (dump_file) > + fprintf (dump_file, "change not profitable"); > + ok = false; > + } > + } It should only be necessary to call change_is_worthwhile once, with strict == !prop.likely_profitable_p () So something like: bool ok = recog (attempt, use_change); if (ok && !prop.changed_mem_p () && !use_insn->is_asm ()) { bool strict_p = !prop.likely_profitable_p (); if (!change_is_worthwhile (use_change, strict_p)) { if (dump_file) fprintf (dump_file, "change not profitable"); ok = false; } } > diff --git a/gcc/rtl-ssa/changes.cc b/gcc/rtl-ssa/changes.cc > index 11639e81bb7..9bad6c2070c 100644 > --- a/gcc/rtl-ssa/changes.cc > +++ b/gcc/rtl-ssa/changes.cc > @@ -185,7 +185,18 @@ rtl_ssa::changes_are_worthwhile (array_slice<insn_change *const> changes, > * change->old_cost ()); > if (!change->is_deletion ()) > { > + /* Invalidate recog data as insn_cost may call > + extract_insn_cached. */ > + INSN_CODE (change->rtl ()) = -1; The: bool ok = recog (attempt, use_change); should leave INSN_CODE set to the result of the successful recog. Why isn't that true in the example you hit? I wondered whether we might be trying to cost a NOOP_MOVE_INSN_CODE, since I couldn't see anything in the current code to stop that. But if so, that's a bug. NOOP_MOVE_INSN_CODE should have zero cost, and shouldn't go through insn_cost. Thanks, Richard > change->new_cost = insn_cost (change->rtl (), for_speed); > + /* If the cost is unknown, replacement is not worthwhile. */ > + if (!change->new_cost) > + { > + if (dump_file && (dump_flags & TDF_DETAILS)) > + fprintf (dump_file, > + "Reject replacement due to unknown insn cost.\n"); > + return false; > + } > new_cost += change->new_cost; > if (for_speed) > weighted_new_cost += (cfg_bb->count.to_sreal_scale (entry_count)
Hi Richard, Thanks for your comments. 在 2024/6/12 15:51, Richard Sandiford 写道: > It should only be necessary to call change_is_worthwhile once, > with strict == !prop.likely_profitable_p () > > So something like: > > bool ok = recog (attempt, use_change); > if (ok && !prop.changed_mem_p () && !use_insn->is_asm ()) > { > bool strict_p = !prop.likely_profitable_p (); > if (!change_is_worthwhile (use_change, strict_p)) > { > if (dump_file) > fprintf (dump_file, "change not profitable"); > ok = false; > } > } I will modify the code. Thanks. > The: > > bool ok = recog (attempt, use_change); > > should leave INSN_CODE set to the result of the successful recog. > Why isn't that true in the example you hit? > > I wondered whether we might be trying to cost a NOOP_MOVE_INSN_CODE, > since I couldn't see anything in the current code to stop that. > But if so, that's a bug. NOOP_MOVE_INSN_CODE should have zero cost, > and shouldn't go through insn_cost. Yes, the recog sets the recog data for the new rtl. But changes_are_worthwhile calls change->old_cost and finally calls calculate_cost to get the insn cost for old rtl. The undo/redo_changes don't restore/recover the recog_data, which causes insn_cost takes the wrong number of operands (recog_data.n_operands) and wrong operands (recog_data.operand[]). Note, rs6000_insn_cost checks if the recog data is cached. If so, it doesn't recog the insn again. void insn_info::calculate_cost () const { basic_block cfg_bb = BLOCK_FOR_INSN (m_rtl); temporarily_undo_changes (0); m_cost_or_uid = insn_cost (m_rtl, optimize_bb_for_speed_p (cfg_bb)); redo_changes (0); } // A simple debug output for calculate_cost before undo INSN CODE 850 n_operands 3 after undo INSN CODE 685 n_operands 3 Actually insn pattern 850 has 3 operands and insn pattern 685 has 2 operands. IMHO, we should invalidate recog data after each undo/redo or before calling the insn cost. Looking forward to your advice. Thanks Gui Haochen
HAO CHEN GUI <guihaoc@linux.ibm.com> writes: >> The: >> >> bool ok = recog (attempt, use_change); >> >> should leave INSN_CODE set to the result of the successful recog. >> Why isn't that true in the example you hit? >> >> I wondered whether we might be trying to cost a NOOP_MOVE_INSN_CODE, >> since I couldn't see anything in the current code to stop that. >> But if so, that's a bug. NOOP_MOVE_INSN_CODE should have zero cost, >> and shouldn't go through insn_cost. > > Yes, the recog sets the recog data for the new rtl. But > changes_are_worthwhile calls change->old_cost and finally calls > calculate_cost to get the insn cost for old rtl. The undo/redo_changes > don't restore/recover the recog_data, which causes insn_cost takes the > wrong number of operands (recog_data.n_operands) and wrong operands > (recog_data.operand[]). Note, rs6000_insn_cost checks if the recog data > is cached. If so, it doesn't recog the insn again. > > void > insn_info::calculate_cost () const > { > basic_block cfg_bb = BLOCK_FOR_INSN (m_rtl); > temporarily_undo_changes (0); > m_cost_or_uid = insn_cost (m_rtl, optimize_bb_for_speed_p (cfg_bb)); > redo_changes (0); > } > > // A simple debug output for calculate_cost > before undo > INSN CODE 850 > n_operands 3 > > after undo > INSN CODE 685 > n_operands 3 > > Actually insn pattern 850 has 3 operands and insn pattern 685 has 2 > operands. > > IMHO, we should invalidate recog data after each undo/redo or before > calling the insn cost. Ah, ok. If the problem is stale recog_data information, I think we should instead make recog.cc:swap_change conditionally invalidate it. I.e. change: if (changes[num].object && !MEM_P (changes[num].object)) std::swap (INSN_CODE (changes[num].object), changes[num].old_code); to something like: if (changes[num].object && !MEM_P (changes[num].object)) { std::swap (INSN_CODE (changes[num].object), changes[num].old_code); if (recog_data.insn == changes[num].object) recot_data.insn = nullptr; } (untested). IMO this is better then resetting the INSN_CODE, since the INSN_CODE should be correct and is relatively expensive to recompute. Thanks, Richard
在 2024/6/14 16:36, Richard Sandiford 写道: > Ah, ok. If the problem is stale recog_data information, I think we > should instead make recog.cc:swap_change conditionally invalidate it. > I.e. change: > > if (changes[num].object && !MEM_P (changes[num].object)) > std::swap (INSN_CODE (changes[num].object), changes[num].old_code); > > to something like: > > if (changes[num].object && !MEM_P (changes[num].object)) > { > std::swap (INSN_CODE (changes[num].object), changes[num].old_code); > if (recog_data.insn == changes[num].object) > recot_data.insn = nullptr; > } > > (untested). IMO this is better then resetting the INSN_CODE, since the > INSN_CODE should be correct and is relatively expensive to recompute. It's better. I will modify the patch and test it. Thanks Gui Haochen
diff --git a/gcc/fwprop.cc b/gcc/fwprop.cc index de543923b92..975de0eec7f 100644 --- a/gcc/fwprop.cc +++ b/gcc/fwprop.cc @@ -471,29 +471,19 @@ try_fwprop_subst_pattern (obstack_watermark &attempt, insn_change &use_change, redo_changes (0); } - /* ??? In theory, it should be better to use insn costs rather than - set_src_costs here. That would involve replacing this code with - change_is_worthwhile. */ bool ok = recog (attempt, use_change); - if (ok && !prop.changed_mem_p () && !use_insn->is_asm ()) - if (rtx use_set = single_set (use_rtl)) - { - bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_rtl)); - temporarily_undo_changes (0); - auto old_cost = set_src_cost (SET_SRC (use_set), - GET_MODE (SET_DEST (use_set)), speed); - redo_changes (0); - auto new_cost = set_src_cost (SET_SRC (use_set), - GET_MODE (SET_DEST (use_set)), speed); - if (new_cost > old_cost - || (new_cost == old_cost && !prop.likely_profitable_p ())) - { - if (dump_file) - fprintf (dump_file, "change not profitable" - " (cost %d -> cost %d)\n", old_cost, new_cost); - ok = false; - } - } + if (ok && !prop.changed_mem_p () && !use_insn->is_asm () + && single_set (use_rtl)) + { + if (!change_is_worthwhile (use_change, false) + || (!prop.likely_profitable_p () + && !change_is_worthwhile (use_change, true))) + { + if (dump_file) + fprintf (dump_file, "change not profitable"); + ok = false; + } + } if (!ok) { diff --git a/gcc/rtl-ssa/changes.cc b/gcc/rtl-ssa/changes.cc index 11639e81bb7..9bad6c2070c 100644 --- a/gcc/rtl-ssa/changes.cc +++ b/gcc/rtl-ssa/changes.cc @@ -185,7 +185,18 @@ rtl_ssa::changes_are_worthwhile (array_slice<insn_change *const> changes, * change->old_cost ()); if (!change->is_deletion ()) { + /* Invalidate recog data as insn_cost may call + extract_insn_cached. */ + INSN_CODE (change->rtl ()) = -1; change->new_cost = insn_cost (change->rtl (), for_speed); + /* If the cost is unknown, replacement is not worthwhile. */ + if (!change->new_cost) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + "Reject replacement due to unknown insn cost.\n"); + return false; + } new_cost += change->new_cost; if (for_speed) weighted_new_cost += (cfg_bb->count.to_sreal_scale (entry_count)