From 8006f46bdd8be581f287ed7d1c2d204c608fb426 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 26 Nov 2014 14:39:43 +0000 Subject: [PATCH] fold-const.h (const_unop): Declare. 2014-11-26 Richard Biener * 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 --- gcc/ChangeLog | 18 ++ gcc/fold-const.c | 355 +++++++++++++++++++++++----------------- gcc/fold-const.h | 2 + gcc/gimple-match-head.c | 9 +- 4 files changed, 230 insertions(+), 154 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 702e86a77e0..34f66f95b2b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2014-11-26 Richard Biener + + * 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 PR bootstrap/63995 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 04a195c2bf8..195d1e5408d 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -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) diff --git a/gcc/fold-const.h b/gcc/fold-const.h index 09ece6735c7..31c5984ae65 100644 --- a/gcc/fold-const.h +++ b/gcc/fold-const.h @@ -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 diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c index 9c6da59d44b..4bd4a48c55c 100644 --- a/gcc/gimple-match-head.c +++ b/gcc/gimple-match-head.c @@ -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; -- 2.30.2