Where is rd_gen computed in gcse.c
Steven Bosscher
stevenb@suse.de
Fri May 14 15:17:00 GMT 2004
On Monday 10 May 2004 18:39, Steven Bosscher wrote:
> On Monday 10 May 2004 18:21, law@redhat.com wrote:
> > I wouldn't lose a huge amount of sleep if the old classic GCSE algorithm
> > went away and we just didn't bother with GCSE at all when optimizing for
> > size.
>
> I wouldn't want you to lose any sleep at all, but I'll prepare
> a patch to remove classic gcse anyway. Whee, gcse is getting
> smaller and smaller :)
Like so. I also took the liberty of removing delete_null_pointer_checks
as discussed. Bootstrapped&tested on amd64, OK?
Gr.
Steven
-------------- next part --------------
* common.opt (fdelete-null-pointer-checks): Remove.
* opts.c (decode_options): Don't set delete_null_pointer_checks.
(common_handle_option): Likewise.
* passes.c (rest_of_handle_null_pointer): Remove.
(rest_of_handle_cse): Don't call rest_of_handle_null_pointer.
(rest_of_compilation): Likewise.
* toplev.c (flag_delete_null_pointer_checks): Remove flag.
* toplev.h (flag_delete_null_pointer_checks): Likewise.
* rtl.h (delete_null_pointer_checks): Remove prototype.
* gcse.c (rd_kill, rd_gen, reaching_defs, rd_out, ae_in, ae_out):
Remove declarations.
(get_bitmap_width, alloc_rd_mem, free_rd_mem, handle_rd_kill_set,
compute_kill_rd, compute_rd, alloc_avail_expr_mem,
free_avail_expr_mem, compute_ae_gen, expr_killed_p, compute_ae_kill,
expr_reaches_here_p, computing_insn, def_reaches_here_p,
can_disregard_other_sets, handle_avail_expr, classic_gcse,
one_classic_gcse_pass, invalidate_nonnull_info,
delete_null_pointer_checks_1, delete_null_pointer_checks,
expr_reached_here_p_work): Remove.
(gcse_main): Do not perform classic GCSE when optimizing for size.
(alloc_pre_mem, free_pre_mem): Don't touch ae_in and ae_out, they
are never used.
* doc/invoke.texi: Remove all references to null pointer check
elimination.
Index: common.opt
===================================================================
RCS file: /cvs/gcc/gcc/gcc/common.opt,v
retrieving revision 1.33
diff -c -3 -p -r1.33 common.opt
*** common.opt 13 May 2004 06:39:33 -0000 1.33
--- common.opt 14 May 2004 14:49:57 -0000
*************** fdelayed-branch
*** 302,311 ****
Common
Attempt to fill delay slots of branch instructions
- fdelete-null-pointer-checks
- Common
- Delete useless null pointer checks
-
fdiagnostics-show-location=
Common Joined RejectNegative
-fdiagnostics-show-location=[once|every-line] How often to emit source location at the beginning of line-wrapped diagnostics
--- 302,307 ----
Index: gcse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcse.c,v
retrieving revision 1.302
diff -c -3 -p -r1.302 gcse.c
*** gcse.c 13 May 2004 06:39:40 -0000 1.302
--- gcse.c 14 May 2004 14:50:01 -0000
*************** Software Foundation, 59 Temple Place - S
*** 192,198 ****
3) Perform copy/constant propagation.
! 4) Perform global cse.
5) Perform another pass of copy/constant propagation.
--- 192,199 ----
3) Perform copy/constant propagation.
! 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 struct ls_expr * pre_ldst_mems =
*** 485,491 ****
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.
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. */
--- 486,492 ----
static regset reg_set_bitmap;
/* For each block, a bitmap of registers set in the block.
! 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. */
*************** static int const_prop_count;
*** 515,539 ****
/* Number of copys propagated. */
static int copy_prop_count;
! /* 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;
/* Objects of this type are passed around by the null-pointer check
removal routines. */
--- 516,523 ----
/* Number of copys propagated. */
static int copy_prop_count;
! /* 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 alloc_gcse_mem (rtx);
*** 558,564 ****
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 *);
--- 542,547 ----
*************** static void compute_code_hoist_data (voi
*** 640,670 ****
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);
--- 623,630 ----
*************** gcse_main (rtx f, FILE *file)
*** 790,796 ****
changed = one_cprop_pass (pass + 1, 0, 0);
if (optimize_size)
! changed |= one_classic_gcse_pass (pass + 1);
else
{
changed |= one_pre_gcse_pass (pass + 1);
--- 750,756 ----
changed = one_cprop_pass (pass + 1, 0, 0);
if (optimize_size)
! /* Do nothing. */ ;
else
{
changed |= one_pre_gcse_pass (pass + 1);
*************** gcse_main (rtx f, FILE *file)
*** 821,828 ****
/* 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). */
if (optimize_size)
{
max_gcse_regno = max_reg_num ();
--- 781,787 ----
/* 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 don't run the partial redundancy algorithms). */
if (optimize_size)
{
max_gcse_regno = max_reg_num ();
*************** free_gcse_mem (void)
*** 1025,1070 ****
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);
- }
/* Compute the local properties of each recorded expression.
--- 984,989 ----
*************** mark_oprs_set (rtx insn)
*** 2878,3638 ****
}
- /* 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);
-
- reaching_defs = sbitmap_vector_alloc (n_blocks, n_insns);
- sbitmap_vector_zero (reaching_defs, n_blocks);
-
- rd_out = sbitmap_vector_alloc (n_blocks, n_insns);
- sbitmap_vector_zero (rd_out, n_blocks);
- }
-
- /* Free reaching def variables. */
-
- static void
- free_rd_mem (void)
- {
- sbitmap_vector_free (rd_kill);
- sbitmap_vector_free (rd_gen);
- sbitmap_vector_free (reaching_defs);
- sbitmap_vector_free (rd_out);
- }
-
- /* Add INSN to the kills of BB. REGNO, set in BB, is killed by INSN. */
-
- static void
- handle_rd_kill_set (rtx insn, int regno, basic_block bb)
- {
- 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));
- }
-
- /* Compute the set of kill's for reaching definitions. */
-
- static void
- compute_kill_rd (void)
- {
- int cuid;
- unsigned int regno;
- int i;
- basic_block bb;
-
- /* 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);
-
- if (GET_CODE (insn) == CALL_INSN)
- {
- 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);
- }
-
- if (GET_CODE (pat) == PARALLEL)
- {
- 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);
- }
- }
- 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)
- {
- 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]);
- }
- passes++;
- }
-
- if (gcse_file)
- fprintf (gcse_file, "reaching def computation: %d passes\n", passes);
- }
-
- /* 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;
-
- /* 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);
- }
-
- /* Return nonzero if expression X is killed in BB. */
-
- static int
- expr_killed_p (rtx x, basic_block bb)
- {
- int i, j;
- enum rtx_code code;
- const char *fmt;
-
- if (x == 0)
- return 1;
-
- code = GET_CODE (x);
- switch (code)
- {
- case REG:
- return TEST_BIT (reg_set_in_block[bb->index], REGNO (x));
-
- 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);
-
- 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 0;
-
- 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)
- return expr_killed_p (XEXP (x, i), bb);
- else if (expr_killed_p (XEXP (x, i), bb))
- return 1;
- }
- else if (fmt[i] == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- if (expr_killed_p (XVECEXP (x, i, j), bb))
- return 1;
- }
-
- return 0;
- }
-
- /* Compute the set of available expressions killed in each basic block. */
-
- static void
- compute_ae_kill (sbitmap *ae_gen, sbitmap *ae_kill,
- struct hash_table *expr_hash_table)
- {
- 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);
- }
- }
-
- /* Actually perform the Classic GCSE optimizations. */
-
- /* Return nonzero if occurrence OCCR of expression EXPR reaches block BB.
-
- 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.
-
- VISITED is a pointer to a working buffer for tracking which BB's have
- been visited. It is NULL for the top-level call.
-
- 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. */
-
- static int
- expr_reaches_here_p_work (struct occr *occr, struct expr *expr,
- basic_block bb, int check_self_loop, char *visited)
- {
- edge pred;
-
- for (pred = bb->pred; pred != NULL; pred = pred->pred_next)
- {
- 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;
- }
-
/* Compute copy/constant propagation working variables. */
/* Local properties of assignments. */
--- 2797,2802 ----
*************** alloc_pre_mem (int n_blocks, int n_exprs
*** 5046,5053 ****
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. */
--- 4210,4215 ----
*************** free_pre_mem (void)
*** 5071,5084 ****
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. */
--- 4233,4241 ----
*************** compute_pre_data (void)
*** 5107,5114 ****
/* Compute ae_kill for each basic block using:
~(TRANSP | COMP)
!
! This is significantly faster than compute_ae_kill. */
FOR_EACH_BB (bb)
{
--- 4264,4270 ----
/* Compute ae_kill for each basic block using:
~(TRANSP | COMP)
! */
FOR_EACH_BB (bb)
{
*************** compute_transpout (void)
*** 5911,6205 ****
RESET_BIT (transpout[bb->index], expr->bitmap_index);
}
}
- }
-
- /* 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. */
--- 5067,5072 ----
Index: opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/opts.c,v
retrieving revision 1.68
diff -c -3 -p -r1.68 opts.c
*** opts.c 13 May 2004 06:39:44 -0000 1.68
--- opts.c 14 May 2004 14:50:02 -0000
*************** decode_options (unsigned int argc, const
*** 580,586 ****
#endif
flag_regmove = 1;
flag_strict_aliasing = 1;
- flag_delete_null_pointer_checks = 1;
flag_reorder_blocks = 1;
flag_reorder_functions = 1;
flag_unit_at_a_time = 1;
--- 580,585 ----
*************** common_handle_option (size_t scode, cons
*** 997,1006 ****
case OPT_fdelayed_branch:
flag_delayed_branch = value;
- break;
-
- case OPT_fdelete_null_pointer_checks:
- flag_delete_null_pointer_checks = value;
break;
case OPT_fdiagnostics_show_location_:
--- 996,1001 ----
Index: passes.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/passes.c,v
retrieving revision 2.12
diff -c -3 -p -r2.12 passes.c
*** passes.c 13 May 2004 06:39:44 -0000 2.12
--- passes.c 14 May 2004 14:50:02 -0000
*************** rest_of_handle_jump_bypass (tree decl, r
*** 1004,1023 ****
#endif
}
- /* Try to identify useless null pointer tests and delete them. */
- static void
- rest_of_handle_null_pointer (tree decl, rtx insns)
- {
- open_dump_file (DFI_null, decl);
- if (dump_file)
- dump_flow_info (dump_file);
-
- if (delete_null_pointer_checks (insns))
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
-
- close_dump_file (DFI_null, print_rtl_with_bb, insns);
- }
-
/* Try combining insns through substitution. */
static void
rest_of_handle_combine (tree decl, rtx insns)
--- 1004,1009 ----
*************** rest_of_handle_cse (tree decl, rtx insns
*** 1120,1138 ****
if (tem || optimize > 1)
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
- /* Try to identify useless null pointer tests and delete them. */
- if (flag_delete_null_pointer_checks)
- {
- timevar_push (TV_JUMP);
-
- if (delete_null_pointer_checks (insns))
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
- timevar_pop (TV_JUMP);
- }
-
- /* The second pass of jump optimization is likely to have
- removed a bunch more instructions. */
- renumber_insns (dump_file);
timevar_pop (TV_CSE);
close_dump_file (DFI_cse, print_rtl_with_bb, insns);
--- 1106,1111 ----
*************** rest_of_compilation (tree decl)
*** 1546,1554 ****
if (optimize)
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
-
- if (flag_delete_null_pointer_checks)
- rest_of_handle_null_pointer (decl, insns);
/* Jump optimization, and the removal of NULL pointer checks, may
have reduced the number of instructions substantially. CSE, and
--- 1519,1524 ----
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.471
diff -c -3 -p -r1.471 rtl.h
*** rtl.h 13 May 2004 06:39:45 -0000 1.471
--- rtl.h 14 May 2004 14:50:03 -0000
*************** extern void cannot_change_mode_set_regs
*** 2320,2327 ****
extern bool invalid_mode_change_p (unsigned int, enum reg_class,
enum machine_mode);
- extern int delete_null_pointer_checks (rtx);
-
/* In regmove.c */
#ifdef BUFSIZ
extern void regmove_optimize (rtx, int, FILE *);
--- 2320,2325 ----
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.897
diff -c -3 -p -r1.897 toplev.c
*** toplev.c 13 May 2004 06:39:45 -0000 1.897
--- toplev.c 14 May 2004 14:50:03 -0000
*************** int flag_if_conversion;
*** 524,534 ****
int flag_if_conversion2;
- /* Nonzero means to use global dataflow analysis to eliminate
- useless null pointer tests. */
-
- int flag_delete_null_pointer_checks;
-
/* Nonzero means perform global CSE. */
int flag_gcse = 0;
--- 524,529 ----
*************** static const lang_independent_options f_
*** 996,1002 ****
{"if-conversion2", &flag_if_conversion2, 1 },
{"rerun-cse-after-loop", &flag_rerun_cse_after_loop, 1 },
{"rerun-loop-opt", &flag_rerun_loop_opt, 1 },
- {"delete-null-pointer-checks", &flag_delete_null_pointer_checks, 1 },
{"schedule-insns", &flag_schedule_insns, 1 },
{"schedule-insns2", &flag_schedule_insns_after_reload, 1 },
{"sched-interblock",&flag_schedule_interblock, 1 },
--- 991,996 ----
Index: toplev.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.h,v
retrieving revision 1.120
diff -c -3 -p -r1.120 toplev.h
*** toplev.h 13 May 2004 06:39:45 -0000 1.120
--- toplev.h 14 May 2004 14:50:03 -0000
*************** extern int flag_loop_optimize;
*** 113,119 ****
extern int flag_crossjumping;
extern int flag_if_conversion;
extern int flag_if_conversion2;
- extern int flag_delete_null_pointer_checks;
extern int flag_keep_static_consts;
extern int flag_peel_loops;
extern int flag_rerun_cse_after_loop;
--- 113,118 ----
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.460
diff -c -3 -p -r1.460 invoke.texi
*** doc/invoke.texi 13 May 2004 06:40:25 -0000 1.460
--- doc/invoke.texi 14 May 2004 14:50:13 -0000
*************** in the following sections.
*** 281,287 ****
-fbranch-target-load-optimize2 -fbtr-bb-exclusive @gol
-fcaller-saves -fcprop-registers @gol
-fcse-follow-jumps -fcse-skip-blocks -fdata-sections @gol
! -fdelayed-branch -fdelete-null-pointer-checks @gol
-fexpensive-optimizations -ffast-math -ffloat-store @gol
-fforce-addr -fforce-mem -ffunction-sections @gol
-fgcse -fgcse-lm -fgcse-sm -fgcse-las -fgcse-after-reload @gol
--- 281,287 ----
-fbranch-target-load-optimize2 -fbtr-bb-exclusive @gol
-fcaller-saves -fcprop-registers @gol
-fcse-follow-jumps -fcse-skip-blocks -fdata-sections @gol
! -fdelayed-branch @gol
-fexpensive-optimizations -ffast-math -ffloat-store @gol
-fforce-addr -fforce-mem -ffunction-sections @gol
-fgcse -fgcse-lm -fgcse-sm -fgcse-las -fgcse-after-reload @gol
*************** also turns on the following optimization
*** 3802,3808 ****
-fcse-follow-jumps -fcse-skip-blocks @gol
-frerun-cse-after-loop -frerun-loop-opt @gol
-fgcse -fgcse-lm -fgcse-sm -fgcse-las @gol
- -fdelete-null-pointer-checks @gol
-fexpensive-optimizations @gol
-fregmove @gol
-fschedule-insns -fschedule-insns2 @gol
--- 3802,3807 ----
*************** Use conditional execution (where availab
*** 4204,4223 ****
branch-less equivalents.
Enabled at levels @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}.
-
- @item -fdelete-null-pointer-checks
- @opindex fdelete-null-pointer-checks
- Use global dataflow analysis to identify and eliminate useless checks
- for null pointers. The compiler assumes that dereferencing a null
- pointer would have halted the program. If a pointer is checked after
- it has already been dereferenced, it cannot be null.
-
- In some environments, this assumption is not true, and programs can
- safely dereference null pointers. Use
- @option{-fno-delete-null-pointer-checks} to disable this optimization
- for programs which depend on that behavior.
-
- Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
@item -fexpensive-optimizations
@opindex fexpensive-optimizations
--- 4203,4208 ----
More information about the Gcc-patches
mailing list