tree-vrp.c (find_conditional_asserts): Update comments.

2006-02-07  Jeff Law  <law@redhat.com>

	* tree-vrp.c (find_conditional_asserts): Update comments.
	(simplify_stmt_for_jump_threading): New.
	(identify_jump_threads, finalize_jump_threads): New.
	(vrp_finalize): Call identify_jump_threads.
	(execute_vrp): Call finalize_jump_threads.
	* tree-ssa-dom.c (struct opt_stats_d): Remove num_iterations field.
	(vrp_element, vrp_data, vrp_element_p): Remove.
	(vrp_hash_elt, vrp_variables_stack): Remove.
	(vrp_hash, vrp_eq, record_range): Remove.
	(simplify_cond_and_lookup_avail_expr): Remove.
	(extract_range_from_cond): Remove.
	(thread_across_edge): Relocated into tree-ssa-threadedge.c.
	(simplify_stmt_for_jump_threading): New.
	(dom_thread_across_edge): New wrapper.
	(tree_ssa_dominator_optimize): No longer initialize or
	finalize any of the VRP datastructures.  Remove iteration
	step and simplify as a result of removal of iteration step.
	(pass_dominator): Perform a cfg cleanup after DOM.
	(dom_opt_finalize_block): Use the new common routines
	for threading jumps.  Simplify stack management slightly.
	No longer need to unwind VRP state.
	(record_equivalences_from_incoming_edge): No longer record
	VRP information.
	(eliminate_redundant_computations): No longer call
	simplify_cond_and_lookup_avail_expr.
	* tree-flow.h (potentially_threadable_block): Prototype.
	(thread_across_edge): Likewise.
	* Makefile.in (OBJS-common):  Add tree-ssa-threadedge.o
	(tree-ssa-threadedge.o): Add dependencies.
	* tree-ssa-threadedge.c: New file.
	* passes.c (init_optimization_passes): Merge PHIs before
	calling VRP.  Run VRP again late in the SSA optimization pipeline.


	* gcc.dg/tree-ssa/vrp01.c: Update dumpfile names now that we have
	multiple VRP passes.
	* gcc.dg/tree-ssa/vrp09.c: Likewise.
	* gcc.dg/tree-ssa/vrp18.c: Likewise.
	* gcc.dg/tree-ssa/pr21582.c: Likewise.
	* gcc.dg/tree-ssa/pr20657.c: Likewise.
	* gcc.dg/tree-ssa/pr21001.c: Likewise.
	* gcc.dg/tree-ssa/vrp02.c: Likewise
	* gcc.dg/tree-ssa/vrp11.c: Likewise
	* gcc.dg/tree-ssa/pr14341.c: Likewise
	* gcc.dg/tree-ssa/vrp19.c: Likewise
	* gcc.dg/tree-ssa/vrp20.c: Likewise
	* gcc.dg/tree-ssa/vrp03.c: Likewise
	* gcc.dg/tree-ssa/pr21086.c: Likewise
	* gcc.dg/tree-ssa/pr21959.c: Likewise
	* gcc.dg/tree-ssa/vrp21.c: Likewise
	* gcc.dg/tree-ssa/vrp04.c: Likewise 
	* gcc.dg/tree-ssa/pr25485.c: Likewise
	* gcc.dg/tree-ssa/pr22026.c: Likewise
	* gcc.dg/tree-ssa/vrp22.c: Likewise
	* gcc.dg/tree-ssa/vrp05.c: Likewise
	* gcc.dg/tree-ssa/20030807-10.c: Likewise
	* gcc.dg/tree-ssa/pr20701.c: Likewise
	* gcc.dg/tree-ssa/vrp23.c: Likewise
	* gcc.dg/tree-ssa/vrp06.c: Likewise
	* gcc.dg/tree-ssa/pr22117.c: Likewise
	* gcc.dg/tree-ssa/pr20702.c: Likewise
	* gcc.dg/tree-ssa/vrp15.c: Likewise
	* gcc.dg/tree-ssa/pr21090.c: Likewise
	* gcc.dg/tree-ssa/pr21294.c: Likewise
	* gcc.dg/tree-ssa/vrp24.c: Likewise
	* gcc.dg/tree-ssa/vrp07.c: Likewise
	* gcc.dg/tree-ssa/pr21563.c: Likewise
	* gcc.dg/tree-ssa/pr25382.c: Likewise
	* gcc.dg/tree-ssa/vrp16.c: Likewise
	* gcc.dg/tree-ssa/vrp25.c: Likewise
	* gcc.dg/tree-ssa/vrp08.c: Likewise
	* gcc.dg/tree-ssa/20030807-6.c: Likewise
	* gcc.dg/tree-ssa/vrp17.c: Likewise
	* gcc.dg/tree-ssa/pr21458.c: Likewise
	* g++.dg/tree-ssa/pr18178.C: Likewise

From-SVN: r110705
This commit is contained in:
Jeff Law 2006-02-07 11:31:27 -07:00 committed by Jeff Law
parent e45dcf9c6e
commit 2090d6a0a8
48 changed files with 1026 additions and 1090 deletions

View File

@ -1,3 +1,38 @@
2006-02-07 Jeff Law <law@redhat.com>
* tree-vrp.c (find_conditional_asserts): Update comments.
(simplify_stmt_for_jump_threading): New.
(identify_jump_threads, finalize_jump_threads): New.
(vrp_finalize): Call identify_jump_threads.
(execute_vrp): Call finalize_jump_threads.
* tree-ssa-dom.c (struct opt_stats_d): Remove num_iterations field.
(vrp_element, vrp_data, vrp_element_p): Remove.
(vrp_hash_elt, vrp_variables_stack): Remove.
(vrp_hash, vrp_eq, record_range): Remove.
(simplify_cond_and_lookup_avail_expr): Remove.
(extract_range_from_cond): Remove.
(thread_across_edge): Relocated into tree-ssa-threadedge.c.
(simplify_stmt_for_jump_threading): New.
(dom_thread_across_edge): New wrapper.
(tree_ssa_dominator_optimize): No longer initialize or
finalize any of the VRP datastructures. Remove iteration
step and simplify as a result of removal of iteration step.
(pass_dominator): Perform a cfg cleanup after DOM.
(dom_opt_finalize_block): Use the new common routines
for threading jumps. Simplify stack management slightly.
No longer need to unwind VRP state.
(record_equivalences_from_incoming_edge): No longer record
VRP information.
(eliminate_redundant_computations): No longer call
simplify_cond_and_lookup_avail_expr.
* tree-flow.h (potentially_threadable_block): Prototype.
(thread_across_edge): Likewise.
* Makefile.in (OBJS-common): Add tree-ssa-threadedge.o
(tree-ssa-threadedge.o): Add dependencies.
* tree-ssa-threadedge.c: New file.
* passes.c (init_optimization_passes): Merge PHIs before
calling VRP. Run VRP again late in the SSA optimization pipeline.
2006-02-07 Richard Guenther <rguenther@suse.de>
PR c++/26140

View File

@ -961,7 +961,7 @@ OBJS-common = \
tree-ssa-dom.o domwalk.o tree-tailcall.o gimple-low.o tree-iterator.o \
omp-low.o tree-phinodes.o tree-ssanames.o tree-sra.o tree-complex.o \
tree-vect-generic.o tree-ssa-loop.o tree-ssa-loop-niter.o \
tree-ssa-loop-manip.o tree-ssa-threadupdate.o \
tree-ssa-loop-manip.o tree-ssa-threadupdate.o tree-ssa-threadedge.o \
tree-vectorizer.o tree-vect-analyze.o tree-vect-transform.o \
tree-vect-patterns.o \
tree-ssa-loop-ivcanon.o tree-ssa-propagate.o tree-ssa-address.o \
@ -1860,6 +1860,10 @@ tree-ssa-uncprop.o : tree-ssa-uncprop.c $(TREE_FLOW_H) $(CONFIG_H) \
$(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
$(TREE_DUMP_H) $(BASIC_BLOCK_H) domwalk.h real.h tree-pass.h $(FLAGS_H) \
langhooks.h tree-ssa-propagate.h
tree-ssa-threadedge.o : tree-ssa-threadedge.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \
$(DIAGNOSTIC_H) $(FUNCTION_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
$(BASIC_BLOCK_H) $(FLAGS_H) tree-pass.h $(CFGLOOP_H)
tree-ssa-threadupdate.o : tree-ssa-threadupdate.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \
$(DIAGNOSTIC_H) $(FUNCTION_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \

View File

@ -1,6 +1,6 @@
/* Top level of GCC compilers (cc1, cc1plus, etc.)
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GCC.
@ -507,9 +507,9 @@ init_optimization_passes (void)
NEXT_PASS (pass_dce);
NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_vrp);
NEXT_PASS (pass_dce);
NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_dominator);
/* The only copy propagation opportunities left after DOM
@ -560,6 +560,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_tree_loop);
NEXT_PASS (pass_cse_reciprocals);
NEXT_PASS (pass_reassoc);
NEXT_PASS (pass_vrp);
NEXT_PASS (pass_dominator);
/* The only copy propagation opportunities left after DOM

View File

@ -1,3 +1,47 @@
2006-02-07 Jeff Law <law@redhat.com>
* gcc.dg/tree-ssa/vrp01.c: Update dumpfile names now that we have
multiple VRP passes.
* gcc.dg/tree-ssa/vrp09.c: Likewise.
* gcc.dg/tree-ssa/vrp18.c: Likewise.
* gcc.dg/tree-ssa/pr21582.c: Likewise.
* gcc.dg/tree-ssa/pr20657.c: Likewise.
* gcc.dg/tree-ssa/pr21001.c: Likewise.
* gcc.dg/tree-ssa/vrp02.c: Likewise
* gcc.dg/tree-ssa/vrp11.c: Likewise
* gcc.dg/tree-ssa/pr14341.c: Likewise
* gcc.dg/tree-ssa/vrp19.c: Likewise
* gcc.dg/tree-ssa/vrp20.c: Likewise
* gcc.dg/tree-ssa/vrp03.c: Likewise
* gcc.dg/tree-ssa/pr21086.c: Likewise
* gcc.dg/tree-ssa/pr21959.c: Likewise
* gcc.dg/tree-ssa/vrp21.c: Likewise
* gcc.dg/tree-ssa/vrp04.c: Likewise
* gcc.dg/tree-ssa/pr25485.c: Likewise
* gcc.dg/tree-ssa/pr22026.c: Likewise
* gcc.dg/tree-ssa/vrp22.c: Likewise
* gcc.dg/tree-ssa/vrp05.c: Likewise
* gcc.dg/tree-ssa/20030807-10.c: Likewise
* gcc.dg/tree-ssa/pr20701.c: Likewise
* gcc.dg/tree-ssa/vrp23.c: Likewise
* gcc.dg/tree-ssa/vrp06.c: Likewise
* gcc.dg/tree-ssa/pr22117.c: Likewise
* gcc.dg/tree-ssa/pr20702.c: Likewise
* gcc.dg/tree-ssa/vrp15.c: Likewise
* gcc.dg/tree-ssa/pr21090.c: Likewise
* gcc.dg/tree-ssa/pr21294.c: Likewise
* gcc.dg/tree-ssa/vrp24.c: Likewise
* gcc.dg/tree-ssa/vrp07.c: Likewise
* gcc.dg/tree-ssa/pr21563.c: Likewise
* gcc.dg/tree-ssa/pr25382.c: Likewise
* gcc.dg/tree-ssa/vrp16.c: Likewise
* gcc.dg/tree-ssa/vrp25.c: Likewise
* gcc.dg/tree-ssa/vrp08.c: Likewise
* gcc.dg/tree-ssa/20030807-6.c: Likewise
* gcc.dg/tree-ssa/vrp17.c: Likewise
* gcc.dg/tree-ssa/pr21458.c: Likewise
* g++.dg/tree-ssa/pr18178.C: Likewise
2006-02-07 Richard Guenther <rguenther@suse.de>
PR c++/26140

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
// Define this to see it work.
// #define WORK_WORK_WORK
@ -43,5 +43,5 @@ void doit (array *a)
/* VRP should remove all but 1 if() in the loop. */
/* { dg-final { scan-tree-dump-times "if " 1 "vrp"} } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "if " 1 "vrp1"} } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
extern const unsigned char mode_size[];
@ -18,9 +18,9 @@ subreg_highpart_offset (outermode, innermode)
}
/* There should be one mask with the value 3. */
/* { dg-final { scan-tree-dump-times " \& 3" 1 "vrp"} } */
/* { dg-final { scan-tree-dump-times " \& 3" 1 "vrp1"} } */
/* There should be one right shift by 2 places. */
/* { dg-final { scan-tree-dump-times " >> 2" 1 "vrp"} } */
/* { dg-final { scan-tree-dump-times " >> 2" 1 "vrp1"} } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
void
@ -39,5 +39,5 @@ foo4 (distance, i, j)
}
/* There should be no ABS_EXPR. */
/* { dg-final { scan-tree-dump-times "ABS_EXPR " 0 "vrp"} } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "ABS_EXPR " 0 "vrp1"} } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
void fn_call (int);
int h(int, int);
@ -12,5 +12,5 @@ void t()
}
}
/* { dg-final { scan-tree-dump-times "fn_call \\(1\\)" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "fn_call \\(1\\)" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -3,7 +3,7 @@
statement, which was needed to eliminate the second "if" statement. */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details" } */
int
foo (int a)
@ -14,5 +14,5 @@ foo (int a)
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp"} } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
typedef struct {
int code;
@ -26,5 +26,5 @@ can_combine_p (rtx insn, rtx elt)
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 0" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 0" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -4,7 +4,7 @@
immediate successors of the basic block. */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details" } */
extern void bar (int);
@ -25,5 +25,5 @@ foo (int *p, int b)
return a;
}
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp"} } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -5,7 +5,7 @@
range infomation out of the conditional. */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details" } */
int
foo (int a)
@ -17,5 +17,5 @@ foo (int a)
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp"} } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
int
foo (int *p)
@ -15,5 +15,5 @@ foo (int *p)
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate " 2 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate " 2 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
int g, h;
@ -19,5 +19,5 @@ foo (int a)
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -4,7 +4,7 @@
allows us to eliminate the second "if" statement. */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details" } */
struct f {
int i;
@ -19,5 +19,5 @@ foo (struct f *p)
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp"} } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
extern void g (void);
extern void bar (int);
@ -16,5 +16,5 @@ foo (int a)
}
}
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -2,7 +2,7 @@
Make sure VRP folds the second "if" statement. */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details" } */
int
foo (int a)
@ -13,5 +13,5 @@ foo (int a)
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp"} } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do link } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
static inline void do_thing(char *s, int *p, char *q)
{
@ -24,5 +24,5 @@ main()
do_other_thing ("xxx", &i, "yyy");
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*" 0 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*" 0 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
unsigned char c[0xFF];
void f(void)
@ -16,5 +16,5 @@ void f(void)
}
}
/* { dg-final { scan-tree-dump-times "Folding predicate " 0 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate " 0 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -3,7 +3,7 @@
same applies to subtraction and unsigned multiplication. */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
int
plus (int x, int y)
@ -45,5 +45,5 @@ mult (unsigned x, unsigned y)
}
/* None of the predicates can be folded in these functions. */
/* { dg-final { scan-tree-dump-times "Folding predicate" 0 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate" 0 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -3,7 +3,7 @@
known to be zero after entering the first two "if" statements. */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
void
foo (int *p, int q)
@ -19,5 +19,5 @@ foo (int *p, int q)
}
}
/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -3,7 +3,7 @@
Check that VRP now gets ranges from BIT_AND_EXPRs. */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
int
foo (int a)
@ -15,5 +15,5 @@ foo (int a)
return 1;
}
/* { dg-final { scan-tree-dump-times "Folding predicate b_.* > 300 to 0" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate b_.* > 300 to 0" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,7 +1,7 @@
/* PR tree-optimization/25485
VRP did not fold TRUTH_AND_EXPR. Make sure it does now. */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
int
foo (int a, int b)
@ -13,5 +13,5 @@ foo (int a, int b)
return 31;
}
/* { dg-final { scan-tree-dump-times "if" 1 "vrp"} } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "if" 1 "vrp1"} } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
foo (int *p, int i)
{
@ -24,5 +24,5 @@ foo (int *p, int i)
return i;
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
struct A
{
@ -20,5 +20,5 @@ foo (struct A *p, struct A *q)
return x + p->b;
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
struct A
{
@ -30,6 +30,6 @@ foo (struct A *p, struct A *q)
return q->a;
}
/* { dg-final { scan-tree-dump-times "Folding predicate q_.*to 1" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate r_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate q_.*to 1" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate r_.*to 1" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
foo (int a, int b)
{
@ -9,5 +9,5 @@ foo (int a, int b)
return a + b;
}
/* { dg-final { scan-tree-dump-times "Folding predicate a_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate a_.*to 1" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
foo (int k, int j)
{
@ -16,5 +16,5 @@ foo (int k, int j)
return j;
}
/* { dg-final { scan-tree-dump-times "Folding predicate j_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate j_.*to 1" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
foo (int i, int j, int a)
{
@ -25,7 +25,7 @@ foo (int i, int j, int a)
return i + a + j;
}
/* { dg-final { scan-tree-dump-times "Folding predicate i_.*to 0" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate j_.*to 1" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate i_.*to 0" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate i_.*to 0" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate j_.*to 1" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate i_.*to 0" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
foo (int i, int *p)
{
@ -30,7 +30,7 @@ foo (int i, int *p)
return i;
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 0" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "PREDICATE: p_\[0-9\] ne_expr 0B" 2 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 0" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "PREDICATE: p_\[0-9\] ne_expr 0B" 2 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
/* Compile with -fno-tree-fre -O2 to prevent CSEing *p. */
foo (int a, int *p)
@ -18,6 +18,6 @@ foo (int a, int *p)
return a;
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "PREDICATE: p_. ne_expr 0" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "PREDICATE: p_. ne_expr 0" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
foo (int *p)
{
@ -27,5 +27,5 @@ L78:
}
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.. != 0B to 1" 2 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate p_.. != 0B to 1" 2 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
foo (int k, int j, int z)
{
@ -16,5 +16,5 @@ foo (int k, int j, int z)
return j;
}
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
extern void abort (void) __attribute__ ((__noreturn__));
@ -29,6 +29,6 @@ blah (tree t)
}
/* { dg-final { scan-tree-dump-times "tree_code_length.42." 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "tree_code_length.42." 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
extern void abort (void) __attribute__ ((__noreturn__));
@ -18,6 +18,6 @@ nonlocal_mentioned_p (rtx x)
abort ();
}
/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
extern void abort (void) __attribute__ ((__noreturn__));
union tree_node;
@ -27,6 +27,6 @@ gimplify_for_stmt (tree stmt)
abort ();
}
/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
static int blocksize = 4096;
@ -30,5 +30,5 @@ void foo (void)
eof_reached = 1;
}
/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-vrp" } */
/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-vrp1" } */
#include <limits.h>
extern void abort ();
@ -22,6 +22,6 @@ int g (int b) {
}
return 1;
}
/* { dg-final { scan-tree-dump "Folding predicate a_. < 0 to 0" "vrp" } } */
/* { dg-final { scan-tree-dump "Folding predicate b_. >= 0 to 1" "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump "Folding predicate a_. < 0 to 0" "vrp1" } } */
/* { dg-final { scan-tree-dump "Folding predicate b_. >= 0 to 1" "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-vrp" } */
/* { dg-options "-fwrapv -O1 -ftree-vrp -fdump-tree-vrp1" } */
extern void abort ();
extern void exit (int);
@ -23,6 +23,6 @@ int g (int b) {
return 1;
}
/* { dg-final { scan-tree-dump "Folding predicate a_. == 0 to 0" "vrp" } } */
/* { dg-final { scan-tree-dump "Folding predicate b_. != 0 to 1" "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump "Folding predicate a_. == 0 to 0" "vrp1" } } */
/* { dg-final { scan-tree-dump "Folding predicate b_. != 0 to 1" "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -ftree-vrp -fdump-tree-vrp" } */
/* { dg-options "-O1 -ftree-vrp -fdump-tree-vrp1" } */
extern void link_error ();
@ -22,5 +22,5 @@ void test02(unsigned int a, unsigned int b)
link_error ();
}
/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -ftree-vrp -fdump-tree-vrp" } */
/* { dg-options "-O1 -ftree-vrp -fdump-tree-vrp1" } */
extern void link_error ();
@ -12,5 +12,5 @@ void test02(unsigned int a, unsigned int b)
link_error ();
}
/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
blah (int code1, int code2)
{
@ -40,6 +40,6 @@ L8:
/* The n_sets > 0 test can be simplified into n_sets == 1 since the
only way to reach the test is when n_sets <= 1, and the only value
which satisfies both conditions is n_sets == 1. */
/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
struct rtx_def;
@ -84,6 +84,6 @@ L7:
/* The n_sets > 0 test can be simplified into n_sets == 1 since the
only way to reach the test is when n_sets <= 1, and the only value
which satisfies both conditions is n_sets == 1. */
/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Simplified relational" 1 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp-details" } */
/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
extern void abort ();
int tree_code_length[100];
@ -47,6 +47,6 @@ L9:
/* The second test of (code1 != 53) and the test (D18670 <= 2) are
both totally subsumed by earlier tests and thus should be folded
away using VRP. */
/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -749,6 +749,11 @@ tree expand_simple_operations (tree);
void substitute_in_loop_info (struct loop *, tree, tree);
edge single_dom_exit (struct loop *);
/* In tree-ssa-threadedge.c */
extern bool potentially_threadable_block (basic_block);
extern void thread_across_edge (tree, edge, bool,
VEC(tree, heap) **, tree (*) (tree));
/* In tree-ssa-loop-im.c */
/* The possibilities of statement movement. */

File diff suppressed because it is too large Load Diff

537
gcc/tree-ssa-threadedge.c Normal file
View File

@ -0,0 +1,537 @@
/* SSA Jump Threading
Copyright (C) 2005, 2006 Free Software Foundation, Inc.
Contributed by Jeff Law <law@redhat.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "flags.h"
#include "rtl.h"
#include "tm_p.h"
#include "ggc.h"
#include "basic-block.h"
#include "cfgloop.h"
#include "output.h"
#include "expr.h"
#include "function.h"
#include "diagnostic.h"
#include "timevar.h"
#include "tree-dump.h"
#include "tree-flow.h"
#include "domwalk.h"
#include "real.h"
#include "tree-pass.h"
#include "tree-ssa-propagate.h"
#include "langhooks.h"
#include "params.h"
/* To avoid code explosion due to jump threading, we limit the
number of statements we are going to copy. This variable
holds the number of statements currently seen that we'll have
to copy as part of the jump threading process. */
static int stmt_count;
/* Return TRUE if we may be able to thread an incoming edge into
BB to an outgoing edge from BB. Return FALSE otherwise. */
bool
potentially_threadable_block (basic_block bb)
{
block_stmt_iterator bsi;
/* If BB has a single successor or a single predecessor, then
there is no threading opportunity. */
if (single_succ_p (bb) || single_pred_p (bb))
return false;
/* If BB does not end with a conditional, switch or computed goto,
then there is no threading opportunity. */
bsi = bsi_last (bb);
if (bsi_end_p (bsi)
|| ! bsi_stmt (bsi)
|| (TREE_CODE (bsi_stmt (bsi)) != COND_EXPR
&& TREE_CODE (bsi_stmt (bsi)) != GOTO_EXPR
&& TREE_CODE (bsi_stmt (bsi)) != SWITCH_EXPR))
return false;
return true;
}
/* Return the LHS of any ASSERT_EXPR where OP appears as the first
argument to the ASSERT_EXPR and in which the ASSERT_EXPR dominates
BB. If no such ASSERT_EXPR is found, return OP. */
static tree
lhs_of_dominating_assert (tree op, basic_block bb, tree stmt)
{
imm_use_iterator imm_iter;
use_operand_p imm_use;
FOR_EACH_IMM_USE_SAFE (imm_use, imm_iter, op)
{
tree use_stmt = USE_STMT (imm_use);
if (use_stmt != stmt
&& TREE_CODE (use_stmt) == MODIFY_EXPR
&& TREE_CODE (TREE_OPERAND (use_stmt, 1)) == ASSERT_EXPR
&& TREE_OPERAND (TREE_OPERAND (use_stmt, 1), 0) == op
&& dominated_by_p (CDI_DOMINATORS, bb, bb_for_stmt (use_stmt)))
op = TREE_OPERAND (use_stmt, 0);
}
return op;
}
/* We record temporary equivalences created by PHI nodes or
statements within the target block. Doing so allows us to
identify more jump threading opportunities, even in blocks
with side effects.
We keep track of those temporary equivalences in a stack
structure so that we can unwind them when we're done processing
a particular edge. This routine handles unwinding the data
structures. */
static void
remove_temporary_equivalences (VEC(tree, heap) **stack)
{
while (VEC_length (tree, *stack) > 0)
{
tree prev_value, dest;
dest = VEC_pop (tree, *stack);
/* A NULL value indicates we should stop unwinding, oherwise
pop off the next entry as they're recorded in pairs. */
if (dest == NULL)
break;
prev_value = VEC_pop (tree, *stack);
SSA_NAME_VALUE (dest) = prev_value;
}
}
/* Record a temporary equivalence, saving enough information so that
we can restore the state of recorded equivalences when we're
done processing the current edge. */
static void
record_temporary_equivalence (tree x, tree y, VEC(tree, heap) **stack)
{
tree prev_x = SSA_NAME_VALUE (x);
if (TREE_CODE (y) == SSA_NAME)
{
tree tmp = SSA_NAME_VALUE (y);
y = tmp ? tmp : y;
}
SSA_NAME_VALUE (x) = y;
VEC_reserve (tree, heap, *stack, 2);
VEC_quick_push (tree, *stack, prev_x);
VEC_quick_push (tree, *stack, x);
}
/* Record temporary equivalences created by PHIs at the target of the
edge E. Record unwind information for the equivalences onto STACK.
If a PHI which prevents threading is encountered, then return FALSE
indicating we should not thread this edge, else return TRUE. */
static bool
record_temporary_equivalences_from_phis (edge e, VEC(tree, heap) **stack)
{
tree phi;
/* Each PHI creates a temporary equivalence, record them.
These are context sensitive equivalences and will be removed
later. */
for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
{
tree src = PHI_ARG_DEF_FROM_EDGE (phi, e);
tree dst = PHI_RESULT (phi);
/* If the desired argument is not the same as this PHI's result
and it is set by a PHI in E->dest, then we can not thread
through E->dest. */
if (src != dst
&& TREE_CODE (src) == SSA_NAME
&& TREE_CODE (SSA_NAME_DEF_STMT (src)) == PHI_NODE
&& bb_for_stmt (SSA_NAME_DEF_STMT (src)) == e->dest)
return false;
/* We consider any non-virtual PHI as a statement since it
count result in a constant assignment or copy operation. */
if (is_gimple_reg (dst))
stmt_count++;
record_temporary_equivalence (dst, src, stack);
}
return true;
}
/* Try to simplify each statement in E->dest, ultimately leading to
a simplification of the COND_EXPR at the end of E->dest.
Record unwind information for temporary equivalences onto STACK.
Use SIMPLIFY (a pointer to a callback function) to further simplify
statements using pass specific information.
We might consider marking just those statements which ultimately
feed the COND_EXPR. It's not clear if the overhead of bookkeeping
would be recovered by trying to simplify fewer statements.
If we are able to simplify a statement into the form
SSA_NAME = (SSA_NAME | gimple invariant), then we can record
a context sensitive equivalency which may help us simplify
later statements in E->dest. */
static tree
record_temporary_equivalences_from_stmts_at_dest (edge e,
VEC(tree, heap) **stack,
tree (*simplify) (tree))
{
block_stmt_iterator bsi;
tree stmt = NULL;
int max_stmt_count;
max_stmt_count = PARAM_VALUE (PARAM_MAX_JUMP_THREAD_DUPLICATION_STMTS);
/* Walk through each statement in the block recording equivalences
we discover. Note any equivalences we discover are context
sensitive (ie, are dependent on traversing E) and must be unwound
when we're finished processing E. */
for (bsi = bsi_start (e->dest); ! bsi_end_p (bsi); bsi_next (&bsi))
{
tree cached_lhs = NULL;
stmt = bsi_stmt (bsi);
/* Ignore empty statements and labels. */
if (IS_EMPTY_STMT (stmt) || TREE_CODE (stmt) == LABEL_EXPR)
continue;
/* Safely handle threading across loop backedges. Only allowing
a conditional at the target of the backedge is over conservative,
but still allows us to capture the majority of the cases where
we can thread across a loop backedge. */
if ((e->flags & EDGE_DFS_BACK) != 0
&& TREE_CODE (stmt) != COND_EXPR
&& TREE_CODE (stmt) != SWITCH_EXPR)
return NULL;
/* If the statement has volatile operands, then we assume we
can not thread through this block. This is overly
conservative in some ways. */
if (TREE_CODE (stmt) == ASM_EXPR && ASM_VOLATILE_P (stmt))
return NULL;
/* If duplicating this block is going to cause too much code
expansion, then do not thread through this block. */
stmt_count++;
if (stmt_count > max_stmt_count)
return NULL;
/* If this is not a MODIFY_EXPR which sets an SSA_NAME to a new
value, then do not try to simplify this statement as it will
not simplify in any way that is helpful for jump threading. */
if (TREE_CODE (stmt) != MODIFY_EXPR
|| TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
continue;
/* At this point we have a statement which assigns an RHS to an
SSA_VAR on the LHS. We want to try and simplify this statement
to expose more context sensitive equivalences which in turn may
allow us to simplify the condition at the end of the loop.
Handle simple copy operations as well as implied copies from
ASSERT_EXPRs. */
if (TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME)
cached_lhs = TREE_OPERAND (stmt, 1);
else if (TREE_CODE (TREE_OPERAND (stmt, 1)) == ASSERT_EXPR)
cached_lhs = TREE_OPERAND (TREE_OPERAND (stmt, 1), 0);
else
{
/* A statement that is not a trivial copy or ASSERT_EXPR.
We're going to temporarily copy propagate the operands
and see if that allows us to simplify this statement. */
tree *copy, pre_fold_expr;
ssa_op_iter iter;
use_operand_p use_p;
unsigned int num, i = 0;
num = NUM_SSA_OPERANDS (stmt, (SSA_OP_USE | SSA_OP_VUSE));
copy = XCNEWVEC (tree, num);
/* Make a copy of the uses & vuses into USES_COPY, then cprop into
the operands. */
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE | SSA_OP_VUSE)
{
tree tmp = NULL;
tree use = USE_FROM_PTR (use_p);
copy[i++] = use;
if (TREE_CODE (use) == SSA_NAME)
tmp = SSA_NAME_VALUE (use);
if (tmp && TREE_CODE (tmp) != VALUE_HANDLE)
SET_USE (use_p, tmp);
}
/* Try to fold/lookup the new expression. Inserting the
expression into the hash table is unlikely to help
Sadly, we have to handle conditional assignments specially
here, because fold expects all the operands of an expression
to be folded before the expression itself is folded, but we
can't just substitute the folded condition here. */
if (TREE_CODE (TREE_OPERAND (stmt, 1)) == COND_EXPR)
{
tree cond = COND_EXPR_COND (TREE_OPERAND (stmt, 1));
cond = fold (cond);
if (cond == boolean_true_node)
pre_fold_expr = COND_EXPR_THEN (TREE_OPERAND (stmt, 1));
else if (cond == boolean_false_node)
pre_fold_expr = COND_EXPR_ELSE (TREE_OPERAND (stmt, 1));
else
pre_fold_expr = TREE_OPERAND (stmt, 1);
}
else
pre_fold_expr = TREE_OPERAND (stmt, 1);
if (pre_fold_expr)
{
cached_lhs = fold (pre_fold_expr);
if (TREE_CODE (cached_lhs) != SSA_NAME
&& !is_gimple_min_invariant (cached_lhs))
cached_lhs = (*simplify) (stmt);
}
/* Restore the statement's original uses/defs. */
i = 0;
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE | SSA_OP_VUSE)
SET_USE (use_p, copy[i++]);
free (copy);
}
/* Record the context sensitive equivalence if we were able
to simplify this statement. */
if (cached_lhs
&& (TREE_CODE (cached_lhs) == SSA_NAME
|| is_gimple_min_invariant (cached_lhs)))
record_temporary_equivalence (TREE_OPERAND (stmt, 0),
cached_lhs,
stack);
}
return stmt;
}
/* Simplify the control statement at the end of the block E->dest.
To avoid allocating memory unnecessarily, a scratch COND_EXPR
is available to use/clobber in DUMMY_COND.
Use SIMPLIFY (a pointer to a callback function) to further simplify
a condition using pass specific information.
Return the simplified condition or NULL if simplification could
not be performed. */
static tree
simplify_control_stmt_condition (edge e,
tree stmt,
tree dummy_cond,
tree (*simplify) (tree),
bool handle_dominating_asserts)
{
tree cond, cached_lhs;
if (TREE_CODE (stmt) == COND_EXPR)
cond = COND_EXPR_COND (stmt);
else if (TREE_CODE (stmt) == GOTO_EXPR)
cond = GOTO_DESTINATION (stmt);
else
cond = SWITCH_COND (stmt);
/* For comparisons, we have to update both operands, then try
to simplify the comparison. */
if (COMPARISON_CLASS_P (cond))
{
tree op0, op1;
enum tree_code cond_code;
op0 = TREE_OPERAND (cond, 0);
op1 = TREE_OPERAND (cond, 1);
cond_code = TREE_CODE (cond);
/* Get the current value of both operands. */
if (TREE_CODE (op0) == SSA_NAME)
{
tree tmp = SSA_NAME_VALUE (op0);
if (tmp && TREE_CODE (tmp) != VALUE_HANDLE)
op0 = tmp;
}
if (TREE_CODE (op1) == SSA_NAME)
{
tree tmp = SSA_NAME_VALUE (op1);
if (tmp && TREE_CODE (tmp) != VALUE_HANDLE)
op1 = tmp;
}
if (handle_dominating_asserts)
{
/* Now see if the operand was consumed by an ASSERT_EXPR
which dominates E->src. If so, we want to replace the
operand with the LHS of the ASSERT_EXPR. */
if (TREE_CODE (op0) == SSA_NAME)
op0 = lhs_of_dominating_assert (op0, e->src, stmt);
if (TREE_CODE (op1) == SSA_NAME)
op1 = lhs_of_dominating_assert (op1, e->src, stmt);
}
/* We may need to canonicalize the comparison. For
example, op0 might be a constant while op1 is an
SSA_NAME. Failure to canonicalize will cause us to
miss threading opportunities. */
if (cond_code != SSA_NAME
&& tree_swap_operands_p (op0, op1, false))
{
tree tmp;
cond_code = swap_tree_comparison (TREE_CODE (cond));
tmp = op0;
op0 = op1;
op1 = tmp;
}
/* Stuff the operator and operands into our dummy conditional
expression. */
TREE_SET_CODE (COND_EXPR_COND (dummy_cond), cond_code);
TREE_OPERAND (COND_EXPR_COND (dummy_cond), 0) = op0;
TREE_OPERAND (COND_EXPR_COND (dummy_cond), 1) = op1;
/* We absolutely do not care about any type conversions
we only care about a zero/nonzero value. */
cached_lhs = fold (COND_EXPR_COND (dummy_cond));
while (TREE_CODE (cached_lhs) == NOP_EXPR
|| TREE_CODE (cached_lhs) == CONVERT_EXPR
|| TREE_CODE (cached_lhs) == NON_LVALUE_EXPR)
cached_lhs = TREE_OPERAND (cached_lhs, 0);
/* If we have not simplified the condition down to an invariant,
then use the pass specific callback to simplify the condition. */
if (! is_gimple_min_invariant (cached_lhs))
cached_lhs = (*simplify) (dummy_cond);
}
/* We can have conditionals which just test the state of a variable
rather than use a relational operator. These are simpler to handle. */
else if (TREE_CODE (cond) == SSA_NAME)
{
cached_lhs = cond;
/* Get the variable's current value from the equivalency chains. */
while (cached_lhs
&& TREE_CODE (cached_lhs) == SSA_NAME
&& SSA_NAME_VALUE (cached_lhs))
cached_lhs = SSA_NAME_VALUE (cached_lhs);
/* If we're dominated by a suitable ASSERT_EXPR, then
update CACHED_LHS appropriately. */
if (handle_dominating_asserts && TREE_CODE (cached_lhs) == SSA_NAME)
cached_lhs = lhs_of_dominating_assert (cached_lhs, e->src, stmt);
/* If we haven't simplified to an invariant yet, then use the
pass specific callback to try and simplify it further. */
if (cached_lhs && ! is_gimple_min_invariant (cached_lhs))
cached_lhs = (*simplify) (stmt);
}
else
cached_lhs = NULL;
return cached_lhs;
}
/* We are exiting E->src, see if E->dest ends with a conditional
jump which has a known value when reached via E.
Special care is necessary if E is a back edge in the CFG as we
may have already recorded equivalences for E->dest into our
various tables, including the result of the conditional at
the end of E->dest. Threading opportunities are severely
limited in that case to avoid short-circuiting the loop
incorrectly.
Note it is quite common for the first block inside a loop to
end with a conditional which is either always true or always
false when reached via the loop backedge. Thus we do not want
to blindly disable threading across a loop backedge. */
void
thread_across_edge (tree dummy_cond,
edge e,
bool handle_dominating_asserts,
VEC(tree, heap) **stack,
tree (*simplify) (tree))
{
tree stmt;
stmt_count = 0;
/* PHIs create temporary equivalences. */
if (!record_temporary_equivalences_from_phis (e, stack))
goto fail;
/* Now walk each statement recording any context sensitive
temporary equivalences we can detect. */
stmt = record_temporary_equivalences_from_stmts_at_dest (e, stack, simplify);
if (!stmt)
goto fail;
/* If we stopped at a COND_EXPR or SWITCH_EXPR, see if we know which arm
will be taken. */
if (TREE_CODE (stmt) == COND_EXPR
|| TREE_CODE (stmt) == GOTO_EXPR
|| TREE_CODE (stmt) == SWITCH_EXPR)
{
tree cond;
/* Extract and simplify the condition. */
cond = simplify_control_stmt_condition (e, stmt, dummy_cond, simplify, handle_dominating_asserts);
if (cond && is_gimple_min_invariant (cond))
{
edge taken_edge = find_taken_edge (e->dest, cond);
basic_block dest = (taken_edge ? taken_edge->dest : NULL);
if (dest == e->dest)
goto fail;
remove_temporary_equivalences (stack);
register_jump_thread (e, taken_edge);
}
}
fail:
remove_temporary_equivalences (stack);
}

View File

@ -2755,7 +2755,24 @@ find_conditional_asserts (basic_block bb)
/* Remove the COND_EXPR operands from the FOUND_IN_SUBGRAPH bitmap.
Otherwise, when we finish traversing each of the sub-graphs, we
won't know whether the variables were found in the sub-graphs or
if they had been found in a block upstream from BB. */
if they had been found in a block upstream from BB.
This is actually a bad idea is some cases, particularly jump
threading. Consider a CFG like the following:
0
/|
1 |
\|
2
/ \
3 4
Assume that one or more operands in the conditional at the
end of block 0 are used in a conditional in block 2, but not
anywhere in block 1. In this case we will not insert any
assert statements in block 1, which may cause us to miss
opportunities to optimize, particularly for jump threading. */
FOR_EACH_SSA_TREE_OPERAND (op, last, iter, SSA_OP_USE)
RESET_BIT (found_in_subgraph, SSA_NAME_VERSION (op));
@ -4202,6 +4219,157 @@ simplify_stmt_using_ranges (tree stmt)
}
}
/* Stack of dest,src equivalency pairs that need to be restored after
each attempt to thread a block's incoming edge to an outgoing edge.
A NULL entry is used to mark the end of pairs which need to be
restored. */
static VEC(tree,heap) *stack;
/* A trivial wrapper so that we can present the generic jump
threading code with a simple API for simplifying statements. */
static tree
simplify_stmt_for_jump_threading (tree stmt)
{
/* We only use VRP information to simplify conditionals. This is
overly conservative, but it's unclear if doing more would be
worth the compile time cost. */
if (TREE_CODE (stmt) != COND_EXPR)
return NULL;
return vrp_evaluate_conditional (COND_EXPR_COND (stmt), true);
}
/* Blocks which have more than one predecessor and more than
one successor present jump threading opportunities. ie,
when the block is reached from a specific predecessor, we
may be able to determine which of the outgoing edges will
be traversed. When this optimization applies, we are able
to avoid conditionals at runtime and we may expose secondary
optimization opportunities.
This routine is effectively a driver for the generic jump
threading code. It basically just presents the generic code
with edges that may be suitable for jump threading.
Unlike DOM, we do not iterate VRP if jump threading was successful.
While iterating may expose new opportunities for VRP, it is expected
those opportunities would be very limited and the compile time cost
to expose those opportunities would be significant.
As jump threading opportunities are discovered, they are registered
for later realization. */
static void
identify_jump_threads (void)
{
basic_block bb;
tree dummy;
/* Ugh. When substituting values earlier in this pass we can
wipe the dominance information. So rebuild the dominator
information as we need it within the jump threading code. */
calculate_dominance_info (CDI_DOMINATORS);
/* We do not allow VRP information to be used for jump threading
across a back edge in the CFG. Otherwise it becomes too
difficult to avoid eliminating loop exit tests. Of course
EDGE_DFS_BACK is not accurate at this time so we have to
recompute it. */
mark_dfs_back_edges ();
/* Allocate our unwinder stack to unwind any temporary equivalences
that might be recorded. */
stack = VEC_alloc (tree, heap, 20);
/* To avoid lots of silly node creation, we create a single
conditional and just modify it in-place when attempting to
thread jumps. */
dummy = build2 (EQ_EXPR, boolean_type_node, NULL, NULL);
dummy = build3 (COND_EXPR, void_type_node, dummy, NULL, NULL);
/* Walk through all the blocks finding those which present a
potential jump threading opportunity. We could set this up
as a dominator walker and record data during the walk, but
I doubt it's worth the effort for the classes of jump
threading opportunities we are trying to identify at this
point in compilation. */
FOR_EACH_BB (bb)
{
tree last, cond;
/* If the generic jump threading code does not find this block
interesting, then there is nothing to do. */
if (! potentially_threadable_block (bb))
continue;
/* We only care about blocks ending in a COND_EXPR. While there
may be some value in handling SWITCH_EXPR here, I doubt it's
terribly important. */
last = bsi_stmt (bsi_last (bb));
if (TREE_CODE (last) != COND_EXPR)
continue;
/* We're basically looking for any kind of conditional with
integral type arguments. */
cond = COND_EXPR_COND (last);
if ((TREE_CODE (cond) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (cond)))
|| (COMPARISON_CLASS_P (cond)
&& TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 0)))
&& (TREE_CODE (TREE_OPERAND (cond, 1)) == SSA_NAME
|| is_gimple_min_invariant (TREE_OPERAND (cond, 1)))
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 1)))))
{
edge_iterator ei;
edge e;
/* We've got a block with multiple predecessors and multiple
successors which also ends in a suitable conditional. For
each predecessor, see if we can thread it to a specific
successor. */
FOR_EACH_EDGE (e, ei, bb->preds)
{
/* Do not thread across back edges or abnormal edges
in the CFG. */
if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
continue;
thread_across_edge (dummy, e, true,
&stack,
simplify_stmt_for_jump_threading);
}
}
}
/* We do not actually update the CFG or SSA graphs at this point as
ASSERT_EXPRs are still in the IL and cfg cleanup code does not yet
handle ASSERT_EXPRs gracefully. */
}
/* We identified all the jump threading opportunities earlier, but could
not transform the CFG at that time. This routine transforms the
CFG and arranges for the dominator tree to be rebuilt if necessary.
Note the SSA graph update will occur during the normal TODO
processing by the pass manager. */
static void
finalize_jump_threads (void)
{
bool cfg_altered = false;
cfg_altered = thread_through_all_blocks ();
/* If we threaded jumps, then we need to recompute the dominance
information, to safely do that we must clean up the CFG first. */
if (cfg_altered)
{
free_dominance_info (CDI_DOMINATORS);
cleanup_tree_cfg ();
calculate_dominance_info (CDI_DOMINATORS);
}
VEC_free (tree, heap, stack);
}
/* Traverse all the blocks folding conditionals with known ranges. */
@ -4246,6 +4414,10 @@ vrp_finalize (void)
substitute_and_fold (single_val_range, true);
/* We must identify jump threading opportunities before we release
the datastructures built by VRP. */
identify_jump_threads ();
/* Free allocated memory. */
for (i = 0; i < num_ssa_names; i++)
if (vr_value[i])
@ -4323,7 +4495,12 @@ execute_vrp (void)
current_loops = NULL;
}
/* ASSERT_EXPRs must be removed before finalizing jump threads
as finalizing jump threads calls the CFG cleanup code which
does not properly handle ASSERT_EXPRs. */
remove_range_assertions ();
finalize_jump_threads ();
}
static bool