3) Perform copy/constant propagation.
- 4) Perform global cse.
+ 4) Perform global cse using lazy code motion if not optimizing
+ for size, or code hoisting if we are.
5) Perform another pass of copy/constant propagation.
static regset reg_set_bitmap;
/* For each block, a bitmap of registers set in the block.
- This is used by expr_killed_p and compute_transp.
+ This is used by compute_transp.
It is computed during hash table computation and not by compute_sets
as it includes registers added since the last pass (or between cprop and
gcse) and it's currently not easy to realloc sbitmap vectors. */
/* Number of copys propagated. */
static int copy_prop_count;
\f
-/* These variables are used by classic GCSE.
- Normally they'd be defined a bit later, but `rd_gen' needs to
- be declared sooner. */
-
-/* Each block has a bitmap of each type.
- The length of each blocks bitmap is:
-
- max_cuid - for reaching definitions
- n_exprs - for available expressions
-
- Thus we view the bitmaps as 2 dimensional arrays. i.e.
- rd_kill[block_num][cuid_num]
- ae_kill[block_num][expr_num] */
-
-/* For reaching defs */
-static sbitmap *rd_kill, *rd_gen, *reaching_defs, *rd_out;
-
-/* for available exprs */
-static sbitmap *ae_kill, *ae_gen, *ae_in, *ae_out;
+/* For available exprs */
+static sbitmap *ae_kill, *ae_gen;
/* Objects of this type are passed around by the null-pointer check
removal routines. */
static void free_gcse_mem (void);
static void alloc_reg_set_mem (int);
static void free_reg_set_mem (void);
-static int get_bitmap_width (int, int, int);
static void record_one_set (int, rtx);
static void replace_one_set (int, rtx, rtx);
static void record_set_info (rtx, rtx, void *);
static int hoist_expr_reaches_here_p (basic_block, int, basic_block, char *);
static void hoist_code (void);
static int one_code_hoisting_pass (void);
-static void alloc_rd_mem (int, int);
-static void free_rd_mem (void);
-static void handle_rd_kill_set (rtx, int, basic_block);
-static void compute_kill_rd (void);
-static void compute_rd (void);
-static void alloc_avail_expr_mem (int, int);
-static void free_avail_expr_mem (void);
-static void compute_ae_gen (struct hash_table *);
-static int expr_killed_p (rtx, basic_block);
-static void compute_ae_kill (sbitmap *, sbitmap *, struct hash_table *);
-static int expr_reaches_here_p (struct occr *, struct expr *, basic_block,
- int);
-static rtx computing_insn (struct expr *, rtx);
-static int def_reaches_here_p (rtx, rtx);
-static int can_disregard_other_sets (struct reg_set **, rtx, int);
-static int handle_avail_expr (rtx, struct expr *);
-static int classic_gcse (void);
-static int one_classic_gcse_pass (int);
-static void invalidate_nonnull_info (rtx, rtx, void *);
-static int delete_null_pointer_checks_1 (unsigned int *, sbitmap *, sbitmap *,
- struct null_pointer_info *);
static rtx process_insert_insn (struct expr *);
static int pre_edge_insert (struct edge_list *, struct expr **);
-static int expr_reaches_here_p_work (struct occr *, struct expr *,
- basic_block, int, char *);
static int pre_expr_reaches_here_p_work (basic_block, struct expr *,
basic_block, char *);
static struct ls_expr * ldst_entry (rtx);
changed = one_cprop_pass (pass + 1, 0, 0);
if (optimize_size)
- changed |= one_classic_gcse_pass (pass + 1);
+ /* Do nothing. */ ;
else
{
changed |= one_pre_gcse_pass (pass + 1);
/* It does not make sense to run code hoisting unless we are optimizing
for code size -- it rarely makes programs faster, and can make
them bigger if we did partial redundancy elimination (when optimizing
- for space, we use a classic gcse algorithm instead of partial
- redundancy algorithms). */
+ for space, we don't run the partial redundancy algorithms). */
if (optimize_size)
{
max_gcse_regno = max_reg_num ();
BITMAP_XFREE (modify_mem_list_set);
BITMAP_XFREE (canon_modify_mem_list_set);
}
-
-/* Many of the global optimization algorithms work by solving dataflow
- equations for various expressions. Initially, some local value is
- computed for each expression in each block. Then, the values across the
- various blocks are combined (by following flow graph edges) to arrive at
- global values. Conceptually, each set of equations is independent. We
- may therefore solve all the equations in parallel, solve them one at a
- time, or pick any intermediate approach.
-
- When you're going to need N two-dimensional bitmaps, each X (say, the
- number of blocks) by Y (say, the number of expressions), call this
- function. It's not important what X and Y represent; only that Y
- correspond to the things that can be done in parallel. This function will
- return an appropriate chunking factor C; you should solve C sets of
- equations in parallel. By going through this function, we can easily
- trade space against time; by solving fewer equations in parallel we use
- less space. */
-
-static int
-get_bitmap_width (int n, int x, int y)
-{
- /* It's not really worth figuring out *exactly* how much memory will
- be used by a particular choice. The important thing is to get
- something approximately right. */
- size_t max_bitmap_memory = 10 * 1024 * 1024;
-
- /* The number of bytes we'd use for a single column of minimum
- width. */
- size_t column_size = n * x * sizeof (SBITMAP_ELT_TYPE);
-
- /* Often, it's reasonable just to solve all the equations in
- parallel. */
- if (column_size * SBITMAP_SET_SIZE (y) <= max_bitmap_memory)
- return y;
-
- /* Otherwise, pick the largest width we can, without going over the
- limit. */
- return SBITMAP_ELT_BITS * ((max_bitmap_memory + column_size - 1)
- / column_size);
-}
\f
/* Compute the local properties of each recorded expression.
}
\f
-/* Classic GCSE reaching definition support. */
-
-/* Allocate reaching def variables. */
-
-static void
-alloc_rd_mem (int n_blocks, int n_insns)
-{
- rd_kill = sbitmap_vector_alloc (n_blocks, n_insns);
- sbitmap_vector_zero (rd_kill, n_blocks);
-
- rd_gen = sbitmap_vector_alloc (n_blocks, n_insns);
- sbitmap_vector_zero (rd_gen, n_blocks);
+/* Compute copy/constant propagation working variables. */
- reaching_defs = sbitmap_vector_alloc (n_blocks, n_insns);
- sbitmap_vector_zero (reaching_defs, n_blocks);
+/* Local properties of assignments. */
+static sbitmap *cprop_pavloc;
+static sbitmap *cprop_absaltered;
- rd_out = sbitmap_vector_alloc (n_blocks, n_insns);
- sbitmap_vector_zero (rd_out, n_blocks);
-}
+/* Global properties of assignments (computed from the local properties). */
+static sbitmap *cprop_avin;
+static sbitmap *cprop_avout;
-/* Free reaching def variables. */
+/* Allocate vars used for copy/const propagation. N_BLOCKS is the number of
+ basic blocks. N_SETS is the number of sets. */
static void
-free_rd_mem (void)
+alloc_cprop_mem (int n_blocks, int n_sets)
{
- sbitmap_vector_free (rd_kill);
- sbitmap_vector_free (rd_gen);
- sbitmap_vector_free (reaching_defs);
- sbitmap_vector_free (rd_out);
+ cprop_pavloc = sbitmap_vector_alloc (n_blocks, n_sets);
+ cprop_absaltered = sbitmap_vector_alloc (n_blocks, n_sets);
+
+ cprop_avin = sbitmap_vector_alloc (n_blocks, n_sets);
+ cprop_avout = sbitmap_vector_alloc (n_blocks, n_sets);
}
-/* Add INSN to the kills of BB. REGNO, set in BB, is killed by INSN. */
+/* Free vars used by copy/const propagation. */
static void
-handle_rd_kill_set (rtx insn, int regno, basic_block bb)
+free_cprop_mem (void)
{
- struct reg_set *this_reg;
-
- for (this_reg = reg_set_table[regno]; this_reg; this_reg = this_reg ->next)
- if (BLOCK_NUM (this_reg->insn) != BLOCK_NUM (insn))
- SET_BIT (rd_kill[bb->index], INSN_CUID (this_reg->insn));
+ sbitmap_vector_free (cprop_pavloc);
+ sbitmap_vector_free (cprop_absaltered);
+ sbitmap_vector_free (cprop_avin);
+ sbitmap_vector_free (cprop_avout);
}
-/* Compute the set of kill's for reaching definitions. */
+/* 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, set (SET_P == 1) or reset (SET_P == 0) the INDX
+ bit in BMAP. */
static void
-compute_kill_rd (void)
+compute_transp (rtx x, int indx, sbitmap *bmap, int set_p)
{
- int cuid;
- unsigned int regno;
- int i;
+ int i, j;
basic_block bb;
+ enum rtx_code code;
+ reg_set *r;
+ const char *fmt;
- /* For each block
- For each set bit in `gen' of the block (i.e each insn which
- generates a definition in the block)
- Call the reg set by the insn corresponding to that bit regx
- Look at the linked list starting at reg_set_table[regx]
- For each setting of regx in the linked list, which is not in
- this block
- Set the bit in `kill' corresponding to that insn. */
- FOR_EACH_BB (bb)
- for (cuid = 0; cuid < max_cuid; cuid++)
- if (TEST_BIT (rd_gen[bb->index], cuid))
- {
- rtx insn = CUID_INSN (cuid);
- rtx pat = PATTERN (insn);
+ /* repeat is used to turn tail-recursion into iteration since GCC
+ can't do it when there's no return value. */
+ repeat:
- if (GET_CODE (insn) == CALL_INSN)
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case REG:
+ if (set_p)
+ {
+ if (REGNO (x) < FIRST_PSEUDO_REGISTER)
{
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
- handle_rd_kill_set (insn, regno, bb);
+ FOR_EACH_BB (bb)
+ if (TEST_BIT (reg_set_in_block[bb->index], REGNO (x)))
+ SET_BIT (bmap[bb->index], indx);
}
-
- if (GET_CODE (pat) == PARALLEL)
+ else
{
- for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
- {
- enum rtx_code code = GET_CODE (XVECEXP (pat, 0, i));
-
- if ((code == SET || code == CLOBBER)
- && GET_CODE (XEXP (XVECEXP (pat, 0, i), 0)) == REG)
- handle_rd_kill_set (insn,
- REGNO (XEXP (XVECEXP (pat, 0, i), 0)),
- bb);
- }
+ for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
+ SET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
}
- else if (GET_CODE (pat) == SET && GET_CODE (SET_DEST (pat)) == REG)
- /* Each setting of this register outside of this block
- must be marked in the set of kills in this block. */
- handle_rd_kill_set (insn, REGNO (SET_DEST (pat)), bb);
}
-}
-
-/* Compute the reaching definitions as in
- Compilers Principles, Techniques, and Tools. Aho, Sethi, Ullman,
- Chapter 10. It is the same algorithm as used for computing available
- expressions but applied to the gens and kills of reaching definitions. */
-
-static void
-compute_rd (void)
-{
- int changed, passes;
- basic_block bb;
-
- FOR_EACH_BB (bb)
- sbitmap_copy (rd_out[bb->index] /*dst*/, rd_gen[bb->index] /*src*/);
-
- passes = 0;
- changed = 1;
- while (changed)
- {
- changed = 0;
- FOR_EACH_BB (bb)
+ else
{
- sbitmap_union_of_preds (reaching_defs[bb->index], rd_out, bb->index);
- changed |= sbitmap_union_of_diff_cg (rd_out[bb->index], rd_gen[bb->index],
- reaching_defs[bb->index], rd_kill[bb->index]);
+ if (REGNO (x) < FIRST_PSEUDO_REGISTER)
+ {
+ FOR_EACH_BB (bb)
+ if (TEST_BIT (reg_set_in_block[bb->index], REGNO (x)))
+ RESET_BIT (bmap[bb->index], indx);
+ }
+ else
+ {
+ for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
+ RESET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
+ }
}
- passes++;
- }
-
- if (gcse_file)
- fprintf (gcse_file, "reaching def computation: %d passes\n", passes);
-}
-\f
-/* Classic GCSE available expression support. */
-
-/* Allocate memory for available expression computation. */
-
-static void
-alloc_avail_expr_mem (int n_blocks, int n_exprs)
-{
- ae_kill = sbitmap_vector_alloc (n_blocks, n_exprs);
- sbitmap_vector_zero (ae_kill, n_blocks);
-
- ae_gen = sbitmap_vector_alloc (n_blocks, n_exprs);
- sbitmap_vector_zero (ae_gen, n_blocks);
-
- ae_in = sbitmap_vector_alloc (n_blocks, n_exprs);
- sbitmap_vector_zero (ae_in, n_blocks);
-
- ae_out = sbitmap_vector_alloc (n_blocks, n_exprs);
- sbitmap_vector_zero (ae_out, n_blocks);
-}
-
-static void
-free_avail_expr_mem (void)
-{
- sbitmap_vector_free (ae_kill);
- sbitmap_vector_free (ae_gen);
- sbitmap_vector_free (ae_in);
- sbitmap_vector_free (ae_out);
-}
-
-/* Compute the set of available expressions generated in each basic block. */
-static void
-compute_ae_gen (struct hash_table *expr_hash_table)
-{
- unsigned int i;
- struct expr *expr;
- struct occr *occr;
+ return;
- /* For each recorded occurrence of each expression, set ae_gen[bb][expr].
- This is all we have to do because an expression is not recorded if it
- is not available, and the only expressions we want to work with are the
- ones that are recorded. */
- for (i = 0; i < expr_hash_table->size; i++)
- for (expr = expr_hash_table->table[i]; expr != 0; expr = expr->next_same_hash)
- for (occr = expr->avail_occr; occr != 0; occr = occr->next)
- SET_BIT (ae_gen[BLOCK_NUM (occr->insn)], expr->bitmap_index);
-}
+ case MEM:
+ FOR_EACH_BB (bb)
+ {
+ rtx list_entry = canon_modify_mem_list[bb->index];
-/* Return nonzero if expression X is killed in BB. */
+ while (list_entry)
+ {
+ rtx dest, dest_addr;
-static int
-expr_killed_p (rtx x, basic_block bb)
-{
- int i, j;
- enum rtx_code code;
- const char *fmt;
+ if (GET_CODE (XEXP (list_entry, 0)) == CALL_INSN)
+ {
+ if (set_p)
+ SET_BIT (bmap[bb->index], indx);
+ else
+ RESET_BIT (bmap[bb->index], indx);
+ break;
+ }
+ /* LIST_ENTRY must be an INSN of some kind that sets memory.
+ Examine each hunk of memory that is modified. */
- if (x == 0)
- return 1;
+ dest = XEXP (list_entry, 0);
+ list_entry = XEXP (list_entry, 1);
+ dest_addr = XEXP (list_entry, 0);
- code = GET_CODE (x);
- switch (code)
- {
- case REG:
- return TEST_BIT (reg_set_in_block[bb->index], REGNO (x));
+ if (canon_true_dependence (dest, GET_MODE (dest), dest_addr,
+ x, rtx_addr_varies_p))
+ {
+ if (set_p)
+ SET_BIT (bmap[bb->index], indx);
+ else
+ RESET_BIT (bmap[bb->index], indx);
+ break;
+ }
+ list_entry = XEXP (list_entry, 1);
+ }
+ }
- case MEM:
- if (load_killed_in_block_p (bb, get_max_uid () + 1, x, 0))
- return 1;
- else
- return expr_killed_p (XEXP (x, 0), bb);
+ x = XEXP (x, 0);
+ goto repeat;
case PC:
case CC0: /*FIXME*/
case LABEL_REF:
case ADDR_VEC:
case ADDR_DIFF_VEC:
- return 0;
+ return;
default:
break;
needed at this level, change it into iteration.
This function is called enough to be worth it. */
if (i == 0)
- return expr_killed_p (XEXP (x, i), bb);
- else if (expr_killed_p (XEXP (x, i), bb))
- return 1;
+ {
+ x = XEXP (x, i);
+ goto repeat;
+ }
+
+ compute_transp (XEXP (x, i), indx, bmap, set_p);
}
else if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
- if (expr_killed_p (XVECEXP (x, i, j), bb))
- return 1;
+ compute_transp (XVECEXP (x, i, j), indx, bmap, set_p);
}
-
- return 0;
}
-/* Compute the set of available expressions killed in each basic block. */
+/* Top level routine to do the dataflow analysis needed by copy/const
+ propagation. */
static void
-compute_ae_kill (sbitmap *ae_gen, sbitmap *ae_kill,
- struct hash_table *expr_hash_table)
+compute_cprop_data (void)
{
- basic_block bb;
- unsigned int i;
- struct expr *expr;
-
- FOR_EACH_BB (bb)
- for (i = 0; i < expr_hash_table->size; i++)
- for (expr = expr_hash_table->table[i]; expr; expr = expr->next_same_hash)
- {
- /* Skip EXPR if generated in this block. */
- if (TEST_BIT (ae_gen[bb->index], expr->bitmap_index))
- continue;
-
- if (expr_killed_p (expr->expr, bb))
- SET_BIT (ae_kill[bb->index], expr->bitmap_index);
- }
+ compute_local_properties (cprop_absaltered, cprop_pavloc, NULL, &set_hash_table);
+ compute_available (cprop_pavloc, cprop_absaltered,
+ cprop_avout, cprop_avin);
}
\f
-/* Actually perform the Classic GCSE optimizations. */
+/* Copy/constant propagation. */
-/* Return nonzero if occurrence OCCR of expression EXPR reaches block BB.
+/* Maximum number of register uses in an insn that we handle. */
+#define MAX_USES 8
- CHECK_SELF_LOOP is nonzero if we should consider a block reaching itself
- as a positive reach. We want to do this when there are two computations
- of the expression in the block.
+/* Table of uses found in an insn.
+ Allocated statically to avoid alloc/free complexity and overhead. */
+static struct reg_use reg_use_table[MAX_USES];
- VISITED is a pointer to a working buffer for tracking which BB's have
- been visited. It is NULL for the top-level call.
+/* Index into `reg_use_table' while building it. */
+static int reg_use_count;
- We treat reaching expressions that go through blocks containing the same
- reaching expression as "not reaching". E.g. if EXPR is generated in blocks
- 2 and 3, INSN is in block 4, and 2->3->4, we treat the expression in block
- 2 as not reaching. The intent is to improve the probability of finding
- only one reaching expression and to reduce register lifetimes by picking
- the closest such expression. */
+/* Set up a list of register numbers used in INSN. The found uses are stored
+ in `reg_use_table'. `reg_use_count' is initialized to zero before entry,
+ and contains the number of uses in the table upon exit.
-static int
-expr_reaches_here_p_work (struct occr *occr, struct expr *expr,
- basic_block bb, int check_self_loop, char *visited)
+ ??? If a register appears multiple times we will record it multiple times.
+ This doesn't hurt anything but it will slow things down. */
+
+static void
+find_used_regs (rtx *xptr, void *data ATTRIBUTE_UNUSED)
{
- edge pred;
+ int i, j;
+ enum rtx_code code;
+ const char *fmt;
+ rtx x = *xptr;
- for (pred = bb->pred; pred != NULL; pred = pred->pred_next)
+ /* 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);
+ if (REG_P (x))
{
- basic_block pred_bb = pred->src;
-
- if (visited[pred_bb->index])
- /* This predecessor has already been visited. Nothing to do. */
- ;
- else if (pred_bb == bb)
- {
- /* BB loops on itself. */
- if (check_self_loop
- && TEST_BIT (ae_gen[pred_bb->index], expr->bitmap_index)
- && BLOCK_NUM (occr->insn) == pred_bb->index)
- return 1;
-
- visited[pred_bb->index] = 1;
- }
-
- /* Ignore this predecessor if it kills the expression. */
- else if (TEST_BIT (ae_kill[pred_bb->index], expr->bitmap_index))
- visited[pred_bb->index] = 1;
-
- /* Does this predecessor generate this expression? */
- else if (TEST_BIT (ae_gen[pred_bb->index], expr->bitmap_index))
- {
- /* Is this the occurrence we're looking for?
- Note that there's only one generating occurrence per block
- so we just need to check the block number. */
- if (BLOCK_NUM (occr->insn) == pred_bb->index)
- return 1;
-
- visited[pred_bb->index] = 1;
- }
-
- /* Neither gen nor kill. */
- else
- {
- visited[pred_bb->index] = 1;
- if (expr_reaches_here_p_work (occr, expr, pred_bb, check_self_loop,
- visited))
-
- return 1;
- }
- }
-
- /* All paths have been checked. */
- return 0;
-}
-
-/* This wrapper for expr_reaches_here_p_work() is to ensure that any
- memory allocated for that function is returned. */
-
-static int
-expr_reaches_here_p (struct occr *occr, struct expr *expr, basic_block bb,
- int check_self_loop)
-{
- int rval;
- char *visited = xcalloc (last_basic_block, 1);
-
- rval = expr_reaches_here_p_work (occr, expr, bb, check_self_loop, visited);
-
- free (visited);
- return rval;
-}
-
-/* Return the instruction that computes EXPR that reaches INSN's basic block.
- If there is more than one such instruction, return NULL.
-
- Called only by handle_avail_expr. */
-
-static rtx
-computing_insn (struct expr *expr, rtx insn)
-{
- basic_block bb = BLOCK_FOR_INSN (insn);
-
- if (expr->avail_occr->next == NULL)
- {
- if (BLOCK_FOR_INSN (expr->avail_occr->insn) == bb)
- /* The available expression is actually itself
- (i.e. a loop in the flow graph) so do nothing. */
- return NULL;
-
- /* (FIXME) Case that we found a pattern that was created by
- a substitution that took place. */
- return expr->avail_occr->insn;
- }
- else
- {
- /* Pattern is computed more than once.
- Search backwards from this insn to see how many of these
- computations actually reach this insn. */
- struct occr *occr;
- rtx insn_computes_expr = NULL;
- int can_reach = 0;
-
- for (occr = expr->avail_occr; occr != NULL; occr = occr->next)
- {
- if (BLOCK_FOR_INSN (occr->insn) == bb)
- {
- /* The expression is generated in this block.
- The only time we care about this is when the expression
- is generated later in the block [and thus there's a loop].
- We let the normal cse pass handle the other cases. */
- if (INSN_CUID (insn) < INSN_CUID (occr->insn)
- && expr_reaches_here_p (occr, expr, bb, 1))
- {
- can_reach++;
- if (can_reach > 1)
- return NULL;
-
- insn_computes_expr = occr->insn;
- }
- }
- else if (expr_reaches_here_p (occr, expr, bb, 0))
- {
- can_reach++;
- if (can_reach > 1)
- return NULL;
-
- insn_computes_expr = occr->insn;
- }
- }
-
- if (insn_computes_expr == NULL)
- abort ();
-
- return insn_computes_expr;
- }
-}
-
-/* Return nonzero if the definition in DEF_INSN can reach INSN.
- Only called by can_disregard_other_sets. */
-
-static int
-def_reaches_here_p (rtx insn, rtx def_insn)
-{
- rtx reg;
-
- if (TEST_BIT (reaching_defs[BLOCK_NUM (insn)], INSN_CUID (def_insn)))
- return 1;
-
- if (BLOCK_NUM (insn) == BLOCK_NUM (def_insn))
- {
- if (INSN_CUID (def_insn) < INSN_CUID (insn))
- {
- if (GET_CODE (PATTERN (def_insn)) == PARALLEL)
- return 1;
- else if (GET_CODE (PATTERN (def_insn)) == CLOBBER)
- reg = XEXP (PATTERN (def_insn), 0);
- else if (GET_CODE (PATTERN (def_insn)) == SET)
- reg = SET_DEST (PATTERN (def_insn));
- else
- abort ();
-
- return ! reg_set_between_p (reg, NEXT_INSN (def_insn), insn);
- }
- else
- return 0;
- }
-
- return 0;
-}
-
-/* Return nonzero if *ADDR_THIS_REG can only have one value at INSN. The
- value returned is the number of definitions that reach INSN. Returning a
- value of zero means that [maybe] more than one definition reaches INSN and
- the caller can't perform whatever optimization it is trying. i.e. it is
- always safe to return zero. */
-
-static int
-can_disregard_other_sets (struct reg_set **addr_this_reg, rtx insn, int for_combine)
-{
- int number_of_reaching_defs = 0;
- struct reg_set *this_reg;
-
- for (this_reg = *addr_this_reg; this_reg != 0; this_reg = this_reg->next)
- if (def_reaches_here_p (insn, this_reg->insn))
- {
- number_of_reaching_defs++;
- /* Ignore parallels for now. */
- if (GET_CODE (PATTERN (this_reg->insn)) == PARALLEL)
- return 0;
-
- if (!for_combine
- && (GET_CODE (PATTERN (this_reg->insn)) == CLOBBER
- || ! rtx_equal_p (SET_SRC (PATTERN (this_reg->insn)),
- SET_SRC (PATTERN (insn)))))
- /* A setting of the reg to a different value reaches INSN. */
- return 0;
-
- if (number_of_reaching_defs > 1)
- {
- /* If in this setting the value the register is being set to is
- equal to the previous value the register was set to and this
- setting reaches the insn we are trying to do the substitution
- on then we are ok. */
- if (GET_CODE (PATTERN (this_reg->insn)) == CLOBBER)
- return 0;
- else if (! rtx_equal_p (SET_SRC (PATTERN (this_reg->insn)),
- SET_SRC (PATTERN (insn))))
- return 0;
- }
-
- *addr_this_reg = this_reg;
- }
-
- return number_of_reaching_defs;
-}
-
-/* Expression computed by insn is available and the substitution is legal,
- so try to perform the substitution.
-
- The result is nonzero if any changes were made. */
-
-static int
-handle_avail_expr (rtx insn, struct expr *expr)
-{
- rtx pat, insn_computes_expr, expr_set;
- rtx to;
- struct reg_set *this_reg;
- int found_setting, use_src;
- int changed = 0;
-
- /* We only handle the case where one computation of the expression
- reaches this instruction. */
- insn_computes_expr = computing_insn (expr, insn);
- if (insn_computes_expr == NULL)
- return 0;
- expr_set = single_set (insn_computes_expr);
- /* The set might be in a parallel with multiple sets; we could
- probably handle that, but there's currently no easy way to find
- the relevant sub-expression. */
- if (!expr_set)
- return 0;
-
- found_setting = 0;
- use_src = 0;
-
- /* At this point we know only one computation of EXPR outside of this
- block reaches this insn. Now try to find a register that the
- expression is computed into. */
- if (GET_CODE (SET_SRC (expr_set)) == REG)
- {
- /* This is the case when the available expression that reaches
- here has already been handled as an available expression. */
- unsigned int regnum_for_replacing
- = REGNO (SET_SRC (expr_set));
-
- /* If the register was created by GCSE we can't use `reg_set_table',
- however we know it's set only once. */
- if (regnum_for_replacing >= max_gcse_regno
- /* If the register the expression is computed into is set only once,
- or only one set reaches this insn, we can use it. */
- || (((this_reg = reg_set_table[regnum_for_replacing]),
- this_reg->next == NULL)
- || can_disregard_other_sets (&this_reg, insn, 0)))
- {
- use_src = 1;
- found_setting = 1;
- }
- }
-
- if (!found_setting)
- {
- unsigned int regnum_for_replacing
- = REGNO (SET_DEST (expr_set));
-
- /* This shouldn't happen. */
- if (regnum_for_replacing >= max_gcse_regno)
- abort ();
-
- this_reg = reg_set_table[regnum_for_replacing];
-
- /* If the register the expression is computed into is set only once,
- or only one set reaches this insn, use it. */
- if (this_reg->next == NULL
- || can_disregard_other_sets (&this_reg, insn, 0))
- found_setting = 1;
- }
-
- if (found_setting)
- {
- pat = PATTERN (insn);
- if (use_src)
- to = SET_SRC (expr_set);
- else
- to = SET_DEST (expr_set);
- changed = validate_change (insn, &SET_SRC (pat), to, 0);
-
- /* We should be able to ignore the return code from validate_change but
- to play it safe we check. */
- if (changed)
- {
- gcse_subst_count++;
- if (gcse_file != NULL)
- {
- fprintf (gcse_file, "GCSE: Replacing the source in insn %d with",
- INSN_UID (insn));
- fprintf (gcse_file, " reg %d %s insn %d\n",
- REGNO (to), use_src ? "from" : "set in",
- INSN_UID (insn_computes_expr));
- }
- }
- }
-
- /* The register that the expr is computed into is set more than once. */
- else if (1 /*expensive_op(this_pattrn->op) && do_expensive_gcse)*/)
- {
- /* Insert an insn after insnx that copies the reg set in insnx
- into a new pseudo register call this new register REGN.
- From insnb until end of basic block or until REGB is set
- replace all uses of REGB with REGN. */
- rtx new_insn;
-
- to = gen_reg_rtx (GET_MODE (SET_DEST (expr_set)));
-
- /* Generate the new insn. */
- /* ??? If the change fails, we return 0, even though we created
- an insn. I think this is ok. */
- new_insn
- = emit_insn_after (gen_rtx_SET (VOIDmode, to,
- SET_DEST (expr_set)),
- insn_computes_expr);
-
- /* Keep register set table up to date. */
- record_one_set (REGNO (to), new_insn);
-
- gcse_create_count++;
- if (gcse_file != NULL)
- {
- fprintf (gcse_file, "GCSE: Creating insn %d to copy value of reg %d",
- INSN_UID (NEXT_INSN (insn_computes_expr)),
- REGNO (SET_SRC (PATTERN (NEXT_INSN (insn_computes_expr)))));
- fprintf (gcse_file, ", computed in insn %d,\n",
- INSN_UID (insn_computes_expr));
- fprintf (gcse_file, " into newly allocated reg %d\n",
- REGNO (to));
- }
-
- pat = PATTERN (insn);
-
- /* Do register replacement for INSN. */
- changed = validate_change (insn, &SET_SRC (pat),
- SET_DEST (PATTERN
- (NEXT_INSN (insn_computes_expr))),
- 0);
-
- /* We should be able to ignore the return code from validate_change but
- to play it safe we check. */
- if (changed)
- {
- gcse_subst_count++;
- if (gcse_file != NULL)
- {
- fprintf (gcse_file,
- "GCSE: Replacing the source in insn %d with reg %d ",
- INSN_UID (insn),
- REGNO (SET_DEST (PATTERN (NEXT_INSN
- (insn_computes_expr)))));
- fprintf (gcse_file, "set in insn %d\n",
- INSN_UID (insn_computes_expr));
- }
- }
- }
-
- return changed;
-}
-
-/* Perform classic GCSE. This is called by one_classic_gcse_pass after all
- the dataflow analysis has been done.
-
- The result is nonzero if a change was made. */
-
-static int
-classic_gcse (void)
-{
- int changed;
- rtx insn;
- basic_block bb;
-
- /* Note we start at block 1. */
-
- if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR)
- return 0;
-
- changed = 0;
- FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb->next_bb, EXIT_BLOCK_PTR, next_bb)
- {
- /* Reset tables used to keep track of what's still valid [since the
- start of the block]. */
- reset_opr_set_tables ();
-
- for (insn = BB_HEAD (bb);
- insn != NULL && insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
- {
- /* Is insn of form (set (pseudo-reg) ...)? */
- if (GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == SET
- && GET_CODE (SET_DEST (PATTERN (insn))) == REG
- && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_PSEUDO_REGISTER)
- {
- rtx pat = PATTERN (insn);
- rtx src = SET_SRC (pat);
- struct expr *expr;
-
- if (want_to_gcse_p (src)
- /* Is the expression recorded? */
- && ((expr = lookup_expr (src, &expr_hash_table)) != NULL)
- /* Is the expression available [at the start of the
- block]? */
- && TEST_BIT (ae_in[bb->index], expr->bitmap_index)
- /* Are the operands unchanged since the start of the
- block? */
- && oprs_not_set_p (src, insn))
- changed |= handle_avail_expr (insn, expr);
- }
-
- /* Keep track of everything modified by this insn. */
- /* ??? Need to be careful w.r.t. mods done to INSN. */
- if (INSN_P (insn))
- mark_oprs_set (insn);
- }
- }
-
- return changed;
-}
-
-/* Top level routine to perform one classic GCSE pass.
-
- Return nonzero if a change was made. */
-
-static int
-one_classic_gcse_pass (int pass)
-{
- int changed = 0;
-
- gcse_subst_count = 0;
- gcse_create_count = 0;
-
- alloc_hash_table (max_cuid, &expr_hash_table, 0);
- alloc_rd_mem (last_basic_block, max_cuid);
- compute_hash_table (&expr_hash_table);
- if (gcse_file)
- dump_hash_table (gcse_file, "Expression", &expr_hash_table);
-
- if (expr_hash_table.n_elems > 0)
- {
- compute_kill_rd ();
- compute_rd ();
- alloc_avail_expr_mem (last_basic_block, expr_hash_table.n_elems);
- compute_ae_gen (&expr_hash_table);
- compute_ae_kill (ae_gen, ae_kill, &expr_hash_table);
- compute_available (ae_gen, ae_kill, ae_out, ae_in);
- changed = classic_gcse ();
- free_avail_expr_mem ();
- }
-
- free_rd_mem ();
- free_hash_table (&expr_hash_table);
-
- if (gcse_file)
- {
- fprintf (gcse_file, "\n");
- fprintf (gcse_file, "GCSE of %s, pass %d: %d bytes needed, %d substs,",
- current_function_name (), pass, bytes_used, gcse_subst_count);
- fprintf (gcse_file, "%d insns created\n", gcse_create_count);
- }
-
- return changed;
-}
-\f
-/* Compute copy/constant propagation working variables. */
-
-/* Local properties of assignments. */
-static sbitmap *cprop_pavloc;
-static sbitmap *cprop_absaltered;
-
-/* Global properties of assignments (computed from the local properties). */
-static sbitmap *cprop_avin;
-static sbitmap *cprop_avout;
-
-/* Allocate vars used for copy/const propagation. N_BLOCKS is the number of
- basic blocks. N_SETS is the number of sets. */
-
-static void
-alloc_cprop_mem (int n_blocks, int n_sets)
-{
- cprop_pavloc = sbitmap_vector_alloc (n_blocks, n_sets);
- cprop_absaltered = sbitmap_vector_alloc (n_blocks, n_sets);
-
- cprop_avin = sbitmap_vector_alloc (n_blocks, n_sets);
- cprop_avout = sbitmap_vector_alloc (n_blocks, n_sets);
-}
-
-/* Free vars used by copy/const propagation. */
-
-static void
-free_cprop_mem (void)
-{
- sbitmap_vector_free (cprop_pavloc);
- sbitmap_vector_free (cprop_absaltered);
- sbitmap_vector_free (cprop_avin);
- sbitmap_vector_free (cprop_avout);
-}
-
-/* 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, set (SET_P == 1) or reset (SET_P == 0) the INDX
- bit in BMAP. */
-
-static void
-compute_transp (rtx x, int indx, sbitmap *bmap, int set_p)
-{
- int i, j;
- basic_block bb;
- enum rtx_code code;
- reg_set *r;
- 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:
- if (set_p)
- {
- if (REGNO (x) < FIRST_PSEUDO_REGISTER)
- {
- FOR_EACH_BB (bb)
- if (TEST_BIT (reg_set_in_block[bb->index], REGNO (x)))
- SET_BIT (bmap[bb->index], indx);
- }
- else
- {
- for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
- SET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
- }
- }
- else
- {
- if (REGNO (x) < FIRST_PSEUDO_REGISTER)
- {
- FOR_EACH_BB (bb)
- if (TEST_BIT (reg_set_in_block[bb->index], REGNO (x)))
- RESET_BIT (bmap[bb->index], indx);
- }
- else
- {
- for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
- RESET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
- }
- }
-
- return;
-
- case MEM:
- FOR_EACH_BB (bb)
- {
- rtx list_entry = canon_modify_mem_list[bb->index];
-
- while (list_entry)
- {
- rtx dest, dest_addr;
-
- if (GET_CODE (XEXP (list_entry, 0)) == CALL_INSN)
- {
- if (set_p)
- SET_BIT (bmap[bb->index], indx);
- else
- RESET_BIT (bmap[bb->index], indx);
- break;
- }
- /* LIST_ENTRY must be an INSN of some kind that sets memory.
- Examine each hunk of memory that is modified. */
-
- dest = XEXP (list_entry, 0);
- list_entry = XEXP (list_entry, 1);
- dest_addr = XEXP (list_entry, 0);
-
- if (canon_true_dependence (dest, GET_MODE (dest), dest_addr,
- x, rtx_addr_varies_p))
- {
- if (set_p)
- SET_BIT (bmap[bb->index], indx);
- else
- RESET_BIT (bmap[bb->index], indx);
- break;
- }
- list_entry = XEXP (list_entry, 1);
- }
- }
-
- x = XEXP (x, 0);
- goto repeat;
-
- case PC:
- case CC0: /*FIXME*/
- case CONST:
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_VECTOR:
- 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, set_p);
- }
- else if (fmt[i] == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- compute_transp (XVECEXP (x, i, j), indx, bmap, set_p);
- }
-}
-
-/* Top level routine to do the dataflow analysis needed by copy/const
- propagation. */
-
-static void
-compute_cprop_data (void)
-{
- compute_local_properties (cprop_absaltered, cprop_pavloc, NULL, &set_hash_table);
- compute_available (cprop_pavloc, cprop_absaltered,
- cprop_avout, cprop_avin);
-}
-\f
-/* Copy/constant propagation. */
-
-/* Maximum number of register uses in an insn that we handle. */
-#define MAX_USES 8
-
-/* Table of uses found in an insn.
- Allocated statically to avoid alloc/free complexity and overhead. */
-static struct reg_use reg_use_table[MAX_USES];
-
-/* Index into `reg_use_table' while building it. */
-static int reg_use_count;
-
-/* Set up a list of register numbers used in INSN. The found uses are stored
- in `reg_use_table'. `reg_use_count' is initialized to zero before entry,
- and contains the number of uses in the table upon exit.
-
- ??? If a register appears multiple times we will record it multiple times.
- This doesn't hurt anything but it will slow things down. */
-
-static void
-find_used_regs (rtx *xptr, void *data ATTRIBUTE_UNUSED)
-{
- int i, j;
- enum rtx_code code;
- const char *fmt;
- rtx x = *xptr;
-
- /* 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);
- if (REG_P (x))
- {
- if (reg_use_count == MAX_USES)
- return;
+ if (reg_use_count == MAX_USES)
+ return;
reg_use_table[reg_use_count].reg_rtx = x;
reg_use_count++;
pre_redundant = NULL;
pre_insert_map = NULL;
pre_delete_map = NULL;
- ae_in = NULL;
- ae_out = NULL;
ae_kill = sbitmap_vector_alloc (n_blocks, n_exprs);
/* pre_insert and pre_delete are allocated later. */
sbitmap_vector_free (pre_insert_map);
if (pre_delete_map)
sbitmap_vector_free (pre_delete_map);
- if (ae_in)
- sbitmap_vector_free (ae_in);
- if (ae_out)
- sbitmap_vector_free (ae_out);
transp = comp = NULL;
pre_optimal = pre_redundant = pre_insert_map = pre_delete_map = NULL;
- ae_in = ae_out = NULL;
}
/* Top level routine to do the dataflow analysis needed by PRE. */
/* Compute ae_kill for each basic block using:
~(TRANSP | COMP)
-
- This is significantly faster than compute_ae_kill. */
+ */
FOR_EACH_BB (bb)
{
}
}
-/* Removal of useless null pointer checks */
-
-/* Called via note_stores. X is set by SETTER. If X is a register we must
- invalidate nonnull_local and set nonnull_killed. DATA is really a
- `null_pointer_info *'.
-
- We ignore hard registers. */
-
-static void
-invalidate_nonnull_info (rtx x, rtx setter ATTRIBUTE_UNUSED, void *data)
-{
- unsigned int regno;
- struct null_pointer_info *npi = (struct null_pointer_info *) data;
-
- while (GET_CODE (x) == SUBREG)
- x = SUBREG_REG (x);
-
- /* Ignore anything that is not a register or is a hard register. */
- if (GET_CODE (x) != REG
- || REGNO (x) < npi->min_reg
- || REGNO (x) >= npi->max_reg)
- return;
-
- regno = REGNO (x) - npi->min_reg;
-
- RESET_BIT (npi->nonnull_local[npi->current_block->index], regno);
- SET_BIT (npi->nonnull_killed[npi->current_block->index], regno);
-}
-
-/* Do null-pointer check elimination for the registers indicated in
- NPI. NONNULL_AVIN and NONNULL_AVOUT are pre-allocated sbitmaps;
- they are not our responsibility to free. */
-
-static int
-delete_null_pointer_checks_1 (unsigned int *block_reg, sbitmap *nonnull_avin,
- sbitmap *nonnull_avout,
- struct null_pointer_info *npi)
-{
- basic_block bb, current_block;
- sbitmap *nonnull_local = npi->nonnull_local;
- sbitmap *nonnull_killed = npi->nonnull_killed;
- int something_changed = 0;
-
- /* Compute local properties, nonnull and killed. A register will have
- the nonnull property if at the end of the current block its value is
- known to be nonnull. The killed property indicates that somewhere in
- the block any information we had about the register is killed.
-
- Note that a register can have both properties in a single block. That
- indicates that it's killed, then later in the block a new value is
- computed. */
- sbitmap_vector_zero (nonnull_local, last_basic_block);
- sbitmap_vector_zero (nonnull_killed, last_basic_block);
-
- FOR_EACH_BB (current_block)
- {
- rtx insn, stop_insn;
-
- /* Set the current block for invalidate_nonnull_info. */
- npi->current_block = current_block;
-
- /* Scan each insn in the basic block looking for memory references and
- register sets. */
- stop_insn = NEXT_INSN (BB_END (current_block));
- for (insn = BB_HEAD (current_block);
- insn != stop_insn;
- insn = NEXT_INSN (insn))
- {
- rtx set;
- rtx reg;
-
- /* Ignore anything that is not a normal insn. */
- if (! INSN_P (insn))
- continue;
-
- /* Basically ignore anything that is not a simple SET. We do have
- to make sure to invalidate nonnull_local and set nonnull_killed
- for such insns though. */
- set = single_set (insn);
- if (!set)
- {
- note_stores (PATTERN (insn), invalidate_nonnull_info, npi);
- continue;
- }
-
- /* See if we've got a usable memory load. We handle it first
- in case it uses its address register as a dest (which kills
- the nonnull property). */
- if (GET_CODE (SET_SRC (set)) == MEM
- && GET_CODE ((reg = XEXP (SET_SRC (set), 0))) == REG
- && REGNO (reg) >= npi->min_reg
- && REGNO (reg) < npi->max_reg)
- SET_BIT (nonnull_local[current_block->index],
- REGNO (reg) - npi->min_reg);
-
- /* Now invalidate stuff clobbered by this insn. */
- note_stores (PATTERN (insn), invalidate_nonnull_info, npi);
-
- /* And handle stores, we do these last since any sets in INSN can
- not kill the nonnull property if it is derived from a MEM
- appearing in a SET_DEST. */
- if (GET_CODE (SET_DEST (set)) == MEM
- && GET_CODE ((reg = XEXP (SET_DEST (set), 0))) == REG
- && REGNO (reg) >= npi->min_reg
- && REGNO (reg) < npi->max_reg)
- SET_BIT (nonnull_local[current_block->index],
- REGNO (reg) - npi->min_reg);
- }
- }
-
- /* Now compute global properties based on the local properties. This
- is a classic global availability algorithm. */
- compute_available (nonnull_local, nonnull_killed,
- nonnull_avout, nonnull_avin);
-
- /* Now look at each bb and see if it ends with a compare of a value
- against zero. */
- FOR_EACH_BB (bb)
- {
- rtx last_insn = BB_END (bb);
- rtx condition, earliest;
- int compare_and_branch;
-
- /* Since MIN_REG is always at least FIRST_PSEUDO_REGISTER, and
- since BLOCK_REG[BB] is zero if this block did not end with a
- comparison against zero, this condition works. */
- if (block_reg[bb->index] < npi->min_reg
- || block_reg[bb->index] >= npi->max_reg)
- continue;
-
- /* LAST_INSN is a conditional jump. Get its condition. */
- condition = get_condition (last_insn, &earliest, false);
-
- /* If we can't determine the condition then skip. */
- if (! condition)
- continue;
-
- /* Is the register known to have a nonzero value? */
- if (!TEST_BIT (nonnull_avout[bb->index], block_reg[bb->index] - npi->min_reg))
- continue;
-
- /* Try to compute whether the compare/branch at the loop end is one or
- two instructions. */
- if (earliest == last_insn)
- compare_and_branch = 1;
- else if (earliest == prev_nonnote_insn (last_insn))
- compare_and_branch = 2;
- else
- continue;
-
- /* We know the register in this comparison is nonnull at exit from
- this block. We can optimize this comparison. */
- if (GET_CODE (condition) == NE)
- {
- rtx new_jump;
-
- new_jump = emit_jump_insn_after (gen_jump (JUMP_LABEL (last_insn)),
- last_insn);
- JUMP_LABEL (new_jump) = JUMP_LABEL (last_insn);
- LABEL_NUSES (JUMP_LABEL (new_jump))++;
- emit_barrier_after (new_jump);
- }
-
- something_changed = 1;
- delete_insn (last_insn);
-#ifdef HAVE_cc0
- if (compare_and_branch == 2)
- delete_insn (earliest);
-#endif
- purge_dead_edges (bb);
-
- /* Don't check this block again. (Note that BB_END is
- invalid here; we deleted the last instruction in the
- block.) */
- block_reg[bb->index] = 0;
- }
-
- return something_changed;
-}
-
-/* Find EQ/NE comparisons against zero which can be (indirectly) evaluated
- at compile time.
-
- This is conceptually similar to global constant/copy propagation and
- classic global CSE (it even uses the same dataflow equations as cprop).
-
- If a register is used as memory address with the form (mem (reg)), then we
- know that REG can not be zero at that point in the program. Any instruction
- which sets REG "kills" this property.
-
- So, if every path leading to a conditional branch has an available memory
- reference of that form, then we know the register can not have the value
- zero at the conditional branch.
-
- So we merely need to compute the local properties and propagate that data
- around the cfg, then optimize where possible.
-
- We run this pass two times. Once before CSE, then again after CSE. This
- has proven to be the most profitable approach. It is rare for new
- optimization opportunities of this nature to appear after the first CSE
- pass.
-
- This could probably be integrated with global cprop with a little work. */
-
-int
-delete_null_pointer_checks (rtx f ATTRIBUTE_UNUSED)
-{
- sbitmap *nonnull_avin, *nonnull_avout;
- unsigned int *block_reg;
- basic_block bb;
- int reg;
- int regs_per_pass;
- int max_reg = max_reg_num ();
- struct null_pointer_info npi;
- int something_changed = 0;
-
- /* If we have only a single block, or it is too expensive, give up. */
- if (n_basic_blocks <= 1
- || is_too_expensive (_ ("NULL pointer checks disabled")))
- return 0;
-
- /* We need four bitmaps, each with a bit for each register in each
- basic block. */
- regs_per_pass = get_bitmap_width (4, last_basic_block, max_reg);
-
- /* Allocate bitmaps to hold local and global properties. */
- npi.nonnull_local = sbitmap_vector_alloc (last_basic_block, regs_per_pass);
- npi.nonnull_killed = sbitmap_vector_alloc (last_basic_block, regs_per_pass);
- nonnull_avin = sbitmap_vector_alloc (last_basic_block, regs_per_pass);
- nonnull_avout = sbitmap_vector_alloc (last_basic_block, regs_per_pass);
-
- /* Go through the basic blocks, seeing whether or not each block
- ends with a conditional branch whose condition is a comparison
- against zero. Record the register compared in BLOCK_REG. */
- block_reg = xcalloc (last_basic_block, sizeof (int));
- FOR_EACH_BB (bb)
- {
- rtx last_insn = BB_END (bb);
- rtx condition, earliest, reg;
-
- /* We only want conditional branches. */
- if (GET_CODE (last_insn) != JUMP_INSN
- || !any_condjump_p (last_insn)
- || !onlyjump_p (last_insn))
- continue;
-
- /* LAST_INSN is a conditional jump. Get its condition. */
- condition = get_condition (last_insn, &earliest, false);
-
- /* If we were unable to get the condition, or it is not an equality
- comparison against zero then there's nothing we can do. */
- if (!condition
- || (GET_CODE (condition) != NE && GET_CODE (condition) != EQ)
- || GET_CODE (XEXP (condition, 1)) != CONST_INT
- || (XEXP (condition, 1)
- != CONST0_RTX (GET_MODE (XEXP (condition, 0)))))
- continue;
-
- /* We must be checking a register against zero. */
- reg = XEXP (condition, 0);
- if (GET_CODE (reg) != REG)
- continue;
-
- block_reg[bb->index] = REGNO (reg);
- }
-
- /* Go through the algorithm for each block of registers. */
- for (reg = FIRST_PSEUDO_REGISTER; reg < max_reg; reg += regs_per_pass)
- {
- npi.min_reg = reg;
- npi.max_reg = MIN (reg + regs_per_pass, max_reg);
- something_changed |= delete_null_pointer_checks_1 (block_reg,
- nonnull_avin,
- nonnull_avout,
- &npi);
- }
-
- /* Free the table of registers compared at the end of every block. */
- free (block_reg);
-
- /* Free bitmaps. */
- sbitmap_vector_free (npi.nonnull_local);
- sbitmap_vector_free (npi.nonnull_killed);
- sbitmap_vector_free (nonnull_avin);
- sbitmap_vector_free (nonnull_avout);
-
- return something_changed;
-}
-
/* Code Hoisting variables and subroutines. */
/* Very busy expressions. */