Commit 418d1b87 by Marc Glisse Committed by Marc Glisse

fold-const.c (fold_negate_expr): Handle vectors.

2013-05-14  Marc Glisse  <marc.glisse@inria.fr>

gcc/
	* fold-const.c (fold_negate_expr): Handle vectors.
	(fold_truth_not_expr): Make it static.
	(fold_invert_truthvalue): New static function.
	(invert_truthvalue_loc): Handle vectors. Do not call
	fold_truth_not_expr directly.
	(fold_unary_loc) <BIT_NOT_EXPR>: Handle comparisons.
	<TRUTH_NOT_EXPR>: Do not cast to boolean.
	(fold_comparison): Handle vector constants.
	(fold_binary_loc) <TRUTH_XOR_EXPR>: Remove redundant code.
	(fold_ternary_loc) <VEC_COND_EXPR>: Adapt more COND_EXPR optimizations.
	* tree.h (fold_truth_not_expr): Remove declaration.

gcc/testsuite/
	* g++.dg/ext/vector22.C: New testcase.
	* gcc.dg/binop-xor3.c: Remove xfail.

From-SVN: r198893
parent a5244b2e
2013-05-14 Marc Glisse <marc.glisse@inria.fr>
* fold-const.c (fold_negate_expr): Handle vectors.
(fold_truth_not_expr): Make it static.
(fold_invert_truthvalue): New static function.
(invert_truthvalue_loc): Handle vectors. Do not call
fold_truth_not_expr directly.
(fold_unary_loc) <BIT_NOT_EXPR>: Handle comparisons.
<TRUTH_NOT_EXPR>: Do not cast to boolean.
(fold_comparison): Handle vector constants.
(fold_binary_loc) <TRUTH_XOR_EXPR>: Remove redundant code.
(fold_ternary_loc) <VEC_COND_EXPR>: Adapt more COND_EXPR optimizations.
* tree.h (fold_truth_not_expr): Remove declaration.
2013-05-14 James Greenhalgh <james.greenhalgh@arm.com> 2013-05-14 James Greenhalgh <james.greenhalgh@arm.com>
* config/aarch64/aarch64-simd.md * config/aarch64/aarch64-simd.md
......
...@@ -526,7 +526,7 @@ fold_negate_expr (location_t loc, tree t) ...@@ -526,7 +526,7 @@ fold_negate_expr (location_t loc, tree t)
case BIT_NOT_EXPR: case BIT_NOT_EXPR:
if (INTEGRAL_TYPE_P (type)) if (INTEGRAL_TYPE_P (type))
return fold_build2_loc (loc, PLUS_EXPR, type, TREE_OPERAND (t, 0), return fold_build2_loc (loc, PLUS_EXPR, type, TREE_OPERAND (t, 0),
build_int_cst (type, 1)); build_one_cst (type));
break; break;
case INTEGER_CST: case INTEGER_CST:
...@@ -3085,7 +3085,7 @@ omit_two_operands_loc (location_t loc, tree type, tree result, ...@@ -3085,7 +3085,7 @@ omit_two_operands_loc (location_t loc, tree type, tree result,
FIXME: one would think we would fold the result, but it causes FIXME: one would think we would fold the result, but it causes
problems with the dominator optimizer. */ problems with the dominator optimizer. */
tree static tree
fold_truth_not_expr (location_t loc, tree arg) fold_truth_not_expr (location_t loc, tree arg)
{ {
tree type = TREE_TYPE (arg); tree type = TREE_TYPE (arg);
...@@ -3220,26 +3220,36 @@ fold_truth_not_expr (location_t loc, tree arg) ...@@ -3220,26 +3220,36 @@ fold_truth_not_expr (location_t loc, tree arg)
} }
} }
/* Fold the truth-negation of ARG. This never alters ARG itself. We
assume that ARG is an operation that returns a truth value (0 or 1
for scalars, 0 or -1 for vectors). Return the folded expression if
folding is successful. Otherwise, return NULL_TREE. */
static tree
fold_invert_truthvalue (location_t loc, tree arg)
{
tree type = TREE_TYPE (arg);
return fold_unary_loc (loc, VECTOR_TYPE_P (type)
? BIT_NOT_EXPR
: TRUTH_NOT_EXPR,
type, arg);
}
/* Return a simplified tree node for the truth-negation of ARG. This /* Return a simplified tree node for the truth-negation of ARG. This
never alters ARG itself. We assume that ARG is an operation that never alters ARG itself. We assume that ARG is an operation that
returns a truth value (0 or 1). returns a truth value (0 or 1 for scalars, 0 or -1 for vectors). */
FIXME: one would think we would fold the result, but it causes
problems with the dominator optimizer. */
tree tree
invert_truthvalue_loc (location_t loc, tree arg) invert_truthvalue_loc (location_t loc, tree arg)
{ {
tree tem;
if (TREE_CODE (arg) == ERROR_MARK) if (TREE_CODE (arg) == ERROR_MARK)
return arg; return arg;
tem = fold_truth_not_expr (loc, arg); tree type = TREE_TYPE (arg);
if (!tem) return fold_build1_loc (loc, VECTOR_TYPE_P (type)
tem = build1_loc (loc, TRUTH_NOT_EXPR, TREE_TYPE (arg), arg); ? BIT_NOT_EXPR
: TRUTH_NOT_EXPR,
return tem; type, arg);
} }
/* Given a bit-wise operation CODE applied to ARG0 and ARG1, see if both /* Given a bit-wise operation CODE applied to ARG0 and ARG1, see if both
...@@ -8281,14 +8291,22 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) ...@@ -8281,14 +8291,22 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
if (i == count) if (i == count)
return build_vector (type, elements); return build_vector (type, elements);
} }
else if (COMPARISON_CLASS_P (arg0)
&& (VECTOR_TYPE_P (type)
|| (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)))
{
tree op_type = TREE_TYPE (TREE_OPERAND (arg0, 0));
enum tree_code subcode = invert_tree_comparison (TREE_CODE (arg0),
HONOR_NANS (TYPE_MODE (op_type)));
if (subcode != ERROR_MARK)
return build2_loc (loc, subcode, type, TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg0, 1));
}
return NULL_TREE; return NULL_TREE;
case TRUTH_NOT_EXPR: case TRUTH_NOT_EXPR:
/* The argument to invert_truthvalue must have Boolean type. */
if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
arg0 = fold_convert_loc (loc, boolean_type_node, arg0);
/* Note that the operand of this must be an int /* Note that the operand of this must be an int
and its values must be 0 or 1. and its values must be 0 or 1.
("true" is a fixed value perhaps depending on the language, ("true" is a fixed value perhaps depending on the language,
...@@ -9586,7 +9604,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type, ...@@ -9586,7 +9604,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
/* Fold ~X op C as X op' ~C, where op' is the swapped comparison. */ /* Fold ~X op C as X op' ~C, where op' is the swapped comparison. */
if (TREE_CODE (arg0) == BIT_NOT_EXPR if (TREE_CODE (arg0) == BIT_NOT_EXPR
&& TREE_CODE (arg1) == INTEGER_CST) && (TREE_CODE (arg1) == INTEGER_CST || TREE_CODE (arg1) == VECTOR_CST))
{ {
tree cmp_type = TREE_TYPE (TREE_OPERAND (arg0, 0)); tree cmp_type = TREE_TYPE (TREE_OPERAND (arg0, 0));
return fold_build2_loc (loc, swap_tree_comparison (code), type, return fold_build2_loc (loc, swap_tree_comparison (code), type,
...@@ -12678,11 +12696,7 @@ fold_binary_loc (location_t loc, ...@@ -12678,11 +12696,7 @@ fold_binary_loc (location_t loc,
/* If the second arg is constant true, this is a logical inversion. */ /* If the second arg is constant true, this is a logical inversion. */
if (integer_onep (arg1)) if (integer_onep (arg1))
{ {
/* Only call invert_truthvalue if operand is a truth value. */ tem = invert_truthvalue_loc (loc, arg0);
if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
tem = fold_build1_loc (loc, TRUTH_NOT_EXPR, TREE_TYPE (arg0), arg0);
else
tem = invert_truthvalue_loc (loc, arg0);
return non_lvalue_loc (loc, fold_convert_loc (loc, type, tem)); return non_lvalue_loc (loc, fold_convert_loc (loc, type, tem));
} }
/* Identical arguments cancel to zero. */ /* Identical arguments cancel to zero. */
...@@ -14043,7 +14057,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, ...@@ -14043,7 +14057,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op2)))) && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op2))))
{ {
location_t loc0 = expr_location_or (arg0, loc); location_t loc0 = expr_location_or (arg0, loc);
tem = fold_truth_not_expr (loc0, arg0); tem = fold_invert_truthvalue (loc0, arg0);
if (tem && COMPARISON_CLASS_P (tem)) if (tem && COMPARISON_CLASS_P (tem))
{ {
tem = fold_cond_expr_with_comparison (loc, type, tem, op2, op1); tem = fold_cond_expr_with_comparison (loc, type, tem, op2, op1);
...@@ -14052,10 +14066,6 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, ...@@ -14052,10 +14066,6 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
} }
} }
/* ??? Fixup the code below for VEC_COND_EXPR. */
if (code == VEC_COND_EXPR)
return NULL_TREE;
/* If the second operand is simpler than the third, swap them /* If the second operand is simpler than the third, swap them
since that produces better jump optimization results. */ since that produces better jump optimization results. */
if (truth_value_p (TREE_CODE (arg0)) if (truth_value_p (TREE_CODE (arg0))
...@@ -14065,13 +14075,15 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, ...@@ -14065,13 +14075,15 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
/* See if this can be inverted. If it can't, possibly because /* See if this can be inverted. If it can't, possibly because
it was a floating-point inequality comparison, don't do it was a floating-point inequality comparison, don't do
anything. */ anything. */
tem = fold_truth_not_expr (loc0, arg0); tem = fold_invert_truthvalue (loc0, arg0);
if (tem) if (tem)
return fold_build3_loc (loc, code, type, tem, op2, op1); return fold_build3_loc (loc, code, type, tem, op2, op1);
} }
/* Convert A ? 1 : 0 to simply A. */ /* Convert A ? 1 : 0 to simply A. */
if (integer_onep (op1) if ((code == VEC_COND_EXPR ? integer_all_onesp (op1)
: (integer_onep (op1)
&& !VECTOR_TYPE_P (type)))
&& integer_zerop (op2) && integer_zerop (op2)
/* If we try to convert OP0 to our type, the /* If we try to convert OP0 to our type, the
call to fold will try to move the conversion inside call to fold will try to move the conversion inside
...@@ -14083,7 +14095,9 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, ...@@ -14083,7 +14095,9 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
/* Convert A ? 0 : 1 to !A. This prefers the use of NOT_EXPR /* Convert A ? 0 : 1 to !A. This prefers the use of NOT_EXPR
over COND_EXPR in cases such as floating point comparisons. */ over COND_EXPR in cases such as floating point comparisons. */
if (integer_zerop (op1) if (integer_zerop (op1)
&& integer_onep (op2) && (code == VEC_COND_EXPR ? integer_all_onesp (op2)
: (integer_onep (op2)
&& !VECTOR_TYPE_P (type)))
&& truth_value_p (TREE_CODE (arg0))) && truth_value_p (TREE_CODE (arg0)))
return pedantic_non_lvalue_loc (loc, return pedantic_non_lvalue_loc (loc,
fold_convert_loc (loc, type, fold_convert_loc (loc, type,
...@@ -14200,46 +14214,53 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type, ...@@ -14200,46 +14214,53 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
/* Convert A ? B : 0 into A && B if A and B are truth values. */ /* Convert A ? B : 0 into A && B if A and B are truth values. */
if (integer_zerop (op2) if (integer_zerop (op2)
&& truth_value_p (TREE_CODE (arg0)) && truth_value_p (TREE_CODE (arg0))
&& truth_value_p (TREE_CODE (arg1))) && truth_value_p (TREE_CODE (arg1))
return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type, && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type)))
fold_convert_loc (loc, type, arg0), return fold_build2_loc (loc, code == VEC_COND_EXPR ? BIT_AND_EXPR
arg1); : TRUTH_ANDIF_EXPR,
type, fold_convert_loc (loc, type, arg0), arg1);
/* Convert A ? B : 1 into !A || B if A and B are truth values. */ /* Convert A ? B : 1 into !A || B if A and B are truth values. */
if (integer_onep (op2) if (code == VEC_COND_EXPR ? integer_all_onesp (op2) : integer_onep (op2)
&& truth_value_p (TREE_CODE (arg0)) && truth_value_p (TREE_CODE (arg0))
&& truth_value_p (TREE_CODE (arg1))) && truth_value_p (TREE_CODE (arg1))
&& (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type)))
{ {
location_t loc0 = expr_location_or (arg0, loc); location_t loc0 = expr_location_or (arg0, loc);
/* Only perform transformation if ARG0 is easily inverted. */ /* Only perform transformation if ARG0 is easily inverted. */
tem = fold_truth_not_expr (loc0, arg0); tem = fold_invert_truthvalue (loc0, arg0);
if (tem) if (tem)
return fold_build2_loc (loc, TRUTH_ORIF_EXPR, type, return fold_build2_loc (loc, code == VEC_COND_EXPR
fold_convert_loc (loc, type, tem), ? BIT_IOR_EXPR
arg1); : TRUTH_ORIF_EXPR,
type, fold_convert_loc (loc, type, tem),
arg1);
} }
/* Convert A ? 0 : B into !A && B if A and B are truth values. */ /* Convert A ? 0 : B into !A && B if A and B are truth values. */
if (integer_zerop (arg1) if (integer_zerop (arg1)
&& truth_value_p (TREE_CODE (arg0)) && truth_value_p (TREE_CODE (arg0))
&& truth_value_p (TREE_CODE (op2))) && truth_value_p (TREE_CODE (op2))
&& (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type)))
{ {
location_t loc0 = expr_location_or (arg0, loc); location_t loc0 = expr_location_or (arg0, loc);
/* Only perform transformation if ARG0 is easily inverted. */ /* Only perform transformation if ARG0 is easily inverted. */
tem = fold_truth_not_expr (loc0, arg0); tem = fold_invert_truthvalue (loc0, arg0);
if (tem) if (tem)
return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type, return fold_build2_loc (loc, code == VEC_COND_EXPR
fold_convert_loc (loc, type, tem), ? BIT_AND_EXPR : TRUTH_ANDIF_EXPR,
op2); type, fold_convert_loc (loc, type, tem),
op2);
} }
/* Convert A ? 1 : B into A || B if A and B are truth values. */ /* Convert A ? 1 : B into A || B if A and B are truth values. */
if (integer_onep (arg1) if (code == VEC_COND_EXPR ? integer_all_onesp (arg1) : integer_onep (arg1)
&& truth_value_p (TREE_CODE (arg0)) && truth_value_p (TREE_CODE (arg0))
&& truth_value_p (TREE_CODE (op2))) && truth_value_p (TREE_CODE (op2))
return fold_build2_loc (loc, TRUTH_ORIF_EXPR, type, && (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type)))
fold_convert_loc (loc, type, arg0), return fold_build2_loc (loc, code == VEC_COND_EXPR
op2); ? BIT_IOR_EXPR : TRUTH_ORIF_EXPR,
type, fold_convert_loc (loc, type, arg0), op2);
return NULL_TREE; return NULL_TREE;
......
2013-05-14 Marc Glisse <marc.glisse@inria.fr>
* g++.dg/ext/vector22.C: New testcase.
* gcc.dg/binop-xor3.c: Remove xfail.
2013-05-14 James Greenhalgh <james.greenhalgh@arm.com> 2013-05-14 James Greenhalgh <james.greenhalgh@arm.com>
* gcc.target/aarch64/vect-fcm.x: Add cases testing * gcc.target/aarch64/vect-fcm.x: Add cases testing
......
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-gimple" } */
typedef unsigned vec __attribute__((vector_size(4*sizeof(int))));
void f(vec*a,vec*b){
*a=(*a)?-1:(*b<10);
*b=(*b)?(*a<10):0;
}
void g(vec*a,vec*b){
*a=(*a)?(*a<*a):-1;
*b=(*b)?-1:(*b<*b);
}
void h(vec*a){
*a=(~*a==5);
}
/* { dg-final { scan-tree-dump-not "~" "gimple" } } */
/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR" "gimple" } } */
/* { dg-final { cleanup-tree-dump "gimple" } } */
...@@ -7,5 +7,5 @@ foo (int a, int b) ...@@ -7,5 +7,5 @@ foo (int a, int b)
return ((a && !b) || (!a && b)); return ((a && !b) || (!a && b));
} }
/* { dg-final { scan-tree-dump-times "\\\^" 1 "optimized" { xfail *-*-* } } } */ /* { dg-final { scan-tree-dump-times "\\\^" 1 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */
...@@ -5770,7 +5770,6 @@ extern tree omit_two_operands_loc (location_t, tree, tree, tree, tree); ...@@ -5770,7 +5770,6 @@ extern tree omit_two_operands_loc (location_t, tree, tree, tree, tree);
#define invert_truthvalue(T)\ #define invert_truthvalue(T)\
invert_truthvalue_loc(UNKNOWN_LOCATION, T) invert_truthvalue_loc(UNKNOWN_LOCATION, T)
extern tree invert_truthvalue_loc (location_t, tree); extern tree invert_truthvalue_loc (location_t, tree);
extern tree fold_truth_not_expr (location_t, tree);
extern tree fold_unary_to_constant (enum tree_code, tree, tree); extern tree fold_unary_to_constant (enum tree_code, tree, tree);
extern tree fold_binary_to_constant (enum tree_code, tree, tree, tree); extern tree fold_binary_to_constant (enum tree_code, tree, tree, tree);
extern tree fold_read_from_constant_string (tree); extern tree fold_read_from_constant_string (tree);
......
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