Commit b114bfb4 by Zhenqiang Chen Committed by Jeff Law

tree-ssa-reassoc.c: Include rtl.h and tm_p.h.

	* tree-ssa-reassoc.c: Include rtl.h and tm_p.h.
	(optimize_range_tests_1): New function,
	extracted from optimize_range_tests.
	(optimize_range_tests_xor): Similarly.
	(optimize_range_tests_diff): New function.
	(optimize_range_tests): Use optimize_range_tests_1.

	* gcc.dg/tree-ssa/reassoc-32.c: New test case.
	* gcc.dg/tree-ssa/reassoc-33.c: New test case.
	* gcc.dg/tree-ssa/reassoc-34.c: New test case.
	* gcc.dg/tree-ssa/reassoc-35.c: New test case.
	* gcc.dg/tree-ssa/reassoc-36.c: New test case.

From-SVN: r203627
parent 69b8f2f9
2013-10-15 Zhenqiang Chen <zhenqiang.chen@arm.com>
* tree-ssa-reassoc.c: Include rtl.h and tm_p.h.
(optimize_range_tests_1): New function,
extracted from optimize_range_tests.
(optimize_range_tests_xor): Similarly.
(optimize_range_tests_diff): New function.
(optimize_range_tests): Use optimize_range_tests_1.
2013-10-15 Cong Hou <congh@google.com> 2013-10-15 Cong Hou <congh@google.com>
* tree-vect-loop.c (vect_is_simple_reduction_1): Relax the * tree-vect-loop.c (vect_is_simple_reduction_1): Relax the
......
2013-10-15 Zhenqiang Chen <zhenqiang.chen@arm.com>
* gcc.dg/tree-ssa/reassoc-32.c: New test case.
* gcc.dg/tree-ssa/reassoc-33.c: New test case.
* gcc.dg/tree-ssa/reassoc-34.c: New test case.
* gcc.dg/tree-ssa/reassoc-35.c: New test case.
* gcc.dg/tree-ssa/reassoc-36.c: New test case.
2013-10-15 Cong Hou <congh@google.com> 2013-10-15 Cong Hou <congh@google.com>
* gcc.dg/vect/vect-reduc-pattern-3.c: New test. * gcc.dg/vect/vect-reduc-pattern-3.c: New test.
......
/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
int test (int a, int b, int c)
{
if ( a == 10 || a == 12 || a == 26)
return b;
else
return c;
}
int main ()
{
if (test (10, 20, 30) != 20)
__builtin_abort ();
if (test (12, 20, 30) != 20)
__builtin_abort ();
if (test (26, 20, 30) != 20)
__builtin_abort ();
if (test (30, 20, 30) != 30)
__builtin_abort ();
return 0;
}
/* { dg-final { scan-tree-dump-times "Optimizing range tests .* 26" 1 "reassoc1"} }*/
/* { dg-final { cleanup-tree-dump "reassoc1" } } */
/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
int test (int a, int b, int c)
{
if (a == 43 || a == 75 || a == 44 || a == 78
|| a == 77 || a == 46 || a == 76 || a == 45)
return b;
else
return c;
}
int
main ()
{
volatile int n43, n47, n75, n79;
n43 = 43; n47 = n43 + 4; n75 = 75; n79 = n75 + 4;
int i;
for (i = -10; i <= 100; i++)
if (test (i, 2, 3) != 3 - ((i >= n43 && i < n47) || (i >= n75 && i < n79)))
__builtin_abort ();
return 0;
}
/* { dg-final { scan-tree-dump-times "Optimizing range tests" 3 "reassoc1"} }*/
/* { dg-final { cleanup-tree-dump "reassoc1" } } */
/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
int test (int a, int b, int c)
{
if (a == 10 || a == 12)
return b;
else
return c;
}
int main ()
{
if (test (10, 20, 30) != 20)
__builtin_abort ();
if (test (12, 20, 30) != 20)
__builtin_abort ();
if (test (26, 20, 30) != 30)
__builtin_abort ();
return 0;
}
/* { dg-final { scan-tree-dump-times "Optimizing range tests" 1 "reassoc1"} }*/
/* { dg-final { cleanup-tree-dump "reassoc1" } } */
/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
int test (unsigned int a, int b, int c)
{
if ((a - 43) <= 3 || (a - 75) <= 3)
return b;
else
return c;
}
int
main ()
{
volatile int n43, n47, n75, n79;
n43 = 43; n47 = n43 + 4; n75 = 75; n79 = n75 + 4;
int i;
for (i = -10; i <= 100; i++)
if (test (i, 2, 3) != 3 - ((i >= n43 && i < n47) || (i >= n75 && i < n79)))
__builtin_abort ();
return 0;
}
/* { dg-final { scan-tree-dump-times "Optimizing range tests" 1 "reassoc1"} }*/
/* { dg-final { cleanup-tree-dump "reassoc1" } } */
/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
int test (int a, int b, int c)
{
if (a != 10 && a != 12)
return b;
else
return c;
}
int main ()
{
if (test (10, 20, 30) != 30)
__builtin_abort ();
if (test (12, 20, 30) != 30)
__builtin_abort ();
if (test (26, 20, 30) != 20)
__builtin_abort ();
return 0;
}
/* { dg-final { scan-tree-dump-times "Optimizing range tests" 1 "reassoc1"} }*/
/* { dg-final { cleanup-tree-dump "reassoc1" } } */
...@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3. If not see ...@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h" #include "coretypes.h"
#include "hash-table.h" #include "hash-table.h"
#include "tm.h" #include "tm.h"
#include "rtl.h"
#include "tm_p.h"
#include "tree.h" #include "tree.h"
#include "basic-block.h" #include "basic-block.h"
#include "gimple-pretty-print.h" #include "gimple-pretty-print.h"
...@@ -2131,6 +2133,152 @@ update_range_test (struct range_entry *range, struct range_entry *otherrange, ...@@ -2131,6 +2133,152 @@ update_range_test (struct range_entry *range, struct range_entry *otherrange,
return true; return true;
} }
/* Optimize X == CST1 || X == CST2
if popcount (CST1 ^ CST2) == 1 into
(X & ~(CST1 ^ CST2)) == (CST1 & ~(CST1 ^ CST2)).
Similarly for ranges. E.g.
X != 2 && X != 3 && X != 10 && X != 11
will be transformed by the previous optimization into
!((X - 2U) <= 1U || (X - 10U) <= 1U)
and this loop can transform that into
!(((X & ~8) - 2U) <= 1U). */
static bool
optimize_range_tests_xor (enum tree_code opcode, tree type,
tree lowi, tree lowj, tree highi, tree highj,
vec<operand_entry_t> *ops,
struct range_entry *rangei,
struct range_entry *rangej)
{
tree lowxor, highxor, tem, exp;
/* Check highi ^ lowi == highj ^ lowj and
popcount (highi ^ lowi) == 1. */
lowxor = fold_binary (BIT_XOR_EXPR, type, lowi, lowj);
if (lowxor == NULL_TREE || TREE_CODE (lowxor) != INTEGER_CST)
return false;
if (tree_log2 (lowxor) < 0)
return false;
highxor = fold_binary (BIT_XOR_EXPR, type, highi, highj);
if (!tree_int_cst_equal (lowxor, highxor))
return false;
tem = fold_build1 (BIT_NOT_EXPR, type, lowxor);
exp = fold_build2 (BIT_AND_EXPR, type, rangei->exp, tem);
lowj = fold_build2 (BIT_AND_EXPR, type, lowi, tem);
highj = fold_build2 (BIT_AND_EXPR, type, highi, tem);
if (update_range_test (rangei, rangej, 1, opcode, ops, exp,
rangei->in_p, lowj, highj,
rangei->strict_overflow_p
|| rangej->strict_overflow_p))
return true;
return false;
}
/* Optimize X == CST1 || X == CST2
if popcount (CST2 - CST1) == 1 into
((X - CST1) & ~(CST2 - CST1)) == 0.
Similarly for ranges. E.g.
X == 43 || X == 76 || X == 44 || X == 78 || X == 77 || X == 46
|| X == 75 || X == 45
will be transformed by the previous optimization into
(X - 43U) <= 3U || (X - 75U) <= 3U
and this loop can transform that into
((X - 43U) & ~(75U - 43U)) <= 3U. */
static bool
optimize_range_tests_diff (enum tree_code opcode, tree type,
tree lowi, tree lowj, tree highi, tree highj,
vec<operand_entry_t> *ops,
struct range_entry *rangei,
struct range_entry *rangej)
{
tree tem1, tem2, mask;
/* Check highi - lowi == highj - lowj. */
tem1 = fold_binary (MINUS_EXPR, type, highi, lowi);
if (tem1 == NULL_TREE || TREE_CODE (tem1) != INTEGER_CST)
return false;
tem2 = fold_binary (MINUS_EXPR, type, highj, lowj);
if (!tree_int_cst_equal (tem1, tem2))
return false;
/* Check popcount (lowj - lowi) == 1. */
tem1 = fold_binary (MINUS_EXPR, type, lowj, lowi);
if (tem1 == NULL_TREE || TREE_CODE (tem1) != INTEGER_CST)
return false;
if (tree_log2 (tem1) < 0)
return false;
mask = fold_build1 (BIT_NOT_EXPR, type, tem1);
tem1 = fold_binary (MINUS_EXPR, type, rangei->exp, lowi);
tem1 = fold_build2 (BIT_AND_EXPR, type, tem1, mask);
lowj = build_int_cst (type, 0);
if (update_range_test (rangei, rangej, 1, opcode, ops, tem1,
rangei->in_p, lowj, tem2,
rangei->strict_overflow_p
|| rangej->strict_overflow_p))
return true;
return false;
}
/* It does some common checks for function optimize_range_tests_xor and
optimize_range_tests_diff.
If OPTIMIZE_XOR is TRUE, it calls optimize_range_tests_xor.
Else it calls optimize_range_tests_diff. */
static bool
optimize_range_tests_1 (enum tree_code opcode, int first, int length,
bool optimize_xor, vec<operand_entry_t> *ops,
struct range_entry *ranges)
{
int i, j;
bool any_changes = false;
for (i = first; i < length; i++)
{
tree lowi, highi, lowj, highj, type, tem;
if (ranges[i].exp == NULL_TREE || ranges[i].in_p)
continue;
type = TREE_TYPE (ranges[i].exp);
if (!INTEGRAL_TYPE_P (type))
continue;
lowi = ranges[i].low;
if (lowi == NULL_TREE)
lowi = TYPE_MIN_VALUE (type);
highi = ranges[i].high;
if (highi == NULL_TREE)
continue;
for (j = i + 1; j < length && j < i + 64; j++)
{
bool changes;
if (ranges[i].exp != ranges[j].exp || ranges[j].in_p)
continue;
lowj = ranges[j].low;
if (lowj == NULL_TREE)
continue;
highj = ranges[j].high;
if (highj == NULL_TREE)
highj = TYPE_MAX_VALUE (type);
/* Check lowj > highi. */
tem = fold_binary (GT_EXPR, boolean_type_node,
lowj, highi);
if (tem == NULL_TREE || !integer_onep (tem))
continue;
if (optimize_xor)
changes = optimize_range_tests_xor (opcode, type, lowi, lowj,
highi, highj, ops,
ranges + i, ranges + j);
else
changes = optimize_range_tests_diff (opcode, type, lowi, lowj,
highi, highj, ops,
ranges + i, ranges + j);
if (changes)
{
any_changes = true;
break;
}
}
}
return any_changes;
}
/* Optimize range tests, similarly how fold_range_test optimizes /* Optimize range tests, similarly how fold_range_test optimizes
it on trees. The tree code for the binary it on trees. The tree code for the binary
operation between all the operands is OPCODE. operation between all the operands is OPCODE.
...@@ -2208,76 +2356,12 @@ optimize_range_tests (enum tree_code opcode, ...@@ -2208,76 +2356,12 @@ optimize_range_tests (enum tree_code opcode,
++update_fail_count; ++update_fail_count;
} }
/* Optimize X == CST1 || X == CST2 any_changes |= optimize_range_tests_1 (opcode, first, length, true,
if popcount (CST1 ^ CST2) == 1 into ops, ranges);
(X & ~(CST1 ^ CST2)) == (CST1 & ~(CST1 ^ CST2)).
Similarly for ranges. E.g.
X != 2 && X != 3 && X != 10 && X != 11
will be transformed by the above loop into
(X - 2U) <= 1U && (X - 10U) <= 1U
and this loop can transform that into
((X & ~8) - 2U) <= 1U. */
for (i = first; i < length; i++)
{
tree lowi, highi, lowj, highj, type, lowxor, highxor, tem, exp;
if (ranges[i].exp == NULL_TREE || ranges[i].in_p) if (BRANCH_COST (optimize_function_for_speed_p (cfun), false) >= 2)
continue; any_changes |= optimize_range_tests_1 (opcode, first, length, false,
type = TREE_TYPE (ranges[i].exp); ops, ranges);
if (!INTEGRAL_TYPE_P (type))
continue;
lowi = ranges[i].low;
if (lowi == NULL_TREE)
lowi = TYPE_MIN_VALUE (type);
highi = ranges[i].high;
if (highi == NULL_TREE)
continue;
for (j = i + 1; j < length && j < i + 64; j++)
{
if (ranges[j].exp == NULL_TREE)
continue;
if (ranges[i].exp != ranges[j].exp)
break;
if (ranges[j].in_p)
continue;
lowj = ranges[j].low;
if (lowj == NULL_TREE)
continue;
highj = ranges[j].high;
if (highj == NULL_TREE)
highj = TYPE_MAX_VALUE (type);
tem = fold_binary (GT_EXPR, boolean_type_node,
lowj, highi);
if (tem == NULL_TREE || !integer_onep (tem))
continue;
lowxor = fold_binary (BIT_XOR_EXPR, type, lowi, lowj);
if (lowxor == NULL_TREE || TREE_CODE (lowxor) != INTEGER_CST)
continue;
gcc_checking_assert (!integer_zerop (lowxor));
tem = fold_binary (MINUS_EXPR, type, lowxor,
build_int_cst (type, 1));
if (tem == NULL_TREE)
continue;
tem = fold_binary (BIT_AND_EXPR, type, lowxor, tem);
if (tem == NULL_TREE || !integer_zerop (tem))
continue;
highxor = fold_binary (BIT_XOR_EXPR, type, highi, highj);
if (!tree_int_cst_equal (lowxor, highxor))
continue;
tem = fold_build1 (BIT_NOT_EXPR, type, lowxor);
exp = fold_build2 (BIT_AND_EXPR, type, ranges[i].exp, tem);
lowj = fold_build2 (BIT_AND_EXPR, type, lowi, tem);
highj = fold_build2 (BIT_AND_EXPR, type, highi, tem);
if (update_range_test (ranges + i, ranges + j, 1, opcode, ops, exp,
ranges[i].in_p, lowj, highj,
ranges[i].strict_overflow_p
|| ranges[j].strict_overflow_p))
{
any_changes = true;
break;
}
}
}
if (any_changes && opcode != ERROR_MARK) if (any_changes && opcode != ERROR_MARK)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment