* [patch] Split parts of cse_insn out to a few new functions
@ 2012-03-20 21:07 Steven Bosscher
2012-03-21 0:14 ` Ian Lance Taylor
0 siblings, 1 reply; 6+ messages in thread
From: Steven Bosscher @ 2012-03-20 21:07 UTC (permalink / raw)
To: GCC Patches
[-- Attachment #1: Type: text/plain, Size: 589 bytes --]
Hello,
This patch splits a couple of pieces of cse_insn out to new functions.
There are no functional changes, and no code generation differences as
far as I could tell on x86_64 (-m64 and -m32).
The purpose of the patch is and, loto hopefully make cse_insn easier
to understand. In a follow-up patch, I will make canonicalize_insn run
only once per insn (it currently, i.e. before and after this patch,
runs multiple times for CSE on extended basic blocks if a block is in
multiple extended basic blocks).
Bootstrapped & tested on x86_64-unknown-linux-gnu. OK for trunk?
Ciao!
Steven
[-- Attachment #2: splitup_cse_insn_1.diff.txt --]
[-- Type: text/plain, Size: 21886 bytes --]
* cse.c (invalidate_from_sets_and_clobbers, try_back_substitute_reg,
find_sets_in_insn, canonicalize_insn): Split out from ...
(cse_insn): ... here.
(invalidate_from_clobbers): Take an insn instead of the pattern.
Index: cse.c
===================================================================
--- cse.c (revision 185515)
+++ cse.c (working copy)
@@ -597,6 +597,7 @@ static void record_jump_cond (enum rtx_c
static void cse_insn (rtx);
static void cse_prescan_path (struct cse_basic_block_data *);
static void invalidate_from_clobbers (rtx);
+static void invalidate_from_sets_and_clobbers (rtx);
static rtx cse_process_notes (rtx, rtx, bool *);
static void cse_extended_basic_block (struct cse_basic_block_data *);
static void count_reg_usage (rtx, int *, rtx, int);
@@ -4089,10 +4090,22 @@ record_jump_cond (enum rtx_code code, en
}
\f
/* CSE processing for one instruction.
- First simplify sources and addresses of all assignments
- in the instruction, using previously-computed equivalents values.
- Then install the new sources and destinations in the table
- of available values. */
+
+ Most "true" common subexpressions are mostly optimized away in GIMPLE,
+ but the few that "leak through" are cleaned up by cse_insn, and complex
+ addressing modes are often formed here.
+
+ The main function is cse_insn, and between here and that function
+ a couple of helper functions is defined to keep the size of cse_insn
+ within reasonable proportions.
+
+ Data is shared between the main and helper functions via STRUCT SET,
+ that contains all data related for every set in the instruction that
+ is being processed.
+
+ Note that cse_main processes all sets in the instruction. Most
+ passes in GCC only process simple SET insns or single_set insns, but
+ CSE processes insns with multiple sets as well. */
/* Data on one SET contained in the instruction. */
@@ -4128,50 +4141,93 @@ struct set
/* Table entry for the destination address. */
struct table_elt *dest_addr_elt;
};
+\f
+/* Special handling for (set REG0 REG1) where REG0 is the
+ "cheapest", cheaper than REG1. After cse, REG1 will probably not
+ be used in the sequel, so (if easily done) change this insn to
+ (set REG1 REG0) and replace REG1 with REG0 in the previous insn
+ that computed their value. Then REG1 will become a dead store
+ and won't cloud the situation for later optimizations.
+
+ Do not make this change if REG1 is a hard register, because it will
+ then be used in the sequel and we may be changing a two-operand insn
+ into a three-operand insn.
+
+ This is the last transformation that cse_insn will try to do. */
static void
-cse_insn (rtx insn)
+try_back_substitute_reg (rtx set, rtx insn)
{
- rtx x = PATTERN (insn);
- int i;
- rtx tem;
- int n_sets = 0;
+ rtx dest = SET_DEST (set);
+ rtx src = SET_SRC (set);
- rtx src_eqv = 0;
- struct table_elt *src_eqv_elt = 0;
- int src_eqv_volatile = 0;
- int src_eqv_in_memory = 0;
- unsigned src_eqv_hash = 0;
+ if (REG_P (dest)
+ && REG_P (src) && ! HARD_REGISTER_P (src)
+ && REGNO_QTY_VALID_P (REGNO (src)))
+ {
+ int src_q = REG_QTY (REGNO (src));
+ struct qty_table_elem *src_ent = &qty_table[src_q];
- struct set *sets = (struct set *) 0;
+ if (src_ent->first_reg == REGNO (dest))
+ {
+ /* Scan for the previous nonnote insn, but stop at a basic
+ block boundary. */
+ rtx prev = insn;
+ rtx bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
+ do
+ {
+ prev = PREV_INSN (prev);
+ }
+ while (prev != bb_head && (NOTE_P (prev) || DEBUG_INSN_P (prev)));
- this_insn = insn;
-#ifdef HAVE_cc0
- /* Records what this insn does to set CC0. */
- this_insn_cc0 = 0;
- this_insn_cc0_mode = VOIDmode;
-#endif
+ /* Do not swap the registers around if the previous instruction
+ attaches a REG_EQUIV note to REG1.
- /* Find all the SETs and CLOBBERs in this instruction.
- Record all the SETs in the array `set' and count them.
- Also determine whether there is a CLOBBER that invalidates
- all memory references, or all references at varying addresses. */
+ ??? It's not entirely clear whether we can transfer a REG_EQUIV
+ from the pseudo that originally shadowed an incoming argument
+ to another register. Some uses of REG_EQUIV might rely on it
+ being attached to REG1 rather than REG2.
- if (CALL_P (insn))
- {
- for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
- {
- if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
- invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
- XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
+ This section previously turned the REG_EQUIV into a REG_EQUAL
+ note. We cannot do that because REG_EQUIV may provide an
+ uninitialized stack slot when REG_PARM_STACK_SPACE is used. */
+ if (NONJUMP_INSN_P (prev)
+ && GET_CODE (PATTERN (prev)) == SET
+ && SET_DEST (PATTERN (prev)) == src
+ && ! find_reg_note (prev, REG_EQUIV, NULL_RTX))
+ {
+ rtx note;
+
+ validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
+ validate_change (insn, &SET_DEST (set), src, 1);
+ validate_change (insn, &SET_SRC (set), dest, 1);
+ apply_change_group ();
+
+ /* If INSN has a REG_EQUAL note, and this note mentions
+ REG0, then we must delete it, because the value in
+ REG0 has changed. If the note's value is REG1, we must
+ also delete it because that is now this insn's dest. */
+ note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+ if (note != 0
+ && (reg_mentioned_p (dest, XEXP (note, 0))
+ || rtx_equal_p (src, XEXP (note, 0))))
+ remove_note (insn, note);
+ }
}
}
+}
+\f
+/* Record all the SETs in this instruction into SETS_PTR,
+ and return the number of recorded sets. */
+static int
+find_sets_in_insn (rtx insn, struct set **psets)
+{
+ struct set *sets = *psets;
+ int n_sets = 0;
+ rtx x = PATTERN (insn);
if (GET_CODE (x) == SET)
{
- sets = XALLOCA (struct set);
- sets[0].rtl = x;
-
/* Ignore SETs that are unconditional jumps.
They never need cse processing, so this does not hurt.
The reason is not efficiency but rather
@@ -4182,57 +4238,20 @@ cse_insn (rtx insn)
if (SET_DEST (x) == pc_rtx
&& GET_CODE (SET_SRC (x)) == LABEL_REF)
;
-
/* Don't count call-insns, (set (reg 0) (call ...)), as a set.
The hard function value register is used only once, to copy to
- someplace else, so it isn't worth cse'ing (and on 80386 is unsafe)!
- Ensure we invalidate the destination register. On the 80386 no
- other code would invalidate it since it is a fixed_reg.
- We need not check the return of apply_change_group; see canon_reg. */
-
+ someplace else, so it isn't worth cse'ing. */
else if (GET_CODE (SET_SRC (x)) == CALL)
- {
- canon_reg (SET_SRC (x), insn);
- apply_change_group ();
- fold_rtx (SET_SRC (x), insn);
- invalidate (SET_DEST (x), VOIDmode);
- }
+ ;
else
- n_sets = 1;
+ sets[n_sets++].rtl = x;
}
else if (GET_CODE (x) == PARALLEL)
{
- int lim = XVECLEN (x, 0);
-
- sets = XALLOCAVEC (struct set, lim);
-
- /* Find all regs explicitly clobbered in this insn,
- and ensure they are not replaced with any other regs
- elsewhere in this insn.
- When a reg that is clobbered is also used for input,
- we should presume that that is for a reason,
- and we should not substitute some other register
- which is not supposed to be clobbered.
- Therefore, this loop cannot be merged into the one below
- because a CALL may precede a CLOBBER and refer to the
- value clobbered. We must not let a canonicalization do
- anything in that case. */
- for (i = 0; i < lim; i++)
- {
- rtx y = XVECEXP (x, 0, i);
- if (GET_CODE (y) == CLOBBER)
- {
- rtx clobbered = XEXP (y, 0);
-
- if (REG_P (clobbered)
- || GET_CODE (clobbered) == SUBREG)
- invalidate (clobbered, VOIDmode);
- else if (GET_CODE (clobbered) == STRICT_LOW_PART
- || GET_CODE (clobbered) == ZERO_EXTRACT)
- invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
- }
- }
+ int i, lim = XVECLEN (x, 0);
+ /* Go over the epressions of the PARALLEL in forward order, to
+ put them in the same order in the SETS array. */
for (i = 0; i < lim; i++)
{
rtx y = XVECEXP (x, 0, i);
@@ -4240,50 +4259,80 @@ cse_insn (rtx insn)
{
/* As above, we ignore unconditional jumps and call-insns and
ignore the result of apply_change_group. */
- if (GET_CODE (SET_SRC (y)) == CALL)
- {
- canon_reg (SET_SRC (y), insn);
- apply_change_group ();
- fold_rtx (SET_SRC (y), insn);
- invalidate (SET_DEST (y), VOIDmode);
- }
- else if (SET_DEST (y) == pc_rtx
- && GET_CODE (SET_SRC (y)) == LABEL_REF)
+ if (SET_DEST (y) == pc_rtx
+ && GET_CODE (SET_SRC (y)) == LABEL_REF)
+ ;
+ else if (GET_CODE (SET_SRC (y)) == CALL)
;
else
sets[n_sets++].rtl = y;
}
- else if (GET_CODE (y) == CLOBBER)
- {
- /* If we clobber memory, canon the address.
- This does nothing when a register is clobbered
- because we have already invalidated the reg. */
- if (MEM_P (XEXP (y, 0)))
- canon_reg (XEXP (y, 0), insn);
- }
- else if (GET_CODE (y) == USE
- && ! (REG_P (XEXP (y, 0))
- && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
- canon_reg (y, insn);
- else if (GET_CODE (y) == CALL)
- {
- /* The result of apply_change_group can be ignored; see
- canon_reg. */
- canon_reg (y, insn);
- apply_change_group ();
- fold_rtx (y, insn);
- }
}
}
+
+ return n_sets;
+}
+\f
+/* Where possible, substitute every register reference in the N_SETS
+ number of SETS in INSN with the the canonical register.
+
+ Register canonicalization propagatest the earliest register (i.e.
+ one that is set before INSN) with the same value. This is a very
+ useful, simple form of CSE, to clean up warts from expanding GIMPLE
+ to RTL. For instance, a CONST for an address is usually expanded
+ multiple times to loads into different registers, thus creating many
+ subexpressions of the form:
+
+ (set (reg1) (some_const))
+ (set (mem (... reg1 ...) (thing)))
+ (set (reg2) (some_const))
+ (set (mem (... reg2 ...) (thing)))
+
+ After canonicalizing, the code takes the following form:
+
+ (set (reg1) (some_const))
+ (set (mem (... reg1 ...) (thing)))
+ (set (reg2) (some_const))
+ (set (mem (... reg1 ...) (thing)))
+
+ The set to reg2 is now trivially dead, and the memory reference (or
+ address, or whatever) may be a candidate for further CSEing.
+
+ In this function, the result of apply_change_group can be ignored;
+ see canon_reg. */
+
+static void
+canonicalize_insn (rtx insn, struct set **psets, int n_sets)
+{
+ struct set *sets = *psets;
+ rtx tem;
+ rtx x = PATTERN (insn);
+ int i;
+
+ if (CALL_P (insn))
+ {
+ for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
+ XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
+ }
+
+ if (GET_CODE (x) == SET && GET_CODE (SET_SRC (x)) == CALL)
+ {
+ canon_reg (SET_SRC (x), insn);
+ apply_change_group ();
+ fold_rtx (SET_SRC (x), insn);
+ }
else if (GET_CODE (x) == CLOBBER)
{
+ /* If we clobber memory, canon the address.
+ This does nothing when a register is clobbered
+ because we have already invalidated the reg. */
if (MEM_P (XEXP (x, 0)))
canon_reg (XEXP (x, 0), insn);
}
- /* Canonicalize a USE of a pseudo register or memory location. */
else if (GET_CODE (x) == USE
&& ! (REG_P (XEXP (x, 0))
&& REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
+ /* Canonicalize a USE of a pseudo register or memory location. */
canon_reg (x, insn);
else if (GET_CODE (x) == ASM_OPERANDS)
{
@@ -4299,29 +4348,60 @@ cse_insn (rtx insn)
}
else if (GET_CODE (x) == CALL)
{
- /* The result of apply_change_group can be ignored; see canon_reg. */
canon_reg (x, insn);
apply_change_group ();
fold_rtx (x, insn);
}
else if (DEBUG_INSN_P (insn))
canon_reg (PATTERN (insn), insn);
+ else if (GET_CODE (x) == PARALLEL)
+ {
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ {
+ rtx y = XVECEXP (x, 0, i);
+ if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
+ {
+ canon_reg (SET_SRC (y), insn);
+ apply_change_group ();
+ fold_rtx (SET_SRC (y), insn);
+ }
+ else if (GET_CODE (y) == CLOBBER)
+ {
+ if (MEM_P (XEXP (y, 0)))
+ canon_reg (XEXP (y, 0), insn);
+ }
+ else if (GET_CODE (y) == USE
+ && ! (REG_P (XEXP (y, 0))
+ && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
+ canon_reg (y, insn);
+ else if (GET_CODE (y) == CALL)
+ {
+ canon_reg (y, insn);
+ apply_change_group ();
+ fold_rtx (y, insn);
+ }
+ }
+ }
- /* Store the equivalent value in SRC_EQV, if different, or if the DEST
- is a STRICT_LOW_PART. The latter condition is necessary because SRC_EQV
- is handled specially for this case, and if it isn't set, then there will
- be no equivalence for the destination. */
if (n_sets == 1 && REG_NOTES (insn) != 0
- && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0
- && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
- || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
+ && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0)
{
- /* The result of apply_change_group can be ignored; see canon_reg. */
- canon_reg (XEXP (tem, 0), insn);
- apply_change_group ();
- src_eqv = fold_rtx (XEXP (tem, 0), insn);
- XEXP (tem, 0) = copy_rtx (src_eqv);
- df_notes_rescan (insn);
+ /* We potentially will process this insn many times. Therefore,
+ drop the REG_EQUAL note if it is equal to the SET_SRC of the
+ unique set in INSN.
+
+ Do not do so if the REG_EQUAL note is for a STRICT_LOW_PART,
+ because cse_insn handles those specially. */
+ if (GET_CODE (SET_DEST (sets[0].rtl)) != STRICT_LOW_PART
+ && rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl)))
+ remove_note (insn, tem);
+ else
+ {
+ canon_reg (XEXP (tem, 0), insn);
+ apply_change_group ();
+ XEXP (tem, 0) = fold_rtx (XEXP (tem, 0), insn);
+ df_notes_rescan (insn);
+ }
}
/* Canonicalize sources and addresses of destinations.
@@ -4368,6 +4448,62 @@ cse_insn (rtx insn)
The result of apply_change_group can be ignored; see canon_reg. */
apply_change_group ();
+}
+\f
+/* Main function of CSE.
+ First simplify sources and addresses of all assignments
+ in the instruction, using previously-computed equivalents values.
+ Then install the new sources and destinations in the table
+ of available values. */
+
+static void
+cse_insn (rtx insn)
+{
+ rtx x = PATTERN (insn);
+ int i;
+ rtx tem;
+ int n_sets = 0;
+
+ rtx src_eqv = 0;
+ struct table_elt *src_eqv_elt = 0;
+ int src_eqv_volatile = 0;
+ int src_eqv_in_memory = 0;
+ unsigned src_eqv_hash = 0;
+
+ struct set *sets = (struct set *) 0;
+
+ if (GET_CODE (x) == SET)
+ sets = XALLOCA (struct set);
+ else if (GET_CODE (x) == PARALLEL)
+ sets = XALLOCAVEC (struct set, XVECLEN (x, 0));
+
+ this_insn = insn;
+#ifdef HAVE_cc0
+ /* Records what this insn does to set CC0. */
+ this_insn_cc0 = 0;
+ this_insn_cc0_mode = VOIDmode;
+#endif
+
+ /* Find all regs explicitly clobbered in this insn,
+ to ensure they are not replaced with any other regs
+ elsewhere in this insn. */
+ invalidate_from_sets_and_clobbers (insn);
+
+ /* Record all the SETs in this instruction. */
+ n_sets = find_sets_in_insn (insn, &sets);
+
+ /* Substitute the canonical register where possible. */
+ canonicalize_insn (insn, &sets, n_sets);
+
+ /* If this insn has a REG_EQUAL note, store the equivalent value in SRC_EQV,
+ if different, or if the DEST is a STRICT_LOW_PART. The latter condition
+ is necessary because SRC_EQV is handled specially for this case, and if
+ it isn't set, then there will be no equivalence for the destination. */
+ if (n_sets == 1 && REG_NOTES (insn) != 0
+ && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0
+ && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
+ || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
+ src_eqv = copy_rtx (XEXP (tem, 0));
/* Set sets[i].src_elt to the class each source belongs to.
Detect assignments from or to volatile things
@@ -5492,7 +5628,7 @@ cse_insn (rtx insn)
}
}
- invalidate_from_clobbers (x);
+ invalidate_from_clobbers (insn);
/* Some registers are invalidated by subroutine calls. Memory is
invalidated by non-constant calls. */
@@ -5788,64 +5924,8 @@ cse_insn (rtx insn)
Also do not do this if we are operating on a copy of INSN. */
- if (n_sets == 1 && sets[0].rtl && REG_P (SET_DEST (sets[0].rtl))
- && NEXT_INSN (PREV_INSN (insn)) == insn
- && REG_P (SET_SRC (sets[0].rtl))
- && REGNO (SET_SRC (sets[0].rtl)) >= FIRST_PSEUDO_REGISTER
- && REGNO_QTY_VALID_P (REGNO (SET_SRC (sets[0].rtl))))
- {
- int src_q = REG_QTY (REGNO (SET_SRC (sets[0].rtl)));
- struct qty_table_elem *src_ent = &qty_table[src_q];
-
- if (src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
- {
- /* Scan for the previous nonnote insn, but stop at a basic
- block boundary. */
- rtx prev = insn;
- rtx bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
- do
- {
- prev = PREV_INSN (prev);
- }
- while (prev != bb_head && (NOTE_P (prev) || DEBUG_INSN_P (prev)));
-
- /* Do not swap the registers around if the previous instruction
- attaches a REG_EQUIV note to REG1.
-
- ??? It's not entirely clear whether we can transfer a REG_EQUIV
- from the pseudo that originally shadowed an incoming argument
- to another register. Some uses of REG_EQUIV might rely on it
- being attached to REG1 rather than REG2.
-
- This section previously turned the REG_EQUIV into a REG_EQUAL
- note. We cannot do that because REG_EQUIV may provide an
- uninitialized stack slot when REG_PARM_STACK_SPACE is used. */
- if (NONJUMP_INSN_P (prev)
- && GET_CODE (PATTERN (prev)) == SET
- && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl)
- && ! find_reg_note (prev, REG_EQUIV, NULL_RTX))
- {
- rtx dest = SET_DEST (sets[0].rtl);
- rtx src = SET_SRC (sets[0].rtl);
- rtx note;
-
- validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
- validate_change (insn, &SET_DEST (sets[0].rtl), src, 1);
- validate_change (insn, &SET_SRC (sets[0].rtl), dest, 1);
- apply_change_group ();
-
- /* If INSN has a REG_EQUAL note, and this note mentions
- REG0, then we must delete it, because the value in
- REG0 has changed. If the note's value is REG1, we must
- also delete it because that is now this insn's dest. */
- note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- if (note != 0
- && (reg_mentioned_p (dest, XEXP (note, 0))
- || rtx_equal_p (src, XEXP (note, 0))))
- remove_note (insn, note);
- }
- }
- }
+ if (n_sets == 1 && sets[0].rtl)
+ try_back_substitute_reg (sets[0].rtl, insn);
done:;
}
@@ -5867,16 +5947,16 @@ invalidate_memory (void)
}
}
-/* Perform invalidation on the basis of everything about an insn
+/* Perform invalidation on the basis of everything about INSN,
except for invalidating the actual places that are SET in it.
This includes the places CLOBBERed, and anything that might
- alias with something that is SET or CLOBBERed.
-
- X is the pattern of the insn. */
+ alias with something that is SET or CLOBBERed. */
static void
-invalidate_from_clobbers (rtx x)
+invalidate_from_clobbers (rtx insn)
{
+ rtx x = PATTERN (insn);
+
if (GET_CODE (x) == CLOBBER)
{
rtx ref = XEXP (x, 0);
@@ -5910,6 +5990,53 @@ invalidate_from_clobbers (rtx x)
}
}
\f
+/* Perform invalidation on the basis of everything about INSN.
+ This includes the places CLOBBERed, and anything that might
+ alias with something that is SET or CLOBBERed. */
+
+static void
+invalidate_from_sets_and_clobbers (rtx insn)
+{
+ rtx tem;
+ rtx x = PATTERN (insn);
+
+ if (CALL_P (insn))
+ {
+ for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
+ if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
+ invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+ }
+
+ /* Ensure we invalidate the destination register of a CALL insn.
+ This is necessary for machines where this register is a fixed_reg,
+ because no other code would invalidate it. */
+ if (GET_CODE (x) == SET && GET_CODE (SET_SRC (x)) == CALL)
+ invalidate (SET_DEST (x), VOIDmode);
+
+ else if (GET_CODE (x) == PARALLEL)
+ {
+ int i;
+
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ {
+ rtx y = XVECEXP (x, 0, i);
+ if (GET_CODE (y) == CLOBBER)
+ {
+ rtx clobbered = XEXP (y, 0);
+
+ if (REG_P (clobbered)
+ || GET_CODE (clobbered) == SUBREG)
+ invalidate (clobbered, VOIDmode);
+ else if (GET_CODE (clobbered) == STRICT_LOW_PART
+ || GET_CODE (clobbered) == ZERO_EXTRACT)
+ invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
+ }
+ else if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
+ invalidate (SET_DEST (y), VOIDmode);
+ }
+ }
+}
+\f
/* Process X, part of the REG_NOTES of an insn. Look at any REG_EQUAL notes
and replace any registers in them with either an equivalent constant
or the canonical form of the register. If we are inside an address,
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] Split parts of cse_insn out to a few new functions
2012-03-20 21:07 [patch] Split parts of cse_insn out to a few new functions Steven Bosscher
@ 2012-03-21 0:14 ` Ian Lance Taylor
2012-03-21 23:10 ` Steven Bosscher
0 siblings, 1 reply; 6+ messages in thread
From: Ian Lance Taylor @ 2012-03-21 0:14 UTC (permalink / raw)
To: Steven Bosscher; +Cc: GCC Patches
On Tue, Mar 20, 2012 at 2:06 PM, Steven Bosscher <stevenb.gcc@gmail.com> wrote:
>
> This patch splits a couple of pieces of cse_insn out to new functions.
> There are no functional changes, and no code generation differences as
> far as I could tell on x86_64 (-m64 and -m32).
>
> The purpose of the patch is and, loto hopefully make cse_insn easier
> to understand. In a follow-up patch, I will make canonicalize_insn run
> only once per insn (it currently, i.e. before and after this patch,
> runs multiple times for CSE on extended basic blocks if a block is in
> multiple extended basic blocks).
This is OK.
Thanks.
Ian
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] Split parts of cse_insn out to a few new functions
2012-03-21 0:14 ` Ian Lance Taylor
@ 2012-03-21 23:10 ` Steven Bosscher
2012-03-21 23:15 ` Steven Bosscher
2012-03-26 19:02 ` Richard Sandiford
0 siblings, 2 replies; 6+ messages in thread
From: Steven Bosscher @ 2012-03-21 23:10 UTC (permalink / raw)
To: GCC Patches; +Cc: Ian Lance Taylor
[-- Attachment #1: Type: text/plain, Size: 1358 bytes --]
On Wed, Mar 21, 2012 at 1:13 AM, Ian Lance Taylor wrote:
> On Tue, Mar 20, 2012 at 2:06 PM, Steven Bosscher wrote:
>>
>> This patch splits a couple of pieces of cse_insn out to new functions.
>> There are no functional changes, and no code generation differences as
>> far as I could tell on x86_64 (-m64 and -m32).
Likewise for the attached patch.
>> The purpose of the patch is and, loto hopefully make cse_insn easier
>> to understand. In a follow-up patch, I will make canonicalize_insn run
>> only once per insn (it currently, i.e. before and after this patch,
>> runs multiple times for CSE on extended basic blocks if a block is in
>> multiple extended basic blocks).
That is what the attached patch does.
Bootstrapped&tested on x86_64-unknown-linux-gnu.
OK for trunk?
Ciao!
Steven
* cse.c (cse_canonicalized_basic_blocks): New simple bitmap to
tag basic blocks that have already been traversed at least once,
so that all insns have been canonicalized.
(cse_insn): Call canonicalize_insn only if the basic block that
contains insn is visited for the first time.
(cse_extended_basic_block): After visiting all insns in a basic
block, mark the block in cse_canonicalized_basic_blocks.
(cse_main): Setup and destroy cse_canonicalized_basic_blocks.
(cse_find_path): Micro-optimization, reorder one condition to
avoid a reference to cfun.
[-- Attachment #2: canon_insn_once.diff --]
[-- Type: text/x-patch, Size: 3557 bytes --]
* cse.c (cse_canonicalized_basic_blocks): New simple bitmap to
tag basic blocks that have already been traversed at least once,
so that all insns have been canonicalized.
(cse_insn): Call canonicalize_insn only if the basic block that
contains insn is visited for the first time.
(cse_extended_basic_block): After visiting all insns in a basic
block, mark the block in cse_canonicalized_basic_blocks.
(cse_main): Setup and destroy cse_canonicalized_basic_blocks.
(cse_find_path): Micro-optimization, reorder one condition to
avoid a reference to cfun.
Index: cse.c
===================================================================
--- cse.c (revision 185622)
+++ cse.c (working copy)
@@ -551,6 +551,10 @@ static bitmap cse_ebb_live_in, cse_ebb_l
already as part of an already processed extended basic block. */
static sbitmap cse_visited_basic_blocks;
+/* A simple bitmap to track for which basic blocks all insns have been
+ canonicalized already. */
+static sbitmap cse_canonicalized_basic_blocks;
+
static bool fixed_base_plus_p (rtx x);
static int notreg_cost (rtx, enum rtx_code, int);
static int approx_reg_cost_1 (rtx *, void *);
@@ -4492,8 +4496,10 @@ cse_insn (rtx insn)
/* Record all the SETs in this instruction. */
n_sets = find_sets_in_insn (insn, &sets);
- /* Substitute the canonical register where possible. */
- canonicalize_insn (insn, &sets, n_sets);
+ /* If we have not visited this block before (as part of another extended
+ basic block, substitute the canonical register where possible. */
+ if (!TEST_BIT (cse_canonicalized_basic_blocks, BLOCK_FOR_INSN (insn)->index))
+ canonicalize_insn (insn, &sets, n_sets);
/* If this insn has a REG_EQUAL note, store the equivalent value in SRC_EQV,
if different, or if the DEST is a STRICT_LOW_PART. The latter condition
@@ -6254,10 +6260,9 @@ cse_find_path (basic_block first_bb, str
else
e = NULL;
- if (e
- && !((e->flags & EDGE_ABNORMAL_CALL) && cfun->has_nonlocal_label)
- && e->dest != EXIT_BLOCK_PTR
+ if (e && e->dest != EXIT_BLOCK_PTR
&& single_pred_p (e->dest)
+ && !((e->flags & EDGE_ABNORMAL_CALL) && cfun->has_nonlocal_label)
/* Avoid visiting basic blocks twice. The large comment
above explains why this can happen. */
&& !TEST_BIT (cse_visited_basic_blocks, e->dest->index))
@@ -6452,6 +6457,9 @@ cse_extended_basic_block (struct cse_bas
}
}
+ /* We have now canonicalized all insns in this basic block. */
+ SET_BIT (cse_canonicalized_basic_blocks, bb->index);
+
/* With non-call exceptions, we are not always able to update
the CFG properly inside cse_insn. So clean up possibly
redundant EH edges here. */
@@ -6555,6 +6563,10 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nr
cse_visited_basic_blocks = sbitmap_alloc (last_basic_block);
sbitmap_zero (cse_visited_basic_blocks);
+ /* Set up the table of already canonicalized basic blocks. */
+ cse_canonicalized_basic_blocks = sbitmap_alloc (last_basic_block);
+ sbitmap_zero (cse_canonicalized_basic_blocks);
+
/* Loop over basic blocks in reverse completion order (RPO),
excluding the ENTRY and EXIT blocks. */
n_blocks = pre_and_rev_post_order_compute (NULL, rc_order, false);
@@ -6598,6 +6610,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nr
free (reg_eqv_table);
free (ebb_data.path);
sbitmap_free (cse_visited_basic_blocks);
+ sbitmap_free (cse_canonicalized_basic_blocks);
free (rc_order);
rtl_hooks = general_rtl_hooks;
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] Split parts of cse_insn out to a few new functions
2012-03-21 23:10 ` Steven Bosscher
@ 2012-03-21 23:15 ` Steven Bosscher
2012-03-26 19:02 ` Richard Sandiford
1 sibling, 0 replies; 6+ messages in thread
From: Steven Bosscher @ 2012-03-21 23:15 UTC (permalink / raw)
To: GCC Patches; +Cc: Ian Lance Taylor
On Thu, Mar 22, 2012 at 12:09 AM, Steven Bosscher <stevenb.gcc@gmail.com> wrote:
> (cse_find_path): Micro-optimization, reorder one condition to
> avoid a reference to cfun.
Ah, and please ignore this bit. I don't know what I was thinking...
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] Split parts of cse_insn out to a few new functions
2012-03-21 23:10 ` Steven Bosscher
2012-03-21 23:15 ` Steven Bosscher
@ 2012-03-26 19:02 ` Richard Sandiford
2012-03-26 19:13 ` Steven Bosscher
1 sibling, 1 reply; 6+ messages in thread
From: Richard Sandiford @ 2012-03-26 19:02 UTC (permalink / raw)
To: Steven Bosscher; +Cc: GCC Patches, Ian Lance Taylor
Steven Bosscher <stevenb.gcc@gmail.com> writes:
> On Wed, Mar 21, 2012 at 1:13 AM, Ian Lance Taylor wrote:
>> On Tue, Mar 20, 2012 at 2:06 PM, Steven Bosscher wrote:
>>>
>>> This patch splits a couple of pieces of cse_insn out to new functions.
>>> There are no functional changes, and no code generation differences as
>>> far as I could tell on x86_64 (-m64 and -m32).
>
> Likewise for the attached patch.
>
>>> The purpose of the patch is and, loto hopefully make cse_insn easier
>>> to understand. In a follow-up patch, I will make canonicalize_insn run
>>> only once per insn (it currently, i.e. before and after this patch,
>>> runs multiple times for CSE on extended basic blocks if a block is in
>>> multiple extended basic blocks).
>
> That is what the attached patch does.
>
> Bootstrapped&tested on x86_64-unknown-linux-gnu.
> OK for trunk?
>
> Ciao!
> Steven
>
> * cse.c (cse_canonicalized_basic_blocks): New simple bitmap to
> tag basic blocks that have already been traversed at least once,
> so that all insns have been canonicalized.
> (cse_insn): Call canonicalize_insn only if the basic block that
> contains insn is visited for the first time.
> (cse_extended_basic_block): After visiting all insns in a basic
> block, mark the block in cse_canonicalized_basic_blocks.
> (cse_main): Setup and destroy cse_canonicalized_basic_blocks.
OK, thanks (without the microoptimisation, as you say).
Out of curiosity, do you still see this bit as useful:
/* We potentially will process this insn many times. Therefore,
drop the REG_EQUAL note if it is equal to the SET_SRC of the
unique set in INSN.
Do not do so if the REG_EQUAL note is for a STRICT_LOW_PART,
because cse_insn handles those specially. */
? Does "many times" mean in CSE, or later?
Richard
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] Split parts of cse_insn out to a few new functions
2012-03-26 19:02 ` Richard Sandiford
@ 2012-03-26 19:13 ` Steven Bosscher
0 siblings, 0 replies; 6+ messages in thread
From: Steven Bosscher @ 2012-03-26 19:13 UTC (permalink / raw)
To: Steven Bosscher, GCC Patches, Ian Lance Taylor, rdsandiford
On Mon, Mar 26, 2012 at 9:02 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
>> * cse.c (cse_canonicalized_basic_blocks): New simple bitmap to
>> tag basic blocks that have already been traversed at least once,
>> so that all insns have been canonicalized.
>> (cse_insn): Call canonicalize_insn only if the basic block that
>> contains insn is visited for the first time.
>> (cse_extended_basic_block): After visiting all insns in a basic
>> block, mark the block in cse_canonicalized_basic_blocks.
>> (cse_main): Setup and destroy cse_canonicalized_basic_blocks.
>
> OK, thanks (without the microoptimisation, as you say).
Thanks, will commit!
> Out of curiosity, do you still see this bit as useful:
>
> /* We potentially will process this insn many times. Therefore,
> drop the REG_EQUAL note if it is equal to the SET_SRC of the
> unique set in INSN.
>
> Do not do so if the REG_EQUAL note is for a STRICT_LOW_PART,
> because cse_insn handles those specially. */
>
> ? Does "many times" mean in CSE, or later?
It means "in CSE", yes. But with the patch to canonicalize only once,
I suppose this can go away again.
Having said that, I do believe it would be good if we avoid having
REG_EQUAL notes that are rtx_equal_p to the SET_SRC. This happens
quite frequently after CSE. I'm not sure how to clean them up.
Ciao!
Steven
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2012-03-26 19:13 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-20 21:07 [patch] Split parts of cse_insn out to a few new functions Steven Bosscher
2012-03-21 0:14 ` Ian Lance Taylor
2012-03-21 23:10 ` Steven Bosscher
2012-03-21 23:15 ` Steven Bosscher
2012-03-26 19:02 ` Richard Sandiford
2012-03-26 19:13 ` Steven Bosscher
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).