[tree-ssa] Support threading through SWITCH_EXPRs
law@redhat.com
law@redhat.com
Wed Jan 21 08:44:00 GMT 2004
[ I ended up saying up later than I originally planned :( ]
The discussion of gcc/1532 happened to catch my eye and though the
primary issue the PR raises it out of the domain of the tree-ssa
optimizers, I did notice something the tree-ssa optimizers should have
handled better.
Specifically, there are 3 paths to the switch statement, each feeding
the switch condition a different constant. The tree-ssa optimizers
correctly found those constants and put them into the PHI node at the
start of the block with the SWITCH_EXPR. However, I hadn't gotten
around to supporting SWITCH_EXPR in the threading code. So we didn't
make use of any of those constants. Opps.
This patch fixing that problem (quite trivially I might add).
FWIW, the testcase looks like this:
inline int check(int i,int j) {
if (i==j) return 0;
else if (i>j) return 1;
else return 2;
}
int foo(int i,int j) {
switch (check(i,j)) {
case 0: return i+j;
case 1: return i;
case 2: return j;
}
}
A little analysis quickly shows that the the if statements in "check"
completely determine which case is taken in the switch statement within
"foo".
With this patch the tree-ssa optimizers are able to completely eliminate
the switch statement before handing the code off to the tree->rtl
expanders. Whee.
Bootstrapped and regression tested on i686-pc-linux-gnu.
* tree-ssa-dom.c (thread_across_edge): Handle SWITCH_EXPRs in the
target block in addition to COND_EXPRs.
Index: tree-ssa-dom.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dom.c,v
retrieving revision 1.1.2.116
diff -c -p -r1.1.2.116 tree-ssa-dom.c
*** tree-ssa-dom.c 21 Jan 2004 07:06:11 -0000 1.1.2.116
--- tree-ssa-dom.c 21 Jan 2004 08:26:43 -0000
*************** thread_across_edge (struct dom_walk_data
*** 666,672 ****
/* If this is not a MODIFY_EXPR which sets an SSA_NAME to a new
value, then stop our search here. Ideally when we stop a
! search we stop on a COND_EXPR. */
if (TREE_CODE (stmt) != MODIFY_EXPR
|| TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
break;
--- 666,672 ----
/* If this is not a MODIFY_EXPR which sets an SSA_NAME to a new
value, then stop our search here. Ideally when we stop a
! search we stop on a COND_EXPR or SWITCH_EXPR. */
if (TREE_CODE (stmt) != MODIFY_EXPR
|| TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
break;
*************** thread_across_edge (struct dom_walk_data
*** 783,793 ****
VARRAY_PUSH_TREE (bd->const_and_copies, prev_value);
}
! /* If we stopped at a COND_EXPR, then see if we know which arm will
! be taken. */
! if (stmt && TREE_CODE (stmt) == COND_EXPR)
{
! tree cached_lhs;
edge e1;
/* Do not forward a back edge in the CFG. This avoids short circuiting
--- 783,794 ----
VARRAY_PUSH_TREE (bd->const_and_copies, prev_value);
}
! /* If we stopped at a COND_EXPR or SWITCH_EXPR, then see if we know which
! arm will be taken. */
! if (stmt
! && (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR))
{
! tree cond, cached_lhs;
edge e1;
/* Do not forward a back edge in the CFG. This avoids short circuiting
*************** thread_across_edge (struct dom_walk_data
*** 811,824 ****
/* Now temporarily cprop the operands and try to find the resulting
expression in the hash tables. */
! if (TREE_CODE_CLASS (TREE_CODE (COND_EXPR_COND (stmt))) == '<')
{
tree dummy_cond, op0, op1;
enum tree_code cond_code;
! op0 = TREE_OPERAND (COND_EXPR_COND (stmt), 0);
! op1 = TREE_OPERAND (COND_EXPR_COND (stmt), 1);
! cond_code = TREE_CODE (COND_EXPR_COND (stmt));
/* Get the current value of both operands. */
if (TREE_CODE (op0) == SSA_NAME)
--- 812,830 ----
/* Now temporarily cprop the operands and try to find the resulting
expression in the hash tables. */
! if (TREE_CODE (stmt) == COND_EXPR)
! cond = COND_EXPR_COND (stmt);
! else
! cond = SWITCH_COND (stmt);
!
! if (TREE_CODE_CLASS (TREE_CODE (cond)) == '<')
{
tree dummy_cond, 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)
*************** thread_across_edge (struct dom_walk_data
*** 869,877 ****
/* 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_EXPR_COND (stmt)) == SSA_NAME)
{
! cached_lhs = COND_EXPR_COND (stmt);
cached_lhs = get_value_for (cached_lhs, const_and_copies);
if (cached_lhs && ! is_gimple_min_invariant (cached_lhs))
cached_lhs = 0;
--- 875,883 ----
/* 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;
cached_lhs = get_value_for (cached_lhs, const_and_copies);
if (cached_lhs && ! is_gimple_min_invariant (cached_lhs))
cached_lhs = 0;
More information about the Gcc-patches
mailing list