- 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 build2 (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 = fold_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 fold_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;
-
- /* Fall through. */
-
- case ORDERED_EXPR:
- case UNORDERED_EXPR:
- case UNLT_EXPR:
- case UNLE_EXPR:
- case UNGT_EXPR:
- case UNGE_EXPR:
- case UNEQ_EXPR:
- case LTGT_EXPR:
- 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)
- return constant_boolean_node (true, type);
- 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)
- return constant_boolean_node (false, type);
- return NULL_TREE;
-
- case TRUTH_XOR_EXPR:
- if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST)
- {
- int x = ! integer_zerop (op0) ^ ! integer_zerop (op1);
- return constant_boolean_node (x, type);
- }
- return NULL_TREE;
-
- default:
- return NULL_TREE;
- }