re PR rtl-optimization/64317 (Ineffective allocation of PIC base register)

PR rtl-optimization/64317
        * Makefile.in (OBJS): Add gcse-common.c
        * gcse.c: Include gcse-common.h
        (struct modify_pair_s): Move structure definition to gcse-common.h
        (compute_transp): Move function to gcse-common.c.
        (canon_list_insert): Similarly.
        (record_last_mem_set_info): Break out some code and put it into
        gcse-common.c.  Call into the new common code.
        (compute_local_properties): Pass additional arguments to compute_transp.
        * postreload-gcse.c: Include gcse-common.h and df.h
        (modify_mem_list_set, blocks_with_calls): New variables.
        (modify_mem_list, canon_modify_mem_list, transp): Likewise.
        (get_bb_avail_insn): Pass in the expression index too.
        (alloc_mem): Allocate memory for the new bitmaps and lists.
        (free_mem): Free memory for the new bitmaps and lists.
        (insert_expr_in_table): Record a bitmap index for each entry we
        add to the table.
        (record_last_mem_set_info): Call into common code in gcse-common.c.
        (get_bb_avail_insn): If no available insn was found in the requested
        BB.  If BB has a single predecessor, see if the expression is
        transparent in BB and available in that single predecessor.
        (compute_expr_transp): New wrapper for compute_transp.
        (eliminate_partially_redundant_load): Pass expression's bitmap_index
        to get_bb_avail_insn.  Compute next_pred_bb_end a bit later.
        (gcse_after_reload_main): If there are elements in the hash table,
        then compute transparency for all the elements in the hash table.
        * gcse-common.h: New file.
        * gcse-common.c: New file.

From-SVN: r221585
This commit is contained in:
Jeff Law 2015-03-22 23:21:04 -06:00 committed by Jeff Law
parent 4460b2dc61
commit af3eb11068
6 changed files with 424 additions and 179 deletions

View File

@ -1,3 +1,34 @@
2015-03-22 Jeff Law <law@redhat.com>
PR rtl-optimization/64317
* Makefile.in (OBJS): Add gcse-common.c
* gcse.c: Include gcse-common.h
(struct modify_pair_s): Move structure definition to gcse-common.h
(compute_transp): Move function to gcse-common.c.
(canon_list_insert): Similarly.
(record_last_mem_set_info): Break out some code and put it into
gcse-common.c. Call into the new common code.
(compute_local_properties): Pass additional arguments to compute_transp.
* postreload-gcse.c: Include gcse-common.h and df.h
(modify_mem_list_set, blocks_with_calls): New variables.
(modify_mem_list, canon_modify_mem_list, transp): Likewise.
(get_bb_avail_insn): Pass in the expression index too.
(alloc_mem): Allocate memory for the new bitmaps and lists.
(free_mem): Free memory for the new bitmaps and lists.
(insert_expr_in_table): Record a bitmap index for each entry we
add to the table.
(record_last_mem_set_info): Call into common code in gcse-common.c.
(get_bb_avail_insn): If no available insn was found in the requested
BB. If BB has a single predecessor, see if the expression is
transparent in BB and available in that single predecessor.
(compute_expr_transp): New wrapper for compute_transp.
(eliminate_partially_redundant_load): Pass expression's bitmap_index
to get_bb_avail_insn. Compute next_pred_bb_end a bit later.
(gcse_after_reload_main): If there are elements in the hash table,
then compute transparency for all the elements in the hash table.
* gcse-common.h: New file.
* gcse-common.c: New file.
2015-03-22 Sandra Loosemore <sandra@codesourcery.com>
* doc/cpp.texi (Search Path): Hyphenate "command-line" when used

View File

@ -1235,6 +1235,7 @@ OBJS = \
function.o \
fwprop.o \
gcse.o \
gcse-common.o \
ggc-common.o \
gimple.o \
gimple-builder.o \

227
gcc/gcse-common.c Normal file
View File

@ -0,0 +1,227 @@
/* Shared code for before and after reload gcse implementations.
Copyright (C) 1997-2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>.
It is expected that more hunks of gcse.c and postreload-gcse.c should
migrate into this file. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "vec.h"
#include "predict.h"
#include "bitmap.h"
#include "basic-block.h"
#include "df.h"
#include "gcse-common.h"
/* Record all of the canonicalized MEMs of record_last_mem_set_info's insn.
Note we store a pair of elements in the list, so they have to be
taken off pairwise. */
void
canon_list_insert (rtx dest, const_rtx x ATTRIBUTE_UNUSED, void *data)
{
rtx dest_addr, insn;
int bb;
modify_pair pair;
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
/* If DEST is not a MEM, then it will not conflict with a load. Note
that function calls are assumed to clobber memory, but are handled
elsewhere. */
if (! MEM_P (dest))
return;
dest_addr = get_addr (XEXP (dest, 0));
dest_addr = canon_rtx (dest_addr);
insn = ((struct gcse_note_stores_info *)data)->insn;
bb = BLOCK_FOR_INSN (insn)->index;
pair.dest = dest;
pair.dest_addr = dest_addr;
vec<modify_pair> *canon_mem_list
= ((struct gcse_note_stores_info *)data)->canon_mem_list;
canon_mem_list[bb].safe_push (pair);
}
/* Record memory modification information for INSN. We do not actually care
about the memory location(s) that are set, or even how they are set (consider
a CALL_INSN). We merely need to record which insns modify memory. */
void
record_last_mem_set_info_common (rtx_insn *insn,
vec<rtx_insn *> *modify_mem_list,
vec<modify_pair> *canon_modify_mem_list,
bitmap modify_mem_list_set,
bitmap blocks_with_calls)
{
int bb;
bb = BLOCK_FOR_INSN (insn)->index;
modify_mem_list[bb].safe_push (insn);
bitmap_set_bit (modify_mem_list_set, bb);
if (CALL_P (insn))
bitmap_set_bit (blocks_with_calls, bb);
else
{
struct gcse_note_stores_info data;
data.insn = insn;
data.canon_mem_list = canon_modify_mem_list;
note_stores (PATTERN (insn), canon_list_insert, (void*) &data);
}
}
/* For each block, compute whether X is transparent. X is either an
expression or an assignment [though we don't care which, for this context
an assignment is treated as an expression]. For each block where an
element of X is modified, reset the INDX bit in BMAP.
BLOCKS_WITH_CALLS indicates which blocks contain CALL_INSNs which kill
memory.
MODIFY_MEM_LIST_SET indicates which blocks have memory stores which might
kill a particular memory location.
CANON_MODIFY_MEM_LIST is the canonicalized list of memory locations modified
for each block. */
void
compute_transp (const_rtx x, int indx, sbitmap *bmap,
bitmap blocks_with_calls,
bitmap modify_mem_list_set,
vec<modify_pair> *canon_modify_mem_list)
{
int i, j;
enum rtx_code code;
const char *fmt;
/* repeat is used to turn tail-recursion into iteration since GCC
can't do it when there's no return value. */
repeat:
if (x == 0)
return;
code = GET_CODE (x);
switch (code)
{
case REG:
{
df_ref def;
for (def = DF_REG_DEF_CHAIN (REGNO (x));
def;
def = DF_REF_NEXT_REG (def))
bitmap_clear_bit (bmap[DF_REF_BB (def)->index], indx);
}
return;
case MEM:
if (! MEM_READONLY_P (x))
{
bitmap_iterator bi;
unsigned bb_index;
rtx x_addr;
x_addr = get_addr (XEXP (x, 0));
x_addr = canon_rtx (x_addr);
/* First handle all the blocks with calls. We don't need to
do any list walking for them. */
EXECUTE_IF_SET_IN_BITMAP (blocks_with_calls, 0, bb_index, bi)
{
bitmap_clear_bit (bmap[bb_index], indx);
}
/* Now iterate over the blocks which have memory modifications
but which do not have any calls. */
EXECUTE_IF_AND_COMPL_IN_BITMAP (modify_mem_list_set,
blocks_with_calls,
0, bb_index, bi)
{
vec<modify_pair> list
= canon_modify_mem_list[bb_index];
modify_pair *pair;
unsigned ix;
FOR_EACH_VEC_ELT_REVERSE (list, ix, pair)
{
rtx dest = pair->dest;
rtx dest_addr = pair->dest_addr;
if (canon_true_dependence (dest, GET_MODE (dest),
dest_addr, x, x_addr))
{
bitmap_clear_bit (bmap[bb_index], indx);
break;
}
}
}
}
x = XEXP (x, 0);
goto repeat;
case PC:
case CC0: /*FIXME*/
case CONST:
CASE_CONST_ANY:
case SYMBOL_REF:
case LABEL_REF:
case ADDR_VEC:
case ADDR_DIFF_VEC:
return;
default:
break;
}
for (i = GET_RTX_LENGTH (code) - 1, fmt = GET_RTX_FORMAT (code); i >= 0; i--)
{
if (fmt[i] == 'e')
{
/* If we are about to do the last recursive call
needed at this level, change it into iteration.
This function is called enough to be worth it. */
if (i == 0)
{
x = XEXP (x, i);
goto repeat;
}
compute_transp (XEXP (x, i), indx, bmap, blocks_with_calls,
modify_mem_list_set, canon_modify_mem_list);
}
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
compute_transp (XVECEXP (x, i, j), indx, bmap, blocks_with_calls,
modify_mem_list_set, canon_modify_mem_list);
}
}

47
gcc/gcse-common.h Normal file
View File

@ -0,0 +1,47 @@
/* Structures and prototypes common across the normal GCSE
implementation and the post-reload implementation.
Copyright (C) 1997-2015 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_GCSE_COMMON_H
#define GCC_GCSE_COMMON_H
typedef vec<rtx_insn *> vec_rtx_heap;
typedef struct modify_pair_s
{
rtx dest; /* A MEM. */
rtx dest_addr; /* The canonical address of `dest'. */
} modify_pair;
typedef vec<modify_pair> vec_modify_pair_heap;
struct gcse_note_stores_info
{
rtx_insn *insn;
vec<modify_pair> *canon_mem_list;
};
extern void compute_transp (const_rtx, int, sbitmap *, bitmap,
bitmap, vec<modify_pair> *);
extern void record_last_mem_set_info_common (rtx_insn *,
vec<rtx_insn *> *,
vec<modify_pair> *,
bitmap, bitmap);
#endif

View File

@ -189,6 +189,7 @@ along with GCC; see the file COPYING3. If not see
#include "dbgcnt.h"
#include "target.h"
#include "gcse.h"
#include "gcse-common.h"
/* We support GCSE via Partial Redundancy Elimination. PRE optimizations
are a superset of those done by classic GCSE.
@ -424,13 +425,6 @@ static regset reg_set_bitmap;
static vec<rtx_insn *> *modify_mem_list;
static bitmap modify_mem_list_set;
typedef struct modify_pair_s
{
rtx dest; /* A MEM. */
rtx dest_addr; /* The canonical address of `dest'. */
} modify_pair;
/* This array parallels modify_mem_list, except that it stores MEMs
being set and their canonicalized memory addresses. */
static vec<modify_pair> *canon_modify_mem_list;
@ -507,12 +501,10 @@ static void alloc_hash_table (struct gcse_hash_table_d *);
static void free_hash_table (struct gcse_hash_table_d *);
static void compute_hash_table_work (struct gcse_hash_table_d *);
static void dump_hash_table (FILE *, const char *, struct gcse_hash_table_d *);
static void compute_transp (const_rtx, int, sbitmap *);
static void compute_local_properties (sbitmap *, sbitmap *, sbitmap *,
struct gcse_hash_table_d *);
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);
static void canon_list_insert (rtx, const_rtx, void *);
static void alloc_pre_mem (int, int);
static void free_pre_mem (void);
static struct edge_list *compute_pre_data (void);
@ -733,7 +725,10 @@ compute_local_properties (sbitmap *transp, sbitmap *comp, sbitmap *antloc,
We start by assuming all are transparent [none are killed], and
then reset the bits for those that are. */
if (transp)
compute_transp (expr->expr, indx, transp);
compute_transp (expr->expr, indx, transp,
blocks_with_calls,
modify_mem_list_set,
canon_modify_mem_list);
/* The occurrences recorded in antic_occr are exactly those that
we want to set to nonzero in ANTLOC. */
@ -1489,40 +1484,6 @@ record_last_reg_set_info (rtx insn, int regno)
}
}
/* Record all of the canonicalized MEMs of record_last_mem_set_info's insn.
Note we store a pair of elements in the list, so they have to be
taken off pairwise. */
static void
canon_list_insert (rtx dest ATTRIBUTE_UNUSED, const_rtx x ATTRIBUTE_UNUSED,
void * v_insn)
{
rtx dest_addr, insn;
int bb;
modify_pair pair;
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
/* If DEST is not a MEM, then it will not conflict with a load. Note
that function calls are assumed to clobber memory, but are handled
elsewhere. */
if (! MEM_P (dest))
return;
dest_addr = get_addr (XEXP (dest, 0));
dest_addr = canon_rtx (dest_addr);
insn = (rtx) v_insn;
bb = BLOCK_FOR_INSN (insn)->index;
pair.dest = dest;
pair.dest_addr = dest_addr;
canon_modify_mem_list[bb].safe_push (pair);
}
/* Record memory modification information for INSN. We do not actually care
about the memory location(s) that are set, or even how they are set (consider
a CALL_INSN). We merely need to record which insns modify memory. */
@ -1530,21 +1491,13 @@ canon_list_insert (rtx dest ATTRIBUTE_UNUSED, const_rtx x ATTRIBUTE_UNUSED,
static void
record_last_mem_set_info (rtx_insn *insn)
{
int bb;
if (! flag_gcse_lm)
return;
/* load_killed_in_block_p will handle the case of calls clobbering
everything. */
bb = BLOCK_FOR_INSN (insn)->index;
modify_mem_list[bb].safe_push (insn);
bitmap_set_bit (modify_mem_list_set, bb);
if (CALL_P (insn))
bitmap_set_bit (blocks_with_calls, bb);
else
note_stores (PATTERN (insn), canon_list_insert, (void*) insn);
record_last_mem_set_info_common (insn, modify_mem_list,
canon_modify_mem_list,
modify_mem_list_set,
blocks_with_calls);
}
/* Called from compute_hash_table via note_stores to handle one
@ -1699,120 +1652,6 @@ free_modify_mem_tables (void)
canon_modify_mem_list = 0;
}
/* For each block, compute whether X is transparent. X is either an
expression or an assignment [though we don't care which, for this context
an assignment is treated as an expression]. For each block where an
element of X is modified, reset the INDX bit in BMAP. */
static void
compute_transp (const_rtx x, int indx, sbitmap *bmap)
{
int i, j;
enum rtx_code code;
const char *fmt;
/* repeat is used to turn tail-recursion into iteration since GCC
can't do it when there's no return value. */
repeat:
if (x == 0)
return;
code = GET_CODE (x);
switch (code)
{
case REG:
{
df_ref def;
for (def = DF_REG_DEF_CHAIN (REGNO (x));
def;
def = DF_REF_NEXT_REG (def))
bitmap_clear_bit (bmap[DF_REF_BB (def)->index], indx);
}
return;
case MEM:
if (! MEM_READONLY_P (x))
{
bitmap_iterator bi;
unsigned bb_index;
rtx x_addr;
x_addr = get_addr (XEXP (x, 0));
x_addr = canon_rtx (x_addr);
/* First handle all the blocks with calls. We don't need to
do any list walking for them. */
EXECUTE_IF_SET_IN_BITMAP (blocks_with_calls, 0, bb_index, bi)
{
bitmap_clear_bit (bmap[bb_index], indx);
}
/* Now iterate over the blocks which have memory modifications
but which do not have any calls. */
EXECUTE_IF_AND_COMPL_IN_BITMAP (modify_mem_list_set,
blocks_with_calls,
0, bb_index, bi)
{
vec<modify_pair> list
= canon_modify_mem_list[bb_index];
modify_pair *pair;
unsigned ix;
FOR_EACH_VEC_ELT_REVERSE (list, ix, pair)
{
rtx dest = pair->dest;
rtx dest_addr = pair->dest_addr;
if (canon_true_dependence (dest, GET_MODE (dest),
dest_addr, x, x_addr))
{
bitmap_clear_bit (bmap[bb_index], indx);
break;
}
}
}
}
x = XEXP (x, 0);
goto repeat;
case PC:
case CC0: /*FIXME*/
case CONST:
CASE_CONST_ANY:
case SYMBOL_REF:
case LABEL_REF:
case ADDR_VEC:
case ADDR_DIFF_VEC:
return;
default:
break;
}
for (i = GET_RTX_LENGTH (code) - 1, fmt = GET_RTX_FORMAT (code); i >= 0; i--)
{
if (fmt[i] == 'e')
{
/* If we are about to do the last recursive call
needed at this level, change it into iteration.
This function is called enough to be worth it. */
if (i == 0)
{
x = XEXP (x, i);
goto repeat;
}
compute_transp (XEXP (x, i), indx, bmap);
}
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
compute_transp (XVECEXP (x, i, j), indx, bmap);
}
}
/* Compute PRE+LCM working variables. */
/* Local properties of expressions. */

View File

@ -67,6 +67,8 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "tree-pass.h"
#include "dbgcnt.h"
#include "df.h"
#include "gcse-common.h"
/* The following code implements gcse after reload, the purpose of this
pass is to cleanup redundant loads generated by reload and other
@ -121,6 +123,9 @@ struct expr
/* The same hash for this entry. */
hashval_t hash;
/* Index in the transparent bitmaps. */
unsigned int bitmap_index;
/* List of available occurrence in basic blocks in the function. */
struct occr *avail_occr;
};
@ -235,6 +240,24 @@ static struct modifies_mem *modifies_mem_obstack_bottom;
block, have no gaps, and only apply to real insns. */
static int *uid_cuid;
#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)])
/* Bitmap of blocks which have memory stores. */
static bitmap modify_mem_list_set;
/* Bitmap of blocks which have calls. */
static bitmap blocks_with_calls;
/* Vector indexed by block # with a list of all the insns that
modify memory within the block. */
static vec<rtx_insn *> *modify_mem_list;
/* Vector indexed by block # with a canonicalized list of insns
that modify memory in the block. */
static vec<modify_pair> *canon_modify_mem_list;
/* Vector of simple bitmaps indexed by block number. Each component sbitmap
indicates which expressions are transparent through the block. */
static sbitmap *transp;
/* Helpers for memory allocation/freeing. */
@ -266,7 +289,7 @@ static bool reg_used_on_edge (rtx, edge);
static rtx get_avail_load_store_reg (rtx_insn *);
static bool bb_has_well_behaved_predecessors (basic_block);
static struct occr* get_bb_avail_insn (basic_block, struct occr *);
static struct occr* get_bb_avail_insn (basic_block, struct occr *, int);
static void hash_scan_set (rtx_insn *);
static void compute_hash_table (void);
@ -321,6 +344,15 @@ alloc_mem (void)
modifies_mem_obstack_bottom =
(struct modifies_mem *) obstack_alloc (&modifies_mem_obstack,
sizeof (struct modifies_mem));
blocks_with_calls = BITMAP_ALLOC (NULL);
modify_mem_list_set = BITMAP_ALLOC (NULL);
modify_mem_list = (vec_rtx_heap *) xcalloc (last_basic_block_for_fn (cfun),
sizeof (vec_rtx_heap));
canon_modify_mem_list
= (vec_modify_pair_heap *) xcalloc (last_basic_block_for_fn (cfun),
sizeof (vec_modify_pair_heap));
}
/* Free memory allocated by alloc_mem. */
@ -338,6 +370,16 @@ free_mem (void)
obstack_free (&unoccr_obstack, NULL);
obstack_free (&modifies_mem_obstack, NULL);
unsigned i;
bitmap_iterator bi;
EXECUTE_IF_SET_IN_BITMAP (modify_mem_list_set, 0, i, bi)
{
modify_mem_list[i].release ();
canon_modify_mem_list[i].release ();
}
BITMAP_FREE (blocks_with_calls);
BITMAP_FREE (modify_mem_list_set);
free (reg_avail_info);
}
@ -376,8 +418,15 @@ insert_expr_in_table (rtx x, rtx_insn *insn)
slot = expr_table->find_slot_with_hash (cur_expr, hash, INSERT);
if (! (*slot))
/* The expression isn't found, so insert it. */
*slot = cur_expr;
{
/* The expression isn't found, so insert it. */
*slot = cur_expr;
/* Anytime we add an entry to the table, record the index
of the new entry. The bitmap index starts counting
at zero. */
cur_expr->bitmap_index = expr_table->elements () - 1;
}
else
{
/* The expression is already in the table, so roll back the
@ -698,6 +747,11 @@ record_last_mem_set_info (rtx_insn *insn)
list_entry->insn = insn;
list_entry->next = modifies_mem_list;
modifies_mem_list = list_entry;
record_last_mem_set_info_common (insn, modify_mem_list,
canon_modify_mem_list,
modify_mem_list_set,
blocks_with_calls);
}
/* Called from compute_hash_table via note_stores to handle one
@ -955,15 +1009,45 @@ bb_has_well_behaved_predecessors (basic_block bb)
/* Search for the occurrences of expression in BB. */
static struct occr*
get_bb_avail_insn (basic_block bb, struct occr *occr)
get_bb_avail_insn (basic_block bb, struct occr *orig_occr, int bitmap_index)
{
struct occr *occr = orig_occr;
for (; occr != NULL; occr = occr->next)
if (BLOCK_FOR_INSN (occr->insn) == bb)
return occr;
/* If we could not find an occurrence in BB, see if BB
has a single predecessor with an occurrence that is
transparent through BB. */
if (single_pred_p (bb)
&& bitmap_bit_p (transp[bb->index], bitmap_index)
&& (occr = get_bb_avail_insn (single_pred (bb), orig_occr, bitmap_index)))
{
rtx avail_reg = get_avail_load_store_reg (occr->insn);
if (!reg_set_between_p (avail_reg,
PREV_INSN (BB_HEAD (bb)),
NEXT_INSN (BB_END (bb)))
&& !reg_killed_on_edge (avail_reg, single_pred_edge (bb)))
return occr;
}
return NULL;
}
/* This helper is called via htab_traverse. */
int
compute_expr_transp (expr **slot, FILE *dump_file ATTRIBUTE_UNUSED)
{
struct expr *expr = *slot;
compute_transp (expr->expr, expr->bitmap_index, transp,
blocks_with_calls, modify_mem_list_set,
canon_modify_mem_list);
return 1;
}
/* This handles the case where several stores feed a partially redundant
load. It checks if the redundancy elimination is possible and if it's
worth it.
@ -1016,9 +1100,13 @@ eliminate_partially_redundant_load (basic_block bb, rtx_insn *insn,
avail_insn = NULL;
avail_reg = NULL_RTX;
pred_bb = pred->src;
next_pred_bb_end = NEXT_INSN (BB_END (pred_bb));
for (a_occr = get_bb_avail_insn (pred_bb, expr->avail_occr); a_occr;
a_occr = get_bb_avail_insn (pred_bb, a_occr->next))
for (a_occr = get_bb_avail_insn (pred_bb,
expr->avail_occr,
expr->bitmap_index);
a_occr;
a_occr = get_bb_avail_insn (pred_bb,
a_occr->next,
expr->bitmap_index))
{
/* Check if the loaded register is not used. */
avail_insn = a_occr->insn;
@ -1038,6 +1126,7 @@ eliminate_partially_redundant_load (basic_block bb, rtx_insn *insn,
avail_insn = NULL;
continue;
}
next_pred_bb_end = NEXT_INSN (BB_END (BLOCK_FOR_INSN (avail_insn)));
if (!reg_set_between_p (avail_reg, avail_insn, next_pred_bb_end))
/* AVAIL_INSN remains non-null. */
break;
@ -1150,9 +1239,9 @@ eliminate_partially_redundant_load (basic_block bb, rtx_insn *insn,
/* Delete the insn if it is not available in this block and mark it
for deletion if it is available. If insn is available it may help
discover additional redundancies, so mark it for later deletion. */
for (a_occr = get_bb_avail_insn (bb, expr->avail_occr);
for (a_occr = get_bb_avail_insn (bb, expr->avail_occr, expr->bitmap_index);
a_occr && (a_occr->insn != insn);
a_occr = get_bb_avail_insn (bb, a_occr->next))
a_occr = get_bb_avail_insn (bb, a_occr->next, expr->bitmap_index))
;
if (!a_occr)
@ -1308,8 +1397,19 @@ gcse_after_reload_main (rtx f ATTRIBUTE_UNUSED)
if (expr_table->elements () > 0)
{
/* Knowing which MEMs are transparent through a block can signifiantly
increase the number of redundant loads found. So compute transparency
information for each memory expression in the hash table. */
df_analyze ();
/* This can not be part of the normal allocation routine because
we have to know the number of elements in the hash table. */
transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
expr_table->elements ());
bitmap_vector_ones (transp, last_basic_block_for_fn (cfun));
expr_table->traverse <FILE *, compute_expr_transp> (dump_file);
eliminate_partially_redundant_loads ();
delete_redundant_insns ();
sbitmap_vector_free (transp);
if (dump_file)
{