This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
RE: Constant folding and Constant propagation
- From: "Rahul Kharche" <rahul at IceraSemi dot com>
- To: "Jean Christophe Beyler" <jean dot christophe dot beyler at gmail dot com>
- Cc: <gcc at gcc dot gnu dot org>
- Date: Thu, 26 Feb 2009 11:31:07 -0000
- Subject: RE: Constant folding and Constant propagation
- References: <AcmLtUt9T1og4J5PQuuxAyjxmaEoPA==> <4D60B0700D1DB54A8C0C6E9BE691637008EB795E@EXCHANGEVS.IceraSemi.local> <c568a2600902251424s2409ddbv9d1555335a697566@mail.gmail.com>
Hi Jean,
> Do you have a link to that patch? So that I can see if it applies for
me ?
See patch below. I put in some comments to try and explain what I have
attempted to do.
The hash SET generation, to track potential candidates in replacing a
register USE, needed some tweaking. This function was not tracking
register copies if the associated INSN had a NOTE attached that
associated the register with a constant. Also, only the last register
or constant in an assignment chain was being added to the hash SET.
It may be profitable to have a closer register copy in the assignment
chain as a potential replacement.
Before the actual replacing operation, the cost of temporary replacement
is determined using rtx_cost. A cost cannot be reliably formed if we
come
across jump INSNs because they may alter jumps or successors. The
default
replacement is used in this case.
Rahul
Index: gcse.c
===================================================================
--- gcse.c (revision 141156)
+++ gcse.c (working copy)
@@ -520,7 +520,7 @@
static void record_set_info (rtx, const_rtx, void *);
static void compute_sets (void);
static void hash_scan_insn (rtx, struct hash_table *, int);
-static void hash_scan_set (rtx, rtx, struct hash_table *);
+static void hash_scan_set (rtx, rtx, struct hash_table *, bool);
static void hash_scan_clobber (rtx, rtx, struct hash_table *);
static void hash_scan_call (rtx, rtx, struct hash_table *);
static int want_to_gcse_p (rtx);
@@ -560,7 +560,7 @@
static void compute_cprop_data (void);
static void find_used_regs (rtx *, void *);
static int try_replace_reg (rtx, rtx, rtx);
-static struct expr *find_avail_set (int, rtx);
+static struct expr *find_avail_set (int, rtx, bool);
static int cprop_jump (basic_block, rtx, rtx, rtx, rtx);
static void mems_conflict_for_gcse_p (rtx, const_rtx, void *);
static int load_killed_in_block_p (const_basic_block, int, const_rtx,
int);
@@ -1671,11 +1671,11 @@
expression one). */
static void
-hash_scan_set (rtx pat, rtx insn, struct hash_table *table)
+hash_scan_set (rtx pat, rtx insn, struct hash_table *table, bool
use_note)
{
rtx src = SET_SRC (pat);
rtx dest = SET_DEST (pat);
- rtx note;
+ rtx note = NULL_RTX;
if (GET_CODE (src) == CALL)
hash_scan_call (src, insn, table);
@@ -1685,16 +1685,21 @@
unsigned int regno = REGNO (dest);
rtx tmp;
- /* See if a REG_NOTE shows this equivalent to a simpler
expression.
- This allows us to do a single GCSE pass and still eliminate
- redundant constants, addresses or other expressions that are
- constructed with multiple instructions. */
- note = find_reg_equal_equiv_note (insn);
- if (note != 0
- && (table->set_p
- ? gcse_constant_p (XEXP (note, 0))
- : want_to_gcse_p (XEXP (note, 0))))
- src = XEXP (note, 0), pat = gen_rtx_SET (VOIDmode, dest, src);
+ /* Do not substitute insn SET_SRC for note if caller uses
+ uses use_note = false. */
+ if (use_note)
+ {
+ /* See if a REG_NOTE shows this equivalent to a simpler
expression.
+ This allows us to do a single GCSE pass and still eliminate
+ redundant constants, addresses or other expressions that
are
+ constructed with multiple instructions. */
+ note = find_reg_equal_equiv_note (insn);
+ if (note != 0
+ && (table->set_p
+ ? gcse_constant_p (XEXP (note, 0))
+ : want_to_gcse_p (XEXP (note, 0))))
+ src = XEXP (note, 0), pat = gen_rtx_SET (VOIDmode, dest,
src);
+ }
/* Only record sets of pseudo-regs in the hash table. */
if (! table->set_p
@@ -1835,14 +1840,30 @@
what's been modified. */
if (GET_CODE (pat) == SET)
- hash_scan_set (pat, insn, table);
+ {
+ /* If we're hashing SETs for constant/copy propagation
+ also hash a SET ignoring any insn notes. */
+ if (table->set_p)
+ {
+ hash_scan_set (pat, insn, table, false);
+ }
+ hash_scan_set (pat, insn, table, true);
+ }
else if (GET_CODE (pat) == PARALLEL)
for (i = 0; i < XVECLEN (pat, 0); i++)
{
rtx x = XVECEXP (pat, 0, i);
if (GET_CODE (x) == SET)
- hash_scan_set (x, insn, table);
+ {
+ /* If we're hashing SETs for constant/copy propagation
+ also hash a SET ignoring any insn notes. */
+ if (table->set_p)
+ {
+ hash_scan_set (x, insn, table, false);
+ }
+ hash_scan_set (x, insn, table, true);
+ }
else if (GET_CODE (x) == CLOBBER)
hash_scan_clobber (x, insn, table);
else if (GET_CODE (x) == CALL)
@@ -2071,7 +2092,7 @@
if (table->set_p
&& implicit_sets[current_bb->index] != NULL_RTX)
hash_scan_set (implicit_sets[current_bb->index],
- BB_HEAD (current_bb), table);
+ BB_HEAD (current_bb), table, true);
/* The next pass builds the hash table. */
in_libcall_block = 0;
@@ -2701,7 +2722,7 @@
NULL no such set is found. */
static struct expr *
-find_avail_set (int regno, rtx insn)
+find_avail_set (int regno, rtx insn, bool follow_chain)
{
/* SET1 contains the last set found that can be returned to the
caller for
use in a substitution. */
@@ -2716,7 +2737,7 @@
This can not happen since the set of (reg Y) would have killed the
set of (reg X) making it unavailable at the start of this block.
*/
- while (1)
+ do
{
rtx src;
struct expr *set = lookup_set (regno, &set_hash_table);
@@ -2758,6 +2779,7 @@
and see if we have an available copy into SRC. */
regno = REGNO (src);
}
+ while (follow_chain);
/* SET1 holds the last set that was available and anticipatable at
INSN. */
@@ -2944,7 +2966,12 @@
unsigned int regno = REGNO (reg_used->reg_rtx);
rtx pat, src;
struct expr *set;
+ int set_cost = INT_MAX;
+ rtx src_first;
+ struct expr *set_first;
+ int set_first_cost = INT_MAX;
+
/* Ignore registers created by GCSE.
We do this because ... */
if (regno >= max_gcse_regno)
@@ -2957,10 +2984,72 @@
/* Find an assignment that sets reg_used and is available
at the start of the block. */
- set = find_avail_set (regno, insn);
+ set = find_avail_set (regno, insn, true);
if (! set)
continue;
+ src = SET_SRC (set->expr);
+
+ /* If possible, determine the cost of substituting the
+ last definition in the target insn */
+ rtx insn_set = make_insn_raw (copy_insn (PATTERN (insn)));
+ if (NONJUMP_INSN_P (insn_set)
+ && try_replace_reg (reg_used->reg_rtx, src, insn_set))
+ {
+ set_cost = rtx_cost (PATTERN (insn_set),
+ GET_CODE (PATTERN (insn_set)));
+
+ /* Bias heavily for last definition if we managed to
+ delete target insn with this substitution */
+ if (INSN_DELETED_P (insn_set))
+ set_cost = 0;
+ }
+ /* Might be a alter_jumps and jump insn case which we neglect
+ in costing this option */
+ /* Find the first definition that sets reg_used
+ i.e. not following the assignment chain */
+ set_first = find_avail_set (regno, insn, false);
+
+ /* If we have a closest definition available, cost the
replacement of
+ first definition (set_first) Vs last definition (in the
assignment chain) */
+ if (set_first
+ /* If we cannot deduce the cost of propagating constants into
+ jump insns, go with constant propagation */
+ && (!alter_jumps
+ || !((any_condjump_p (insn) && onlyjump_p (insn))
+ || (NEXT_INSN (insn) && any_condjump_p (NEXT_INSN
(insn))
+ && onlyjump_p (NEXT_INSN (insn))))))
+ {
+ src_first = SET_SRC (set_first->expr);
+
+ if (REG_P (src_first)
+ && REGNO (src_first) >= FIRST_PSEUDO_REGISTER
+ && REGNO (src_first) != regno)
+ {
+ rtx insn_set_first = make_insn_raw (copy_insn (PATTERN
(insn)));
+ if (try_replace_reg (reg_used->reg_rtx, src_first,
insn_set_first))
+ {
+ set_first_cost = rtx_cost (PATTERN (insn_set_first),
+ GET_CODE (PATTERN
(insn_set_first)));
+ }
+ }
+
+ if (set_first_cost < set_cost)
+ {
+ set = set_first;
+ set_cost = set_first_cost;
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "cprop_insn prefer ");
+ print_inline_rtx (dump_file, SET_SRC
(set_first->expr), 2);
+ fprintf (dump_file, " cost %d over ",
set_first_cost);
+ print_inline_rtx (dump_file, SET_SRC (set->expr), 2);
+ fprintf (dump_file, " cost %d\n", set_cost);
+ }
+ }
+ }
+
pat = set->expr;
/* ??? We might be able to handle PARALLELs. Later. */
gcc_assert (GET_CODE (pat) == SET);