diff options
author | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-05-13 06:41:07 +0000 |
---|---|---|
committer | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-05-13 06:41:07 +0000 |
commit | 4ee9c6840ad3fc92a9034343278a1e476ad6872a (patch) | |
tree | a2568888a519c077427b133de9ece5879a8484a5 /gcc/fold-const.c | |
parent | ebb338380ab170c91e64d38038e6b5ce930d69a1 (diff) | |
download | gcc-4ee9c6840ad3fc92a9034343278a1e476ad6872a.tar.gz |
Merge tree-ssa-20020619-branch into mainline.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@81764 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 777 |
1 files changed, 716 insertions, 61 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7d04db61307..ed54ee93bb6 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -65,7 +65,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 (tree, tree, enum tree_code, tree); -static tree int_const_binop (enum tree_code, tree, tree, int); static tree const_binop (enum tree_code, tree, tree, int); static hashval_t size_htab_hash (const void *); static int size_htab_eq (const void *, const void *); @@ -116,6 +115,7 @@ static bool tree_swap_operands_p (tree, tree, bool); static tree fold_negate_const (tree, tree); static tree fold_abs_const (tree, tree); static tree fold_relational_const (enum tree_code, tree, tree, tree); +static tree fold_relational_hi_lo (enum tree_code *, const tree, tree *, tree *); /* The following constants represent a bit based encoding of GCC's comparison operators. This encoding simplifies transformations @@ -1230,7 +1230,7 @@ associate_trees (tree t1, tree t2, enum tree_code code, tree type) If NOTRUNC is nonzero, do not truncate the result to fit the data type. */ -static tree +tree int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc) { unsigned HOST_WIDE_INT int1l, int2l; @@ -1990,8 +1990,6 @@ fold_convert (tree type, tree arg) tree non_lvalue (tree x) { - tree result; - /* These things are certainly not lvalues. */ if (TREE_CODE (x) == NON_LVALUE_EXPR || TREE_CODE (x) == INTEGER_CST @@ -2000,9 +1998,7 @@ non_lvalue (tree x) || TREE_CODE (x) == ADDR_EXPR) return x; - result = build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x); - TREE_CONSTANT (result) = TREE_CONSTANT (x); - return result; + return build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x); } /* Nonzero means lvalues are limited to those valid in pedantic ANSI C. @@ -2138,16 +2134,16 @@ truth_value_p (enum tree_code code) /* Return nonzero if two operands (typically of the same tree node) are necessarily equal. If either argument has side-effects this - function returns zero. + function returns zero. FLAGS modifies behaviour as follows: - If ONLY_CONST is nonzero, only return nonzero for constants. + If OEP_ONLY_CONST is set, only return nonzero for constants. This function tests whether the operands are indistinguishable; it does not test whether they are equal using C's == operation. The distinction is important for IEEE floating point, because (1) -0.0 and 0.0 are distinguishable, but -0.0==0.0, and (2) two NaNs may be indistinguishable, but NaN!=NaN. - If ONLY_CONST is zero, a VAR_DECL is considered equal to itself + If OEP_ONLY_CONST is unset, a VAR_DECL is considered equal to itself even though it may hold multiple values during a function. This is because a GCC tree node guarantees that nothing else is executed between the evaluation of its "operands" (which may often @@ -2156,13 +2152,15 @@ truth_value_p (enum tree_code code) same value in each operand/subexpression. Hence a zero value for ONLY_CONST assumes isochronic (or instantaneous) tree equivalence. If comparing arbitrary expression trees, such as from different - statements, ONLY_CONST must usually be nonzero. */ + statements, ONLY_CONST must usually be nonzero. + + If OEP_PURE_SAME is set, then pure functions with identical arguments + are considered the same. It is used when the caller has other ways + to ensure that global memory is unchanged in between. */ int -operand_equal_p (tree arg0, tree arg1, int only_const) +operand_equal_p (tree arg0, tree arg1, unsigned int flags) { - tree fndecl; - /* If either is ERROR_MARK, they aren't equal. */ if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK) return 0; @@ -2191,7 +2189,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) expressions with side effects that should be treated the same due to the only side effects being identical SAVE_EXPR's, that will be detected in the recursive calls below. */ - if (arg0 == arg1 && ! only_const + if (arg0 == arg1 && ! (flags & OEP_ONLY_CONST) && (TREE_CODE (arg0) == SAVE_EXPR || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1)))) return 1; @@ -2225,7 +2223,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) while (v1 && v2) { if (!operand_equal_p (TREE_VALUE (v1), TREE_VALUE (v2), - only_const)) + flags)) return 0; v1 = TREE_CHAIN (v1); v2 = TREE_CHAIN (v2); @@ -2236,9 +2234,9 @@ operand_equal_p (tree arg0, tree arg1, int only_const) case COMPLEX_CST: return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1), - only_const) + flags) && operand_equal_p (TREE_IMAGPART (arg0), TREE_IMAGPART (arg1), - only_const)); + flags)); case STRING_CST: return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1) @@ -2253,7 +2251,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) break; } - if (only_const) + if (flags & OEP_ONLY_CONST) return 0; switch (TREE_CODE_CLASS (TREE_CODE (arg0))) @@ -2266,7 +2264,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) return 0; return operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0); + TREE_OPERAND (arg1, 0), flags); case '<': case '2': @@ -2278,9 +2276,9 @@ operand_equal_p (tree arg0, tree arg1, int only_const) /* For commutative ops, allow the other order. */ return (commutative_tree_code (TREE_CODE (arg0)) && operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 1), 0) + TREE_OPERAND (arg1, 1), flags) && operand_equal_p (TREE_OPERAND (arg0, 1), - TREE_OPERAND (arg1, 0), 0)); + TREE_OPERAND (arg1, 0), flags)); case 'r': /* If either of the pointer (or reference) expressions we are @@ -2293,23 +2291,23 @@ operand_equal_p (tree arg0, tree arg1, int only_const) { case INDIRECT_REF: return operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0); + TREE_OPERAND (arg1, 0), flags); case COMPONENT_REF: case ARRAY_REF: case ARRAY_RANGE_REF: return (operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0) + TREE_OPERAND (arg1, 0), flags) && operand_equal_p (TREE_OPERAND (arg0, 1), - TREE_OPERAND (arg1, 1), 0)); + TREE_OPERAND (arg1, 1), flags)); case BIT_FIELD_REF: return (operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0) + TREE_OPERAND (arg1, 0), flags) && operand_equal_p (TREE_OPERAND (arg0, 1), - TREE_OPERAND (arg1, 1), 0) + TREE_OPERAND (arg1, 1), flags) && operand_equal_p (TREE_OPERAND (arg0, 2), - TREE_OPERAND (arg1, 2), 0)); + TREE_OPERAND (arg1, 2), flags)); default: return 0; } @@ -2320,7 +2318,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) case ADDR_EXPR: case TRUTH_NOT_EXPR: return operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0); + TREE_OPERAND (arg1, 0), flags); case RTL_EXPR: return rtx_equal_p (RTL_EXPR_RTL (arg0), RTL_EXPR_RTL (arg1)); @@ -2329,14 +2327,18 @@ operand_equal_p (tree arg0, tree arg1, int only_const) /* If the CALL_EXPRs call different functions, then they clearly can not be equal. */ if (! operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0)) + TREE_OPERAND (arg1, 0), flags)) return 0; - /* Only consider const functions equivalent. */ - fndecl = get_callee_fndecl (arg0); - if (fndecl == NULL_TREE - || ! (flags_from_decl_or_type (fndecl) & ECF_CONST)) - return 0; + { + unsigned int cef = call_expr_flags (arg0); + if (flags & OEP_PURE_SAME) + cef &= ECF_CONST | ECF_PURE; + else + cef &= ECF_CONST; + if (!cef) + return 0; + } /* Now see if all the arguments are the same. operand_equal_p does not handle TREE_LIST, so we walk the operands here @@ -2345,7 +2347,8 @@ operand_equal_p (tree arg0, tree arg1, int only_const) arg1 = TREE_OPERAND (arg1, 1); while (arg0 && arg1) { - if (! operand_equal_p (TREE_VALUE (arg0), TREE_VALUE (arg1), 0)) + if (! operand_equal_p (TREE_VALUE (arg0), TREE_VALUE (arg1), + flags)) return 0; arg0 = TREE_CHAIN (arg0); @@ -2361,11 +2364,11 @@ operand_equal_p (tree arg0, tree arg1, int only_const) } case 'd': - /* Consider __builtin_sqrt equal to sqrt. */ - return TREE_CODE (arg0) == FUNCTION_DECL - && DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1) - && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1) - && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1); + /* Consider __builtin_sqrt equal to sqrt. */ + return (TREE_CODE (arg0) == FUNCTION_DECL + && DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1) + && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1) + && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1)); default: return 0; @@ -2730,6 +2733,9 @@ invert_truthvalue (tree arg) return invert_truthvalue (TREE_OPERAND (arg, 0)); case NOP_EXPR: + if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + break; + case CONVERT_EXPR: case FLOAT_EXPR: return build1 (TREE_CODE (arg), type, @@ -5527,6 +5533,15 @@ tree_swap_operands_p (tree arg0, tree arg1, bool reorder) if (DECL_P (arg0)) return 1; + if (reorder && flag_evaluation_order + && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1))) + return 0; + + if (DECL_P (arg1)) + return 0; + if (DECL_P (arg0)) + return 1; + return 0; } @@ -5553,6 +5568,7 @@ fold (tree expr) tree arg0 = NULL_TREE, arg1 = NULL_TREE; enum tree_code code = TREE_CODE (t); int kind = TREE_CODE_CLASS (code); + /* WINS will be nonzero when the switch is done if all operands are constant. */ int wins = 1; @@ -5673,9 +5689,10 @@ fold (tree expr) && integer_onep (TREE_OPERAND (arg0, 1))))))) { tem = fold (build (code == BIT_AND_EXPR ? TRUTH_AND_EXPR - : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR - : TRUTH_XOR_EXPR, - type, arg0, arg1)); + : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR + : TRUTH_XOR_EXPR, + type, fold_convert (boolean_type_node, arg0), + fold_convert (boolean_type_node, arg1))); if (code == EQ_EXPR) tem = invert_truthvalue (tem); @@ -5731,9 +5748,18 @@ fold (tree expr) return tem; } else if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<') - return fold (build (COND_EXPR, type, arg0, - fold (build1 (code, type, integer_one_node)), - fold (build1 (code, type, integer_zero_node)))); + { + if (TREE_CODE (type) == BOOLEAN_TYPE) + { + arg0 = copy_node (arg0); + TREE_TYPE (arg0) = type; + return arg0; + } + else if (TREE_CODE (type) != INTEGER_TYPE) + return fold (build (COND_EXPR, type, arg0, + fold (build1 (code, type, integer_one_node)), + fold (build1 (code, type, integer_zero_node)))); + } } else if (TREE_CODE_CLASS (code) == '<' && TREE_CODE (arg0) == COMPOUND_EXPR) @@ -5884,7 +5910,7 @@ fold (tree expr) TREE_OPERAND (tem, 0) = TREE_OPERAND (prev, 1); /* First do the assignment, then return converted constant. */ tem = build (COMPOUND_EXPR, TREE_TYPE (tem), prev, fold (tem)); - TREE_NO_UNUSED_WARNING (tem) = 1; + TREE_NO_WARNING (tem) = 1; TREE_USED (tem) = 1; return tem; } @@ -5932,6 +5958,26 @@ fold (tree expr) fold_convert (type, and1))); } + /* Convert (T1)((T2)X op Y) into (T1)X op Y, for pointer types T1 and + T2 being pointers to types of the same size. */ + if (POINTER_TYPE_P (TREE_TYPE (t)) + && TREE_CODE_CLASS (TREE_CODE (arg0)) == '2' + && TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR + && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0)))) + { + tree arg00 = TREE_OPERAND (arg0, 0); + tree t0 = TREE_TYPE (t); + tree t1 = TREE_TYPE (arg00); + tree tt0 = TREE_TYPE (t0); + tree tt1 = TREE_TYPE (t1); + tree s0 = TYPE_SIZE (tt0); + tree s1 = TYPE_SIZE (tt1); + + if (s0 && s1 && operand_equal_p (s0, s1, OEP_ONLY_CONST)) + return build (TREE_CODE (arg0), t0, convert (t0, arg00), + TREE_OPERAND (arg0, 1)); + } + tem = fold_convert_const (code, type, arg0); return tem ? tem : t; @@ -5956,6 +6002,7 @@ fold (tree expr) { tem = copy_node (t); TREE_CONSTANT (tem) = wins; + TREE_INVARIANT (tem) = wins; return tem; } return t; @@ -7131,7 +7178,7 @@ fold (tree expr) if (operand_equal_p (arg0, arg1, 0)) return omit_one_operand (type, arg0, arg1); if (INTEGRAL_TYPE_P (type) - && operand_equal_p (arg1, TYPE_MIN_VALUE (type), 1)) + && operand_equal_p (arg1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST)) return omit_one_operand (type, arg1, arg0); goto associate; @@ -7140,7 +7187,7 @@ fold (tree expr) return omit_one_operand (type, arg0, arg1); if (INTEGRAL_TYPE_P (type) && TYPE_MAX_VALUE (type) - && operand_equal_p (arg1, TYPE_MAX_VALUE (type), 1)) + && operand_equal_p (arg1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST)) return omit_one_operand (type, arg1, arg0); goto associate; @@ -7284,6 +7331,9 @@ fold (tree expr) return non_lvalue (fold_convert (type, invert_truthvalue (arg1))); if (integer_onep (arg1)) return non_lvalue (fold_convert (type, invert_truthvalue (arg0))); + /* Identical arguments cancel to zero. */ + if (operand_equal_p (arg0, arg1, 0)) + return omit_one_operand (type, integer_zero_node, arg0); return t; case EQ_EXPR: @@ -7520,7 +7570,11 @@ fold (tree expr) } /* Comparisons with the highest or lowest possible integer of - the specified size will have known values. */ + the specified size will have known values. + + This is quite similar to fold_relational_hi_lo; however, my + attempts to share the code have been nothing but trouble. + I give up for now. */ { int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg1))); @@ -7622,7 +7676,8 @@ fold (tree expr) break; } - else if (TREE_INT_CST_HIGH (arg1) == 0 + else if (!in_gimple_form + && TREE_INT_CST_HIGH (arg1) == 0 && TREE_INT_CST_LOW (arg1) == signed_max && TYPE_UNSIGNED (TREE_TYPE (arg1)) /* signed_type does not work on pointer types. */ @@ -8262,40 +8317,48 @@ fold (tree expr) case LT_EXPR: /* If C1 is C2 + 1, this is min(A, C2). */ - if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), 1) + if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), + OEP_ONLY_CONST) && operand_equal_p (TREE_OPERAND (arg0, 1), const_binop (PLUS_EXPR, arg2, - integer_one_node, 0), 1)) + integer_one_node, 0), + OEP_ONLY_CONST)) return pedantic_non_lvalue (fold (build (MIN_EXPR, type, arg1, arg2))); break; case LE_EXPR: /* If C1 is C2 - 1, this is min(A, C2). */ - if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), 1) + if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), + OEP_ONLY_CONST) && operand_equal_p (TREE_OPERAND (arg0, 1), const_binop (MINUS_EXPR, arg2, - integer_one_node, 0), 1)) + integer_one_node, 0), + OEP_ONLY_CONST)) return pedantic_non_lvalue (fold (build (MIN_EXPR, type, arg1, arg2))); break; case GT_EXPR: /* If C1 is C2 - 1, this is max(A, C2). */ - if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), 1) + if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), + OEP_ONLY_CONST) && operand_equal_p (TREE_OPERAND (arg0, 1), const_binop (MINUS_EXPR, arg2, - integer_one_node, 0), 1)) + integer_one_node, 0), + OEP_ONLY_CONST)) return pedantic_non_lvalue (fold (build (MAX_EXPR, type, arg1, arg2))); break; case GE_EXPR: /* If C1 is C2 + 1, this is max(A, C2). */ - if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), 1) + if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), + OEP_ONLY_CONST) && operand_equal_p (TREE_OPERAND (arg0, 1), const_binop (PLUS_EXPR, arg2, - integer_one_node, 0), 1)) + integer_one_node, 0), + OEP_ONLY_CONST)) return pedantic_non_lvalue (fold (build (MAX_EXPR, type, arg1, arg2))); break; @@ -8348,7 +8411,7 @@ fold (tree expr) && integer_pow2p (arg1) && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), - arg1, 1)) + arg1, OEP_ONLY_CONST)) return pedantic_non_lvalue (fold_convert (type, TREE_OPERAND (arg0, 0))); @@ -9183,6 +9246,598 @@ rtl_expr_nonnegative_p (rtx r) } } + +/* See if we are applying CODE, a relational to the highest or lowest + possible integer of TYPE. If so, then the result is a compile + time constant. */ + +static tree +fold_relational_hi_lo (enum tree_code *code_p, const tree type, tree *op0_p, + tree *op1_p) +{ + tree op0 = *op0_p; + tree op1 = *op1_p; + enum tree_code code = *code_p; + int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (op1))); + + if (TREE_CODE (op1) == INTEGER_CST + && ! TREE_CONSTANT_OVERFLOW (op1) + && width <= HOST_BITS_PER_WIDE_INT + && (INTEGRAL_TYPE_P (TREE_TYPE (op1)) + || POINTER_TYPE_P (TREE_TYPE (op1)))) + { + unsigned HOST_WIDE_INT signed_max; + unsigned HOST_WIDE_INT max, min; + + signed_max = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) - 1; + + if (TYPE_UNSIGNED (TREE_TYPE (op1))) + { + max = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1; + min = 0; + } + else + { + max = signed_max; + min = ((unsigned HOST_WIDE_INT) -1 << (width - 1)); + } + + if (TREE_INT_CST_HIGH (op1) == 0 + && TREE_INT_CST_LOW (op1) == max) + switch (code) + { + case GT_EXPR: + return omit_one_operand (type, + convert (type, integer_zero_node), + op0); + case GE_EXPR: + *code_p = EQ_EXPR; + break; + case LE_EXPR: + return omit_one_operand (type, + convert (type, integer_one_node), + op0); + case LT_EXPR: + *code_p = NE_EXPR; + break; + + /* The GE_EXPR and LT_EXPR cases above are not normally + reached because of previous transformations. */ + + default: + break; + } + else if (TREE_INT_CST_HIGH (op1) == 0 + && TREE_INT_CST_LOW (op1) == max - 1) + switch (code) + { + case GT_EXPR: + *code_p = EQ_EXPR; + *op1_p = const_binop (PLUS_EXPR, op1, integer_one_node, 0); + break; + case LE_EXPR: + *code_p = NE_EXPR; + *op1_p = const_binop (PLUS_EXPR, op1, integer_one_node, 0); + break; + default: + break; + } + else if (TREE_INT_CST_HIGH (op1) == (min ? -1 : 0) + && TREE_INT_CST_LOW (op1) == min) + switch (code) + { + case LT_EXPR: + return omit_one_operand (type, + convert (type, integer_zero_node), + op0); + case LE_EXPR: + *code_p = EQ_EXPR; + break; + + case GE_EXPR: + return omit_one_operand (type, + convert (type, integer_one_node), + op0); + case GT_EXPR: + *code_p = NE_EXPR; + break; + + default: + break; + } + else if (TREE_INT_CST_HIGH (op1) == (min ? -1 : 0) + && TREE_INT_CST_LOW (op1) == min + 1) + switch (code) + { + case GE_EXPR: + *code_p = NE_EXPR; + *op1_p = const_binop (MINUS_EXPR, op1, integer_one_node, 0); + break; + case LT_EXPR: + *code_p = EQ_EXPR; + *op1_p = const_binop (MINUS_EXPR, op1, integer_one_node, 0); + break; + default: + break; + } + + else if (TREE_INT_CST_HIGH (op1) == 0 + && TREE_INT_CST_LOW (op1) == signed_max + && TYPE_UNSIGNED (TREE_TYPE (op1)) + /* signed_type does not work on pointer types. */ + && INTEGRAL_TYPE_P (TREE_TYPE (op1))) + { + /* The following case also applies to X < signed_max+1 + and X >= signed_max+1 because previous transformations. */ + if (code == LE_EXPR || code == GT_EXPR) + { + tree st0, st1, exp, retval; + st0 = (*lang_hooks.types.signed_type) (TREE_TYPE (op0)); + st1 = (*lang_hooks.types.signed_type) (TREE_TYPE (op1)); + + exp = build (code == LE_EXPR ? GE_EXPR: LT_EXPR, + type, + convert (st0, op0), + convert (st1, integer_zero_node)); + + retval + = nondestructive_fold_binary_to_constant (TREE_CODE (exp), + TREE_TYPE (exp), + TREE_OPERAND (exp, 0), + TREE_OPERAND (exp, 1)); + + /* If we are in gimple form, then returning EXP would create + non-gimple expressions. Clearing it is safe and insures + we do not allow a non-gimple expression to escape. */ + if (in_gimple_form) + exp = NULL; + + return (retval ? retval : exp); + } + } + } + + return NULL_TREE; +} + + +/* Given the components of a binary expression CODE, TYPE, OP0 and OP1, + attempt to fold the expression to a constant without modifying TYPE, + OP0 or OP1. + + If the expression could be simplified to a constant, then return + the constant. If the expression would not be simplified to a + constant, then return NULL_TREE. + + Note this is primarily designed to be called after gimplification + of the tree structures and when at least one operand is a constant. + As a result of those simplifying assumptions this routine is far + simpler than the generic fold routine. */ + +tree +nondestructive_fold_binary_to_constant (enum tree_code code, tree type, + tree op0, tree op1) +{ + int wins = 1; + tree subop0; + tree subop1; + tree tem; + + /* If this is a commutative operation, and ARG0 is a constant, move it + to ARG1 to reduce the number of tests below. */ + if (commutative_tree_code (code) + && (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST)) + { + tem = op0; + op0 = op1; + op1 = tem; + } + + /* If either operand is a complex type, extract its real component. */ + if (TREE_CODE (op0) == COMPLEX_CST) + subop0 = TREE_REALPART (op0); + else + subop0 = op0; + + if (TREE_CODE (op1) == COMPLEX_CST) + subop1 = TREE_REALPART (op1); + else + subop1 = op1; + + /* Note if either argument is not a real or integer constant. + With a few exceptions, simplification is limited to cases + where both arguments are constants. */ + if ((TREE_CODE (subop0) != INTEGER_CST + && TREE_CODE (subop0) != REAL_CST) + || (TREE_CODE (subop1) != INTEGER_CST + && TREE_CODE (subop1) != REAL_CST)) + wins = 0; + + switch (code) + { + case PLUS_EXPR: + /* (plus (address) (const_int)) is a constant. */ + if (TREE_CODE (op0) == PLUS_EXPR + && TREE_CODE (op1) == INTEGER_CST + && (TREE_CODE (TREE_OPERAND (op0, 0)) == ADDR_EXPR + || (TREE_CODE (TREE_OPERAND (op0, 0)) == NOP_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (op0, 0), 0)) + == ADDR_EXPR))) + && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST) + { + return build (PLUS_EXPR, type, TREE_OPERAND (op0, 0), + const_binop (PLUS_EXPR, op1, TREE_OPERAND (op0, 1), 0)); + } + case BIT_XOR_EXPR: + + binary: + if (!wins) + return NULL_TREE; + + /* Both arguments are constants. Simplify. */ + tem = const_binop (code, op0, op1, 0); + if (tem != NULL_TREE) + { + /* The return value should always have the same type as + the original expression. */ + if (TREE_TYPE (tem) != type) + tem = convert (type, tem); + + return tem; + } + return NULL_TREE; + + case MINUS_EXPR: + /* Fold &x - &x. This can happen from &x.foo - &x. + This is unsafe for certain floats even in non-IEEE formats. + In IEEE, it is unsafe because it does wrong for NaNs. + Also note that operand_equal_p is always false if an + operand is volatile. */ + if (! FLOAT_TYPE_P (type) && operand_equal_p (op0, op1, 0)) + return convert (type, integer_zero_node); + + goto binary; + + case MULT_EXPR: + case BIT_AND_EXPR: + /* Special case multiplication or bitwise AND where one argument + is zero. */ + if (! FLOAT_TYPE_P (type) && integer_zerop (op1)) + return omit_one_operand (type, op1, op0); + else + if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (op0))) + && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op0))) + && real_zerop (op1)) + return omit_one_operand (type, op1, op0); + + goto binary; + + case BIT_IOR_EXPR: + /* Special case when we know the result will be all ones. */ + if (integer_all_onesp (op1)) + return omit_one_operand (type, op1, op0); + + goto binary; + + case TRUNC_DIV_EXPR: + case ROUND_DIV_EXPR: + case FLOOR_DIV_EXPR: + case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + case TRUNC_MOD_EXPR: + case ROUND_MOD_EXPR: + case FLOOR_MOD_EXPR: + case CEIL_MOD_EXPR: + case RDIV_EXPR: + /* Division by zero is undefined. */ + if (integer_zerop (op1)) + return NULL_TREE; + + if (TREE_CODE (op1) == REAL_CST + && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (op1))) + && real_zerop (op1)) + return NULL_TREE; + + goto binary; + + case MIN_EXPR: + if (INTEGRAL_TYPE_P (type) + && operand_equal_p (op1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST)) + return omit_one_operand (type, op1, op0); + + goto binary; + + case MAX_EXPR: + if (INTEGRAL_TYPE_P (type) + && TYPE_MAX_VALUE (type) + && operand_equal_p (op1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST)) + return omit_one_operand (type, op1, op0); + + goto binary; + + case RSHIFT_EXPR: + /* Optimize -1 >> x for arithmetic right shifts. */ + if (integer_all_onesp (op0) && ! TYPE_UNSIGNED (type)) + return omit_one_operand (type, op0, op1); + /* ... fall through ... */ + + case LSHIFT_EXPR: + if (integer_zerop (op0)) + return omit_one_operand (type, op0, op1); + + /* Since negative shift count is not well-defined, don't + try to compute it in the compiler. */ + if (TREE_CODE (op1) == INTEGER_CST && tree_int_cst_sgn (op1) < 0) + return NULL_TREE; + + goto binary; + + case LROTATE_EXPR: + case RROTATE_EXPR: + /* -1 rotated either direction by any amount is still -1. */ + if (integer_all_onesp (op0)) + return omit_one_operand (type, op0, op1); + + /* 0 rotated either direction by any amount is still zero. */ + if (integer_zerop (op0)) + return omit_one_operand (type, op0, op1); + + goto binary; + + case COMPLEX_EXPR: + if (wins) + return build_complex (type, op0, op1); + return NULL_TREE; + + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + /* If one arg is a real or integer constant, put it last. */ + if ((TREE_CODE (op0) == INTEGER_CST + && TREE_CODE (op1) != INTEGER_CST) + || (TREE_CODE (op0) == REAL_CST + && TREE_CODE (op0) != REAL_CST)) + { + tree temp; + + temp = op0; + op0 = op1; + op1 = temp; + code = swap_tree_comparison (code); + } + + /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0. + This transformation affects the cases which are handled in later + optimizations involving comparisons with non-negative constants. */ + if (TREE_CODE (op1) == INTEGER_CST + && TREE_CODE (op0) != INTEGER_CST + && tree_int_cst_sgn (op1) > 0) + { + switch (code) + { + case GE_EXPR: + code = GT_EXPR; + op1 = const_binop (MINUS_EXPR, op1, integer_one_node, 0); + break; + + case LT_EXPR: + code = LE_EXPR; + op1 = const_binop (MINUS_EXPR, op1, integer_one_node, 0); + break; + + default: + break; + } + } + + tem = fold_relational_hi_lo (&code, type, &op0, &op1); + if (tem) + return tem; + + if (!wins) + return NULL_TREE; + + return fold_relational_const (code, type, op0, op1); + + case RANGE_EXPR: + /* This could probably be handled. */ + return NULL_TREE; + + case TRUTH_AND_EXPR: + /* If second arg is constant zero, result is zero, but first arg + must be evaluated. */ + if (integer_zerop (op1)) + return omit_one_operand (type, op1, op0); + /* Likewise for first arg, but note that only the TRUTH_AND_EXPR + case will be handled here. */ + if (integer_zerop (op0)) + return omit_one_operand (type, op0, op1); + if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST) + { + int x1 = ! integer_zerop (op0); + int x2 = ! integer_zerop (op1); + + return ((x1 & x2) ? integer_one_node : integer_zero_node); + } + return NULL_TREE; + + case TRUTH_OR_EXPR: + /* If second arg is constant true, result is true, but we must + evaluate first arg. */ + if (TREE_CODE (op1) == INTEGER_CST && ! integer_zerop (op1)) + return omit_one_operand (type, op1, op0); + /* Likewise for first arg, but note this only occurs here for + TRUTH_OR_EXPR. */ + if (TREE_CODE (op0) == INTEGER_CST && ! integer_zerop (op0)) + return omit_one_operand (type, op0, op1); + if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST) + { + int x1 = ! integer_zerop (op0); + int x2 = ! integer_zerop (op1); + + return ((x1 | x2) ? integer_one_node : integer_zero_node); + } + return NULL_TREE; + + case TRUTH_XOR_EXPR: + if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST) + { + int x1 = ! integer_zerop (op0); + int x2 = ! integer_zerop (op1); + + return ((x1 ^ x2) ? integer_one_node : integer_zero_node); + } + return NULL_TREE; + + default: + return NULL_TREE; + } +} + +/* Given the components of a unary expression CODE, TYPE and OP0, + attempt to fold the expression to a constant without modifying + TYPE or OP0. + + If the expression could be simplified to a constant, then return + the constant. If the expression would not be simplified to a + constant, then return NULL_TREE. + + Note this is primarily designed to be called after gimplification + of the tree structures and when op0 is a constant. As a result + of those simplifying assumptions this routine is far simpler than + the generic fold routine. */ + +tree +nondestructive_fold_unary_to_constant (enum tree_code code, tree type, + tree op0) +{ + tree t; + + /* Make sure we have a suitable constant argument. */ + if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR) + { + tree subop; + + if (TREE_CODE (op0) == COMPLEX_CST) + subop = TREE_REALPART (op0); + else + subop = op0; + + if (TREE_CODE (subop) != INTEGER_CST && TREE_CODE (subop) != REAL_CST) + return NULL_TREE; + } + + switch (code) + { + case NOP_EXPR: + case FLOAT_EXPR: + case CONVERT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_CEIL_EXPR: + return fold_convert_const (code, type, op0); + + case NEGATE_EXPR: + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST) + return fold_negate_const (op0, type); + else + return NULL_TREE; + + case ABS_EXPR: + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST) + return fold_abs_const (op0, type); + else + return NULL_TREE; + + case BIT_NOT_EXPR: + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST) + { + t = build_int_2 (~ TREE_INT_CST_LOW (op0), ~ TREE_INT_CST_HIGH (op0)); + TREE_TYPE (t) = type; + force_fit_type (t, 0); + TREE_OVERFLOW (t) = TREE_OVERFLOW (op0); + TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (op0); + return t; + } + else + return NULL_TREE; + + case REALPART_EXPR: + if (TREE_CODE (op0) == COMPLEX_CST) + return TREE_REALPART (op0); + else + return NULL_TREE; + + case IMAGPART_EXPR: + if (TREE_CODE (op0) == COMPLEX_CST) + return TREE_IMAGPART (op0); + else + return NULL_TREE; + + case CONJ_EXPR: + if (TREE_CODE (op0) == COMPLEX_CST + && TREE_CODE (TREE_TYPE (op0)) == COMPLEX_TYPE) + return build_complex (type, TREE_REALPART (op0), + negate_expr (TREE_IMAGPART (op0))); + return NULL_TREE; + + default: + return NULL_TREE; + } +} + +/* If EXP represents referencing an element in a constant string + (either via pointer arithmetic or array indexing), return the + tree representing the value accessed, otherwise return NULL. */ + +tree +fold_read_from_constant_string (tree exp) +{ + if (TREE_CODE (exp) == INDIRECT_REF || TREE_CODE (exp) == ARRAY_REF) + { + tree exp1 = TREE_OPERAND (exp, 0); + tree index; + tree string; + + if (TREE_CODE (exp) == INDIRECT_REF) + { + string = string_constant (exp1, &index); + } + else + { + tree domain = TYPE_DOMAIN (TREE_TYPE (exp1)); + tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node; + index = convert (sizetype, TREE_OPERAND (exp, 1)); + + /* Optimize the special-case of a zero lower bound. + + We convert the low_bound to sizetype to avoid some problems + with constant folding. (E.g. suppose the lower bound is 1, + and its mode is QI. Without the conversion,l (ARRAY + +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1)) + +INDEX), which becomes (ARRAY+255+INDEX). Opps!) */ + if (! integer_zerop (low_bound)) + index = size_diffop (index, convert (sizetype, low_bound)); + + string = exp1; + } + + if (string + && TREE_CODE (string) == STRING_CST + && TREE_CODE (index) == INTEGER_CST + && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0 + && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (string)))) + == MODE_INT) + && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (string)))) == 1)) + return build_int_2 ((TREE_STRING_POINTER (string) + [TREE_INT_CST_LOW (index)]), 0); + } + return NULL; +} + /* Return the tree for neg (ARG0) when ARG0 is known to be either an integer constant or real constant. |