fold-const.h (const_unop): Declare.

2014-11-26  Richard Biener  <rguenther@suse.de>

	* fold-const.h (const_unop): Declare.
	(const_binop): Likewise.
	* fold-const.c (const_binop): Export overload that expects
	a type parameter and dispatches to fold_relational_const as well.
	Check both operand kinds for guarding the transforms.
	(const_unop): New function, with constant folding from fold_unary_loc.
	(fold_unary_loc): Dispatch to const_unop for tcc_constant operand.
	Remove constant folding done there from the simplifications.
	(fold_binary_loc): Check for constants using CONSTANT_CLASS_P.
	(fold_negate_expr): Remove dead code from the REAL_CST case.
	Avoid building garbage in the COMPLEX_CST case.
	* gimple-match-head.c (gimple_resimplify1): Dispatch to
	const_unop.
	(gimple_resimplify2): Dispatch to const_binop.
	(gimple_simplify): Likewise.

From-SVN: r218086
This commit is contained in:
Richard Biener 2014-11-26 14:39:43 +00:00 committed by Richard Biener
parent 4186636315
commit 8006f46bdd
4 changed files with 230 additions and 154 deletions

View File

@ -1,3 +1,21 @@
2014-11-26 Richard Biener <rguenther@suse.de>
* fold-const.h (const_unop): Declare.
(const_binop): Likewise.
* fold-const.c (const_binop): Export overload that expects
a type parameter and dispatches to fold_relational_const as well.
Check both operand kinds for guarding the transforms.
(const_unop): New function, with constant folding from fold_unary_loc.
(fold_unary_loc): Dispatch to const_unop for tcc_constant operand.
Remove constant folding done there from the simplifications.
(fold_binary_loc): Check for constants using CONSTANT_CLASS_P.
(fold_negate_expr): Remove dead code from the REAL_CST case.
Avoid building garbage in the COMPLEX_CST case.
* gimple-match-head.c (gimple_resimplify1): Dispatch to
const_unop.
(gimple_resimplify2): Dispatch to const_binop.
(gimple_simplify): Likewise.
2014-11-26 Ilya Enkovich <ilya.enkovich@intel.com>
PR bootstrap/63995

View File

@ -115,7 +115,6 @@ static bool negate_expr_p (tree);
static tree negate_expr (tree);
static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
static tree associate_trees (location_t, tree, tree, enum tree_code, tree);
static tree const_binop (enum tree_code, tree, tree);
static enum comparison_code comparison_to_compcode (enum tree_code);
static enum tree_code compcode_to_comparison (enum comparison_code);
static int operand_equal_for_comparison_p (tree, tree, tree);
@ -156,6 +155,9 @@ static tree fold_negate_const (tree, tree);
static tree fold_not_const (const_tree, tree);
static tree fold_relational_const (enum tree_code, tree, tree, tree);
static tree fold_convert_const (enum tree_code, tree, tree);
static tree fold_view_convert_expr (tree, tree);
static bool vec_cst_ctor_to_array (tree, tree *);
/* Return EXPR_LOCATION of T if it is not UNKNOWN_LOCATION.
Otherwise, return LOC. */
@ -564,10 +566,7 @@ fold_negate_expr (location_t loc, tree t)
case REAL_CST:
tem = fold_negate_const (t, type);
/* Two's complement FP formats, such as c4x, may overflow. */
if (!TREE_OVERFLOW (tem) || !flag_trapping_math)
return tem;
break;
return tem;
case FIXED_CST:
tem = fold_negate_const (t, type);
@ -575,13 +574,9 @@ fold_negate_expr (location_t loc, tree t)
case COMPLEX_CST:
{
tree rpart = negate_expr (TREE_REALPART (t));
tree ipart = negate_expr (TREE_IMAGPART (t));
if ((TREE_CODE (rpart) == REAL_CST
&& TREE_CODE (ipart) == REAL_CST)
|| (TREE_CODE (rpart) == INTEGER_CST
&& TREE_CODE (ipart) == INTEGER_CST))
tree rpart = fold_negate_expr (loc, TREE_REALPART (t));
tree ipart = fold_negate_expr (loc, TREE_IMAGPART (t));
if (rpart && ipart)
return build_complex (type, rpart, ipart);
}
break;
@ -1138,10 +1133,10 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
STRIP_NOPS (arg1);
STRIP_NOPS (arg2);
if (TREE_CODE (arg1) == INTEGER_CST)
if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST)
return int_const_binop (code, arg1, arg2);
if (TREE_CODE (arg1) == REAL_CST)
if (TREE_CODE (arg1) == REAL_CST && TREE_CODE (arg2) == REAL_CST)
{
machine_mode mode;
REAL_VALUE_TYPE d1;
@ -1219,7 +1214,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
return t;
}
if (TREE_CODE (arg1) == FIXED_CST)
if (TREE_CODE (arg1) == FIXED_CST && TREE_CODE (arg2) == FIXED_CST)
{
FIXED_VALUE_TYPE f1;
FIXED_VALUE_TYPE f2;
@ -1263,7 +1258,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
return t;
}
if (TREE_CODE (arg1) == COMPLEX_CST)
if (TREE_CODE (arg1) == COMPLEX_CST && TREE_CODE (arg2) == COMPLEX_CST)
{
tree type = TREE_TYPE (arg1);
tree r1 = TREE_REALPART (arg1);
@ -1440,6 +1435,179 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
return NULL_TREE;
}
/* Overload that adds a TYPE parameter to be able to dispatch
to fold_relational_const. */
tree
const_binop (enum tree_code code, tree type, tree arg1, tree arg2)
{
if (TREE_CODE_CLASS (code) == tcc_comparison)
return fold_relational_const (code, type, arg1, arg2);
else
return const_binop (code, arg1, arg2);
}
/* Compute CODE ARG1 with resulting type TYPE with ARG1 being constant.
Return zero if computing the constants is not possible. */
tree
const_unop (enum tree_code code, tree type, tree arg0)
{
switch (code)
{
CASE_CONVERT:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
case FIXED_CONVERT_EXPR:
return fold_convert_const (code, type, arg0);
case ADDR_SPACE_CONVERT_EXPR:
if (integer_zerop (arg0))
return fold_convert_const (code, type, arg0);
break;
case VIEW_CONVERT_EXPR:
return fold_view_convert_expr (type, arg0);
case NEGATE_EXPR:
{
/* Can't call fold_negate_const directly here as that doesn't
handle all cases and we might not be able to negate some
constants. */
tree tem = fold_negate_expr (UNKNOWN_LOCATION, arg0);
if (tem && CONSTANT_CLASS_P (tem))
return tem;
break;
}
case ABS_EXPR:
return fold_abs_const (arg0, type);
case CONJ_EXPR:
if (TREE_CODE (arg0) == COMPLEX_CST)
{
tree ipart = fold_negate_const (TREE_IMAGPART (arg0),
TREE_TYPE (type));
return build_complex (type, TREE_REALPART (arg0), ipart);
}
break;
case BIT_NOT_EXPR:
if (TREE_CODE (arg0) == INTEGER_CST)
return fold_not_const (arg0, type);
/* Perform BIT_NOT_EXPR on each element individually. */
else if (TREE_CODE (arg0) == VECTOR_CST)
{
tree *elements;
tree elem;
unsigned count = VECTOR_CST_NELTS (arg0), i;
elements = XALLOCAVEC (tree, count);
for (i = 0; i < count; i++)
{
elem = VECTOR_CST_ELT (arg0, i);
elem = const_unop (BIT_NOT_EXPR, TREE_TYPE (type), elem);
if (elem == NULL_TREE)
break;
elements[i] = elem;
}
if (i == count)
return build_vector (type, elements);
}
break;
case TRUTH_NOT_EXPR:
if (TREE_CODE (arg0) == INTEGER_CST)
return constant_boolean_node (integer_zerop (arg0), type);
break;
case REALPART_EXPR:
if (TREE_CODE (arg0) == COMPLEX_CST)
return fold_convert (type, TREE_REALPART (arg0));
break;
case IMAGPART_EXPR:
if (TREE_CODE (arg0) == COMPLEX_CST)
return fold_convert (type, TREE_IMAGPART (arg0));
break;
case VEC_UNPACK_LO_EXPR:
case VEC_UNPACK_HI_EXPR:
case VEC_UNPACK_FLOAT_LO_EXPR:
case VEC_UNPACK_FLOAT_HI_EXPR:
{
unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
tree *elts;
enum tree_code subcode;
gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts * 2);
if (TREE_CODE (arg0) != VECTOR_CST)
return NULL_TREE;
elts = XALLOCAVEC (tree, nelts * 2);
if (!vec_cst_ctor_to_array (arg0, elts))
return NULL_TREE;
if ((!BYTES_BIG_ENDIAN) ^ (code == VEC_UNPACK_LO_EXPR
|| code == VEC_UNPACK_FLOAT_LO_EXPR))
elts += nelts;
if (code == VEC_UNPACK_LO_EXPR || code == VEC_UNPACK_HI_EXPR)
subcode = NOP_EXPR;
else
subcode = FLOAT_EXPR;
for (i = 0; i < nelts; i++)
{
elts[i] = fold_convert_const (subcode, TREE_TYPE (type), elts[i]);
if (elts[i] == NULL_TREE || !CONSTANT_CLASS_P (elts[i]))
return NULL_TREE;
}
return build_vector (type, elts);
}
case REDUC_MIN_EXPR:
case REDUC_MAX_EXPR:
case REDUC_PLUS_EXPR:
{
unsigned int nelts, i;
tree *elts;
enum tree_code subcode;
if (TREE_CODE (arg0) != VECTOR_CST)
return NULL_TREE;
nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0));
elts = XALLOCAVEC (tree, nelts);
if (!vec_cst_ctor_to_array (arg0, elts))
return NULL_TREE;
switch (code)
{
case REDUC_MIN_EXPR: subcode = MIN_EXPR; break;
case REDUC_MAX_EXPR: subcode = MAX_EXPR; break;
case REDUC_PLUS_EXPR: subcode = PLUS_EXPR; break;
default: gcc_unreachable ();
}
for (i = 1; i < nelts; i++)
{
elts[0] = const_binop (subcode, elts[0], elts[i]);
if (elts[0] == NULL_TREE || !CONSTANT_CLASS_P (elts[0]))
return NULL_TREE;
}
return elts[0];
}
default:
break;
}
return NULL_TREE;
}
/* Create a sizetype INT_CST node with NUMBER sign extended. KIND
indicates which particular sizetype to create. */
@ -7507,8 +7675,6 @@ build_fold_addr_expr_loc (location_t loc, tree t)
return build_fold_addr_expr_with_type_loc (loc, t, ptrtype);
}
static bool vec_cst_ctor_to_array (tree, tree *);
/* Fold a unary expression of code CODE and type TYPE with operand
OP0. Return the folded expression if folding is successful.
Otherwise, return NULL_TREE. */
@ -7523,10 +7689,6 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
gcc_assert (IS_EXPR_CODE_CLASS (kind)
&& TREE_CODE_LENGTH (code) == 1);
tem = generic_simplify (loc, code, type, op0);
if (tem)
return tem;
arg0 = op0;
if (arg0)
{
@ -7552,8 +7714,23 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
constant folder. */
STRIP_NOPS (arg0);
}
if (CONSTANT_CLASS_P (arg0))
{
tree tem = const_unop (code, type, arg0);
if (tem)
{
if (TREE_TYPE (tem) != type)
tem = fold_convert_loc (loc, type, tem);
return tem;
}
}
}
tem = generic_simplify (loc, code, type, op0);
if (tem)
return tem;
if (TREE_CODE_CLASS (code) == tcc_unary)
{
if (TREE_CODE (arg0) == COMPOUND_EXPR)
@ -7790,24 +7967,14 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
}
}
tem = fold_convert_const (code, type, arg0);
return tem ? tem : NULL_TREE;
case ADDR_SPACE_CONVERT_EXPR:
if (integer_zerop (arg0))
return fold_convert_const (code, type, arg0);
return NULL_TREE;
case FIXED_CONVERT_EXPR:
tem = fold_convert_const (code, type, arg0);
return tem ? tem : NULL_TREE;
case VIEW_CONVERT_EXPR:
if (TREE_CODE (op0) == MEM_REF)
return fold_build2_loc (loc, MEM_REF, type,
TREE_OPERAND (op0, 0), TREE_OPERAND (op0, 1));
return fold_view_convert_expr (type, op0);
return NULL_TREE;
case NEGATE_EXPR:
tem = fold_negate_expr (loc, arg0);
@ -7816,11 +7983,9 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
return NULL_TREE;
case ABS_EXPR:
if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST)
return fold_abs_const (arg0, type);
/* Convert fabs((double)float) into (double)fabsf(float). */
else if (TREE_CODE (arg0) == NOP_EXPR
&& TREE_CODE (type) == REAL_TYPE)
if (TREE_CODE (arg0) == NOP_EXPR
&& TREE_CODE (type) == REAL_TYPE)
{
tree targ0 = strip_float_extensions (arg0);
if (targ0 != arg0)
@ -7854,22 +8019,13 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
return fold_build2_loc (loc, COMPLEX_EXPR, type, rpart,
negate_expr (ipart));
}
if (TREE_CODE (arg0) == COMPLEX_CST)
{
tree itype = TREE_TYPE (type);
tree rpart = fold_convert_loc (loc, itype, TREE_REALPART (arg0));
tree ipart = fold_convert_loc (loc, itype, TREE_IMAGPART (arg0));
return build_complex (type, rpart, negate_expr (ipart));
}
if (TREE_CODE (arg0) == CONJ_EXPR)
return fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
return NULL_TREE;
case BIT_NOT_EXPR:
if (TREE_CODE (arg0) == INTEGER_CST)
return fold_not_const (arg0, type);
/* Convert ~ (-A) to A - 1. */
else if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR)
if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR)
return fold_build2_loc (loc, MINUS_EXPR, type,
fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)),
build_int_cst (type, 1));
@ -7897,25 +8053,6 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
return fold_build2_loc (loc, BIT_XOR_EXPR, type,
fold_convert_loc (loc, type,
TREE_OPERAND (arg0, 0)), tem);
/* Perform BIT_NOT_EXPR on each element individually. */
else if (TREE_CODE (arg0) == VECTOR_CST)
{
tree *elements;
tree elem;
unsigned count = VECTOR_CST_NELTS (arg0), i;
elements = XALLOCAVEC (tree, count);
for (i = 0; i < count; i++)
{
elem = VECTOR_CST_ELT (arg0, i);
elem = fold_unary_loc (loc, BIT_NOT_EXPR, TREE_TYPE (type), elem);
if (elem == NULL_TREE)
break;
elements[i] = elem;
}
if (i == count)
return build_vector (type, elements);
}
return NULL_TREE;
@ -7932,8 +8069,6 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
case REALPART_EXPR:
if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
return fold_convert_loc (loc, type, arg0);
if (TREE_CODE (arg0) == COMPLEX_CST)
return fold_convert_loc (loc, type, TREE_REALPART (arg0));
if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
{
tree itype = TREE_TYPE (TREE_TYPE (arg0));
@ -7972,8 +8107,6 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
case IMAGPART_EXPR:
if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
return build_zero_cst (type);
if (TREE_CODE (arg0) == COMPLEX_CST)
return fold_convert_loc (loc, type, TREE_IMAGPART (arg0));
if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
{
tree itype = TREE_TYPE (TREE_TYPE (arg0));
@ -8021,76 +8154,6 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
}
return NULL_TREE;
case VEC_UNPACK_LO_EXPR:
case VEC_UNPACK_HI_EXPR:
case VEC_UNPACK_FLOAT_LO_EXPR:
case VEC_UNPACK_FLOAT_HI_EXPR:
{
unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
tree *elts;
enum tree_code subcode;
gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts * 2);
if (TREE_CODE (arg0) != VECTOR_CST)
return NULL_TREE;
elts = XALLOCAVEC (tree, nelts * 2);
if (!vec_cst_ctor_to_array (arg0, elts))
return NULL_TREE;
if ((!BYTES_BIG_ENDIAN) ^ (code == VEC_UNPACK_LO_EXPR
|| code == VEC_UNPACK_FLOAT_LO_EXPR))
elts += nelts;
if (code == VEC_UNPACK_LO_EXPR || code == VEC_UNPACK_HI_EXPR)
subcode = NOP_EXPR;
else
subcode = FLOAT_EXPR;
for (i = 0; i < nelts; i++)
{
elts[i] = fold_convert_const (subcode, TREE_TYPE (type), elts[i]);
if (elts[i] == NULL_TREE || !CONSTANT_CLASS_P (elts[i]))
return NULL_TREE;
}
return build_vector (type, elts);
}
case REDUC_MIN_EXPR:
case REDUC_MAX_EXPR:
case REDUC_PLUS_EXPR:
{
unsigned int nelts, i;
tree *elts;
enum tree_code subcode;
if (TREE_CODE (op0) != VECTOR_CST)
return NULL_TREE;
nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (op0));
elts = XALLOCAVEC (tree, nelts);
if (!vec_cst_ctor_to_array (op0, elts))
return NULL_TREE;
switch (code)
{
case REDUC_MIN_EXPR: subcode = MIN_EXPR; break;
case REDUC_MAX_EXPR: subcode = MAX_EXPR; break;
case REDUC_PLUS_EXPR: subcode = PLUS_EXPR; break;
default: gcc_unreachable ();
}
for (i = 1; i < nelts; i++)
{
elts[0] = const_binop (subcode, elts[0], elts[i]);
if (elts[0] == NULL_TREE || !CONSTANT_CLASS_P (elts[0]))
return NULL_TREE;
}
return elts[0];
}
default:
return NULL_TREE;
} /* switch (code) */
@ -9689,19 +9752,13 @@ fold_binary_loc (location_t loc,
/* Note that TREE_CONSTANT isn't enough: static var addresses are
constant but we can't do arithmetic on them. */
if ((TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
|| (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
|| (TREE_CODE (arg0) == FIXED_CST && TREE_CODE (arg1) == FIXED_CST)
|| (TREE_CODE (arg0) == FIXED_CST && TREE_CODE (arg1) == INTEGER_CST)
|| (TREE_CODE (arg0) == COMPLEX_CST && TREE_CODE (arg1) == COMPLEX_CST)
|| (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
|| (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == INTEGER_CST))
if (CONSTANT_CLASS_P (arg0) && CONSTANT_CLASS_P (arg1))
{
if (kind == tcc_binary)
{
/* Make sure type and arg0 have the same saturating flag. */
gcc_assert (TYPE_SATURATING (type)
== TYPE_SATURATING (TREE_TYPE (arg0)));
gcc_checking_assert (TYPE_SATURATING (type)
== TYPE_SATURATING (TREE_TYPE (arg0)));
tem = const_binop (code, arg0, arg1);
}
else if (kind == tcc_comparison)

View File

@ -169,5 +169,7 @@ extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int,
tree, tree);
extern tree sign_bit_p (tree, const_tree);
extern tree exact_inverse (tree, tree);
extern tree const_unop (enum tree_code, tree, tree);
extern tree const_binop (enum tree_code, tree, tree, tree);
#endif // GCC_FOLD_CONST_H

View File

@ -94,7 +94,7 @@ gimple_resimplify1 (gimple_seq *seq,
{
tree tem = NULL_TREE;
if (res_code->is_tree_code ())
tem = fold_unary_to_constant (*res_code, type, res_ops[0]);
tem = const_unop (*res_code, type, res_ops[0]);
else
{
tree decl = builtin_decl_implicit (*res_code);
@ -150,8 +150,7 @@ gimple_resimplify2 (gimple_seq *seq,
{
tree tem = NULL_TREE;
if (res_code->is_tree_code ())
tem = fold_binary_to_constant (*res_code, type,
res_ops[0], res_ops[1]);
tem = const_binop (*res_code, type, res_ops[0], res_ops[1]);
else
{
tree decl = builtin_decl_implicit (*res_code);
@ -386,7 +385,7 @@ gimple_simplify (enum tree_code code, tree type,
{
if (constant_for_folding (op0))
{
tree res = fold_unary_to_constant (code, type, op0);
tree res = const_unop (code, type, op0);
if (res != NULL_TREE
&& CONSTANT_CLASS_P (res))
return res;
@ -409,7 +408,7 @@ gimple_simplify (enum tree_code code, tree type,
{
if (constant_for_folding (op0) && constant_for_folding (op1))
{
tree res = fold_binary_to_constant (code, type, op0, op1);
tree res = const_binop (code, type, op0, op1);
if (res != NULL_TREE
&& CONSTANT_CLASS_P (res))
return res;