This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Limit combines work at -Og, introduce --param max-combine-insns
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 15 Jul 2014 13:58:09 +0200 (CEST)
- Subject: [PATCH] Limit combines work at -Og, introduce --param max-combine-insns
- Authentication-results: sourceware.org; auth=none
The following introduces a new param, max-combine-insns, to
be able to limit the work done at -Og to linear complexity
in the number of log-links (thus, two-insn combines). It
also records statistics of performed combines where for
fold-const.ii on x86_64 we see at -Og (unpatched):
208 combine "three-insn combine" 25
208 combine "two-insn combine" 14393
and patched:
208 combine "two-insn combine" 14392
Bootstrap / regtest scheduled on x86_64-unknown-linux-gnu.
Ok? (I can rip out the statistics stuff if you mind)
(the combine_insns diff is so large because of re-indenting)
Thanks,
Richard.
2014-07-15 Richard Biener <rguenther@suse.de>
* params.def (PARAM_MAX_COMBINE_INSNS): New.
* combine.c: Include statistics.h and params.h.
(combine_instructions): Guard three and four insn combines
with max-combine-insns value. Record statistics for combines
performed.
* doc/invoke.texi (max-combine-insns): Document new param.
Index: gcc/params.def
===================================================================
*** gcc/params.def (revision 212548)
--- gcc/params.def (working copy)
*************** DEFPARAM(PARAM_MAX_LAST_VALUE_RTL,
*** 673,678 ****
--- 673,683 ----
"The maximum number of RTL nodes that can be recorded as combiner's last value",
10000, 0, 0)
+ DEFPARAM(PARAM_MAX_COMBINE_INSNS,
+ "max-combine-insns",
+ "The maximum number of insns combine tries to combine",
+ 4, 2, 4)
+
/* INTEGER_CST nodes are shared for values [{-1,0} .. N) for
{signed,unsigned} integral types. This determines N.
Experimentation shows 251 to be a good value that generates the
Index: gcc/combine.c
===================================================================
*** gcc/combine.c (revision 212548)
--- gcc/combine.c (working copy)
*************** along with GCC; see the file COPYING3.
*** 104,109 ****
--- 104,111 ----
#include "valtrack.h"
#include "cgraph.h"
#include "obstack.h"
+ #include "statistics.h"
+ #include "params.h"
/* Number of attempts to combine instructions in this function. */
*************** combine_instructions (rtx f, unsigned in
*** 1209,1214 ****
--- 1211,1217 ----
init_reg_last ();
setup_incoming_promotions (first);
last_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ int max_combine = PARAM_VALUE (PARAM_MAX_COMBINE_INSNS);
FOR_EACH_BB_FN (this_basic_block, cfun)
{
*************** combine_instructions (rtx f, unsigned in
*** 1229,1446 ****
insn = next ? next : NEXT_INSN (insn))
{
next = 0;
! if (NONDEBUG_INSN_P (insn))
! {
! while (last_combined_insn
! && INSN_DELETED_P (last_combined_insn))
! last_combined_insn = PREV_INSN (last_combined_insn);
! if (last_combined_insn == NULL_RTX
! || BARRIER_P (last_combined_insn)
! || BLOCK_FOR_INSN (last_combined_insn) != this_basic_block
! || DF_INSN_LUID (last_combined_insn) <= DF_INSN_LUID (insn))
! last_combined_insn = insn;
!
! /* See if we know about function return values before this
! insn based upon SUBREG flags. */
! check_promoted_subreg (insn, PATTERN (insn));
!
! /* See if we can find hardregs and subreg of pseudos in
! narrower modes. This could help turning TRUNCATEs
! into SUBREGs. */
! note_uses (&PATTERN (insn), record_truncated_values, NULL);
!
! /* Try this insn with each insn it links back to. */
!
! FOR_EACH_LOG_LINK (links, insn)
! if ((next = try_combine (insn, links->insn, NULL_RTX,
! NULL_RTX, &new_direct_jump_p,
! last_combined_insn)) != 0)
! goto retry;
!
! /* Try each sequence of three linked insns ending with this one. */
! FOR_EACH_LOG_LINK (links, insn)
! {
! rtx link = links->insn;
!
! /* If the linked insn has been replaced by a note, then there
! is no point in pursuing this chain any further. */
! if (NOTE_P (link))
! continue;
!
! FOR_EACH_LOG_LINK (nextlinks, link)
! if ((next = try_combine (insn, link, nextlinks->insn,
! NULL_RTX, &new_direct_jump_p,
! last_combined_insn)) != 0)
goto retry;
! }
#ifdef HAVE_cc0
! /* Try to combine a jump insn that uses CC0
! with a preceding insn that sets CC0, and maybe with its
! logical predecessor as well.
! This is how we make decrement-and-branch insns.
! We need this special code because data flow connections
! via CC0 do not get entered in LOG_LINKS. */
!
! if (JUMP_P (insn)
! && (prev = prev_nonnote_insn (insn)) != 0
! && NONJUMP_INSN_P (prev)
! && sets_cc0_p (PATTERN (prev)))
! {
! if ((next = try_combine (insn, prev, NULL_RTX, NULL_RTX,
! &new_direct_jump_p,
last_combined_insn)) != 0)
goto retry;
! FOR_EACH_LOG_LINK (nextlinks, prev)
! if ((next = try_combine (insn, prev, nextlinks->insn,
! NULL_RTX, &new_direct_jump_p,
! last_combined_insn)) != 0)
! goto retry;
! }
!
! /* Do the same for an insn that explicitly references CC0. */
! if (NONJUMP_INSN_P (insn)
! && (prev = prev_nonnote_insn (insn)) != 0
! && NONJUMP_INSN_P (prev)
! && sets_cc0_p (PATTERN (prev))
! && GET_CODE (PATTERN (insn)) == SET
! && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
! {
! if ((next = try_combine (insn, prev, NULL_RTX, NULL_RTX,
! &new_direct_jump_p,
last_combined_insn)) != 0)
goto retry;
! FOR_EACH_LOG_LINK (nextlinks, prev)
! if ((next = try_combine (insn, prev, nextlinks->insn,
! NULL_RTX, &new_direct_jump_p,
! last_combined_insn)) != 0)
! goto retry;
! }
!
! /* Finally, see if any of the insns that this insn links to
! explicitly references CC0. If so, try this insn, that insn,
! and its predecessor if it sets CC0. */
! FOR_EACH_LOG_LINK (links, insn)
! if (NONJUMP_INSN_P (links->insn)
! && GET_CODE (PATTERN (links->insn)) == SET
! && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (links->insn)))
! && (prev = prev_nonnote_insn (links->insn)) != 0
! && NONJUMP_INSN_P (prev)
! && sets_cc0_p (PATTERN (prev))
! && (next = try_combine (insn, links->insn,
! prev, NULL_RTX, &new_direct_jump_p,
! last_combined_insn)) != 0)
! goto retry;
#endif
! /* Try combining an insn with two different insns whose results it
! uses. */
! FOR_EACH_LOG_LINK (links, insn)
! for (nextlinks = links->next; nextlinks;
! nextlinks = nextlinks->next)
! if ((next = try_combine (insn, links->insn,
! nextlinks->insn, NULL_RTX,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
! goto retry;
!
! /* Try four-instruction combinations. */
! FOR_EACH_LOG_LINK (links, insn)
! {
! struct insn_link *next1;
! rtx link = links->insn;
! /* If the linked insn has been replaced by a note, then there
! is no point in pursuing this chain any further. */
! if (NOTE_P (link))
! continue;
! FOR_EACH_LOG_LINK (next1, link)
! {
! rtx link1 = next1->insn;
! if (NOTE_P (link1))
! continue;
! /* I0 -> I1 -> I2 -> I3. */
! FOR_EACH_LOG_LINK (nextlinks, link1)
! if ((next = try_combine (insn, link, link1,
! nextlinks->insn,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
goto retry;
! /* I0, I1 -> I2, I2 -> I3. */
! for (nextlinks = next1->next; nextlinks;
! nextlinks = nextlinks->next)
! if ((next = try_combine (insn, link, link1,
! nextlinks->insn,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
goto retry;
! }
! for (next1 = links->next; next1; next1 = next1->next)
! {
! rtx link1 = next1->insn;
! if (NOTE_P (link1))
! continue;
! /* I0 -> I2; I1, I2 -> I3. */
! FOR_EACH_LOG_LINK (nextlinks, link)
! if ((next = try_combine (insn, link, link1,
! nextlinks->insn,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
goto retry;
! /* I0 -> I1; I1, I2 -> I3. */
! FOR_EACH_LOG_LINK (nextlinks, link1)
! if ((next = try_combine (insn, link, link1,
! nextlinks->insn,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
goto retry;
! }
! }
! /* Try this insn with each REG_EQUAL note it links back to. */
! FOR_EACH_LOG_LINK (links, insn)
{
! rtx set, note;
! rtx temp = links->insn;
! if ((set = single_set (temp)) != 0
! && (note = find_reg_equal_equiv_note (temp)) != 0
! && (note = XEXP (note, 0), GET_CODE (note)) != EXPR_LIST
! /* Avoid using a register that may already been marked
! dead by an earlier instruction. */
! && ! unmentioned_reg_p (note, SET_SRC (set))
! && (GET_MODE (note) == VOIDmode
! ? SCALAR_INT_MODE_P (GET_MODE (SET_DEST (set)))
! : GET_MODE (SET_DEST (set)) == GET_MODE (note)))
{
! /* Temporarily replace the set's source with the
! contents of the REG_EQUAL note. The insn will
! be deleted or recognized by try_combine. */
! rtx orig = SET_SRC (set);
! SET_SRC (set) = note;
! i2mod = temp;
! i2mod_old_rhs = copy_rtx (orig);
! i2mod_new_rhs = copy_rtx (note);
! next = try_combine (insn, i2mod, NULL_RTX, NULL_RTX,
! &new_direct_jump_p,
! last_combined_insn);
! i2mod = NULL_RTX;
! if (next)
! goto retry;
! SET_SRC (set) = orig;
}
}
! if (!NOTE_P (insn))
! record_dead_and_set_regs (insn);
! retry:
! ;
! }
}
}
--- 1232,1477 ----
insn = next ? next : NEXT_INSN (insn))
{
next = 0;
! if (!NONDEBUG_INSN_P (insn))
! continue;
! while (last_combined_insn
! && INSN_DELETED_P (last_combined_insn))
! last_combined_insn = PREV_INSN (last_combined_insn);
! if (last_combined_insn == NULL_RTX
! || BARRIER_P (last_combined_insn)
! || BLOCK_FOR_INSN (last_combined_insn) != this_basic_block
! || DF_INSN_LUID (last_combined_insn) <= DF_INSN_LUID (insn))
! last_combined_insn = insn;
!
! /* See if we know about function return values before this
! insn based upon SUBREG flags. */
! check_promoted_subreg (insn, PATTERN (insn));
!
! /* See if we can find hardregs and subreg of pseudos in
! narrower modes. This could help turning TRUNCATEs
! into SUBREGs. */
! note_uses (&PATTERN (insn), record_truncated_values, NULL);
!
! /* Try this insn with each insn it links back to. */
!
! FOR_EACH_LOG_LINK (links, insn)
! if ((next = try_combine (insn, links->insn, NULL_RTX,
! NULL_RTX, &new_direct_jump_p,
! last_combined_insn)) != 0)
! {
! statistics_counter_event (cfun, "two-insn combine", 1);
! goto retry;
! }
!
! /* Try each sequence of three linked insns ending with this one. */
!
! if (max_combine >= 3)
! FOR_EACH_LOG_LINK (links, insn)
! {
! rtx link = links->insn;
!
! /* If the linked insn has been replaced by a note, then there
! is no point in pursuing this chain any further. */
! if (NOTE_P (link))
! continue;
!
! FOR_EACH_LOG_LINK (nextlinks, link)
! if ((next = try_combine (insn, link, nextlinks->insn,
! NULL_RTX, &new_direct_jump_p,
! last_combined_insn)) != 0)
! {
! statistics_counter_event (cfun, "three-insn combine", 1);
goto retry;
! }
! }
#ifdef HAVE_cc0
! /* Try to combine a jump insn that uses CC0
! with a preceding insn that sets CC0, and maybe with its
! logical predecessor as well.
! This is how we make decrement-and-branch insns.
! We need this special code because data flow connections
! via CC0 do not get entered in LOG_LINKS. */
!
! if (JUMP_P (insn)
! && (prev = prev_nonnote_insn (insn)) != 0
! && NONJUMP_INSN_P (prev)
! && sets_cc0_p (PATTERN (prev)))
! {
! if ((next = try_combine (insn, prev, NULL_RTX, NULL_RTX,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
! goto retry;
!
! FOR_EACH_LOG_LINK (nextlinks, prev)
! if ((next = try_combine (insn, prev, nextlinks->insn,
! NULL_RTX, &new_direct_jump_p,
last_combined_insn)) != 0)
goto retry;
+ }
! /* Do the same for an insn that explicitly references CC0. */
! if (NONJUMP_INSN_P (insn)
! && (prev = prev_nonnote_insn (insn)) != 0
! && NONJUMP_INSN_P (prev)
! && sets_cc0_p (PATTERN (prev))
! && GET_CODE (PATTERN (insn)) == SET
! && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
! {
! if ((next = try_combine (insn, prev, NULL_RTX, NULL_RTX,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
! goto retry;
!
! FOR_EACH_LOG_LINK (nextlinks, prev)
! if ((next = try_combine (insn, prev, nextlinks->insn,
! NULL_RTX, &new_direct_jump_p,
last_combined_insn)) != 0)
goto retry;
+ }
! /* Finally, see if any of the insns that this insn links to
! explicitly references CC0. If so, try this insn, that insn,
! and its predecessor if it sets CC0. */
! FOR_EACH_LOG_LINK (links, insn)
! if (NONJUMP_INSN_P (links->insn)
! && GET_CODE (PATTERN (links->insn)) == SET
! && reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (links->insn)))
! && (prev = prev_nonnote_insn (links->insn)) != 0
! && NONJUMP_INSN_P (prev)
! && sets_cc0_p (PATTERN (prev))
! && (next = try_combine (insn, links->insn,
! prev, NULL_RTX, &new_direct_jump_p,
! last_combined_insn)) != 0)
! goto retry;
#endif
! /* Try combining an insn with two different insns whose results it
! uses. */
! if (max_combine >= 3)
! FOR_EACH_LOG_LINK (links, insn)
! for (nextlinks = links->next; nextlinks;
! nextlinks = nextlinks->next)
! if ((next = try_combine (insn, links->insn,
! nextlinks->insn, NULL_RTX,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
! {
! statistics_counter_event (cfun, "three-insn combine", 1);
! goto retry;
! }
! /* Try four-instruction combinations. */
! if (max_combine >= 4)
! FOR_EACH_LOG_LINK (links, insn)
! {
! struct insn_link *next1;
! rtx link = links->insn;
!
! /* If the linked insn has been replaced by a note, then there
! is no point in pursuing this chain any further. */
! if (NOTE_P (link))
! continue;
!
! FOR_EACH_LOG_LINK (next1, link)
! {
! rtx link1 = next1->insn;
! if (NOTE_P (link1))
! continue;
! /* I0 -> I1 -> I2 -> I3. */
! FOR_EACH_LOG_LINK (nextlinks, link1)
! if ((next = try_combine (insn, link, link1,
! nextlinks->insn,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
! {
! statistics_counter_event (cfun, "four-insn combine", 1);
goto retry;
! }
! /* I0, I1 -> I2, I2 -> I3. */
! for (nextlinks = next1->next; nextlinks;
! nextlinks = nextlinks->next)
! if ((next = try_combine (insn, link, link1,
! nextlinks->insn,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
! {
! statistics_counter_event (cfun, "four-insn combine", 1);
goto retry;
! }
! }
! for (next1 = links->next; next1; next1 = next1->next)
! {
! rtx link1 = next1->insn;
! if (NOTE_P (link1))
! continue;
! /* I0 -> I2; I1, I2 -> I3. */
! FOR_EACH_LOG_LINK (nextlinks, link)
! if ((next = try_combine (insn, link, link1,
! nextlinks->insn,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
! {
! statistics_counter_event (cfun, "four-insn combine", 1);
goto retry;
! }
! /* I0 -> I1; I1, I2 -> I3. */
! FOR_EACH_LOG_LINK (nextlinks, link1)
! if ((next = try_combine (insn, link, link1,
! nextlinks->insn,
! &new_direct_jump_p,
! last_combined_insn)) != 0)
! {
! statistics_counter_event (cfun, "four-insn combine", 1);
goto retry;
! }
! }
! }
! /* Try this insn with each REG_EQUAL note it links back to. */
! FOR_EACH_LOG_LINK (links, insn)
! {
! rtx set, note;
! rtx temp = links->insn;
! if ((set = single_set (temp)) != 0
! && (note = find_reg_equal_equiv_note (temp)) != 0
! && (note = XEXP (note, 0), GET_CODE (note)) != EXPR_LIST
! /* Avoid using a register that may already been marked
! dead by an earlier instruction. */
! && ! unmentioned_reg_p (note, SET_SRC (set))
! && (GET_MODE (note) == VOIDmode
! ? SCALAR_INT_MODE_P (GET_MODE (SET_DEST (set)))
! : GET_MODE (SET_DEST (set)) == GET_MODE (note)))
{
! /* Temporarily replace the set's source with the
! contents of the REG_EQUAL note. The insn will
! be deleted or recognized by try_combine. */
! rtx orig = SET_SRC (set);
! SET_SRC (set) = note;
! i2mod = temp;
! i2mod_old_rhs = copy_rtx (orig);
! i2mod_new_rhs = copy_rtx (note);
! next = try_combine (insn, i2mod, NULL_RTX, NULL_RTX,
! &new_direct_jump_p,
! last_combined_insn);
! i2mod = NULL_RTX;
! if (next)
{
! statistics_counter_event (cfun, "insn-with-note combine", 1);
! goto retry;
}
+ SET_SRC (set) = orig;
}
+ }
! if (!NOTE_P (insn))
! record_dead_and_set_regs (insn);
! retry:
! ;
}
}
Index: gcc/doc/invoke.texi
===================================================================
*** gcc/doc/invoke.texi (revision 212548)
--- gcc/doc/invoke.texi (working copy)
*************** The maximum size measured as number of R
*** 10006,10011 ****
--- 10006,10015 ----
in combiner for a pseudo register as last known value of that register. The default
is 10000.
+ @item max-combine-insns
+ The maximum number of instructions the RTL combiner tries to combine.
+ The default value is 2 at @option{-Og} and 4 otherwise.
+
@item integer-share-limit
Small integer constants can use a shared data structure, reducing the
compiler's memory usage and increasing its speed. This sets the maximum