summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramker <amker@138bc75d-0d04-0410-961f-82ee72b054a4>2016-08-02 10:09:33 +0000
committeramker <amker@138bc75d-0d04-0410-961f-82ee72b054a4>2016-08-02 10:09:33 +0000
commit03eed863e98172e590a96b19095c0d44f8d336df (patch)
treefd8b692140e067fa720442480eb581a6512dc153
parent8020abd0dfe3b93bb45207e4ea74a3129ec54a5c (diff)
downloadgcc-03eed863e98172e590a96b19095c0d44f8d336df.tar.gz
PR tree-optimization/34114
* fold-const.c (multiple_of_p): Improve MULT_EXPR, PLUS_EXPR, PLUS_EXPR case. Handle SSA_NAME case. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@238982 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/fold-const.c67
2 files changed, 66 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f2c81b077fb..5687ad51224 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2016-08-02 Bin Cheng <bin.cheng@arm.com>
+
+ PR tree-optimization/34114
+ * fold-const.c (multiple_of_p): Improve MULT_EXPR, PLUS_EXPR,
+ PLUS_EXPR case. Handle SSA_NAME case.
+
2016-08-02 Tamar Christina <tamar.christina@arm.com>
* config/aarch64/aarch64-simd-builtins.def
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index c5d9a79ed28..c6c2bff5011 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -12538,6 +12538,9 @@ fold_build_call_array_initializer_loc (location_t loc, tree type, tree fn,
int
multiple_of_p (tree type, const_tree top, const_tree bottom)
{
+ gimple *stmt;
+ tree t1, op1, op2;
+
if (operand_equal_p (top, bottom, 0))
return 1;
@@ -12554,19 +12557,31 @@ multiple_of_p (tree type, const_tree top, const_tree bottom)
/* FALLTHRU */
case MULT_EXPR:
- return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
- || multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
+ return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom)
+ || multiple_of_p (type, TREE_OPERAND (top, 0), bottom));
- case PLUS_EXPR:
case MINUS_EXPR:
- return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
- && multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
+ /* It is impossible to prove if op0 - op1 is multiple of bottom
+ precisely, so be conservative here checking if both op0 and op1
+ are multiple of bottom. Note we check the second operand first
+ since it's usually simpler. */
+ return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom)
+ && multiple_of_p (type, TREE_OPERAND (top, 0), bottom));
+
+ case PLUS_EXPR:
+ /* The same as MINUS_EXPR, but handle cases like op0 + 0xfffffffd
+ as op0 - 3 if the expression has unsigned type. For example,
+ (X / 3) + 0xfffffffd is multiple of 3, but 0xfffffffd is not. */
+ op1 = TREE_OPERAND (top, 1);
+ if (TYPE_UNSIGNED (type)
+ && TREE_CODE (op1) == INTEGER_CST && tree_int_cst_sign_bit (op1))
+ op1 = fold_build1 (NEGATE_EXPR, type, op1);
+ return (multiple_of_p (type, op1, bottom)
+ && multiple_of_p (type, TREE_OPERAND (top, 0), bottom));
case LSHIFT_EXPR:
if (TREE_CODE (TREE_OPERAND (top, 1)) == INTEGER_CST)
{
- tree op1, t1;
-
op1 = TREE_OPERAND (top, 1);
/* const_binop may not detect overflow correctly,
so check for it explicitly here. */
@@ -12606,6 +12621,44 @@ multiple_of_p (tree type, const_tree top, const_tree bottom)
return wi::multiple_of_p (wi::to_widest (top), wi::to_widest (bottom),
SIGNED);
+ case SSA_NAME:
+ if (TREE_CODE (bottom) == INTEGER_CST
+ && (stmt = SSA_NAME_DEF_STMT (top)) != NULL
+ && gimple_code (stmt) == GIMPLE_ASSIGN)
+ {
+ enum tree_code code = gimple_assign_rhs_code (stmt);
+
+ /* Check for special cases to see if top is defined as multiple
+ of bottom:
+
+ top = (X & ~(bottom - 1) ; bottom is power of 2
+
+ or
+
+ Y = X % bottom
+ top = X - Y. */
+ if (code == BIT_AND_EXPR
+ && (op2 = gimple_assign_rhs2 (stmt)) != NULL_TREE
+ && TREE_CODE (op2) == INTEGER_CST
+ && integer_pow2p (bottom)
+ && wi::multiple_of_p (wi::to_widest (op2),
+ wi::to_widest (bottom), UNSIGNED))
+ return 1;
+
+ op1 = gimple_assign_rhs1 (stmt);
+ if (code == MINUS_EXPR
+ && (op2 = gimple_assign_rhs2 (stmt)) != NULL_TREE
+ && TREE_CODE (op2) == SSA_NAME
+ && (stmt = SSA_NAME_DEF_STMT (op2)) != NULL
+ && gimple_code (stmt) == GIMPLE_ASSIGN
+ && (code = gimple_assign_rhs_code (stmt)) == TRUNC_MOD_EXPR
+ && operand_equal_p (op1, gimple_assign_rhs1 (stmt), 0)
+ && operand_equal_p (bottom, gimple_assign_rhs2 (stmt), 0))
+ return 1;
+ }
+
+ /* .. fall through ... */
+
default:
return 0;
}