-/* Similarly, but assume that X and Y are the two operands of an EQ_EXPR.
- This constrains the cases in which we may treat this as assignment. */
-
-static void
-record_equality (tree x, tree y)
-{
- tree prev_x = NULL, prev_y = NULL;
-
- if (TREE_CODE (x) == SSA_NAME)
- prev_x = SSA_NAME_VALUE (x);
- if (TREE_CODE (y) == SSA_NAME)
- prev_y = SSA_NAME_VALUE (y);
-
- /* If one of the previous values is invariant, or invariant in more loops
- (by depth), then use that.
- Otherwise it doesn't matter which value we choose, just so
- long as we canonicalize on one value. */
- if (TREE_INVARIANT (y))
- ;
- else if (TREE_INVARIANT (x) || (loop_depth_of_name (x) <= loop_depth_of_name (y)))
- prev_x = x, x = y, y = prev_x, prev_x = prev_y;
- else if (prev_x && TREE_INVARIANT (prev_x))
- x = y, y = prev_x, prev_x = prev_y;
- else if (prev_y && TREE_CODE (prev_y) != VALUE_HANDLE)
- y = prev_y;
-
- /* After the swapping, we must have one SSA_NAME. */
- if (TREE_CODE (x) != SSA_NAME)
- return;
-
- /* For IEEE, -0.0 == 0.0, so we don't necessarily know the sign of a
- variable compared against zero. If we're honoring signed zeros,
- then we cannot record this value unless we know that the value is
- nonzero. */
- if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (x)))
- && (TREE_CODE (y) != REAL_CST
- || REAL_VALUES_EQUAL (dconst0, TREE_REAL_CST (y))))
- return;
-
- record_const_or_copy_1 (x, y, prev_x);
-}
-
-/* Return true, if it is ok to do folding of an associative expression.
- EXP is the tree for the associative expression. */
-
-static inline bool
-unsafe_associative_fp_binop (tree exp)
-{
- enum tree_code code = TREE_CODE (exp);
- return !(!flag_unsafe_math_optimizations
- && (code == MULT_EXPR || code == PLUS_EXPR
- || code == MINUS_EXPR)
- && FLOAT_TYPE_P (TREE_TYPE (exp)));
-}
-
-/* Returns true when STMT is a simple iv increment. It detects the
- following situation:
-
- i_1 = phi (..., i_2)
- i_2 = i_1 +/- ... */
-
-static bool
-simple_iv_increment_p (tree stmt)
-{
- tree lhs, rhs, preinc, phi;
- unsigned i;
-
- if (TREE_CODE (stmt) != MODIFY_EXPR)
- return false;
-
- lhs = TREE_OPERAND (stmt, 0);
- if (TREE_CODE (lhs) != SSA_NAME)
- return false;
-
- rhs = TREE_OPERAND (stmt, 1);
-
- if (TREE_CODE (rhs) != PLUS_EXPR
- && TREE_CODE (rhs) != MINUS_EXPR)
- return false;
-
- preinc = TREE_OPERAND (rhs, 0);
- if (TREE_CODE (preinc) != SSA_NAME)
- return false;
-
- phi = SSA_NAME_DEF_STMT (preinc);
- if (TREE_CODE (phi) != PHI_NODE)
- return false;
-
- for (i = 0; i < (unsigned) PHI_NUM_ARGS (phi); i++)
- if (PHI_ARG_DEF (phi, i) == lhs)
- return true;
-
- return false;
-}
-
-/* STMT is a MODIFY_EXPR for which we were unable to find RHS in the
- hash tables. Try to simplify the RHS using whatever equivalences
- we may have recorded.
-
- If we are able to simplify the RHS, then lookup the simplified form in
- the hash table and return the result. Otherwise return NULL. */
-
-static tree
-simplify_rhs_and_lookup_avail_expr (tree stmt, int insert)
-{
- tree rhs = TREE_OPERAND (stmt, 1);
- enum tree_code rhs_code = TREE_CODE (rhs);
- tree result = NULL;
-
- /* If we have lhs = ~x, look and see if we earlier had x = ~y.
- In which case we can change this statement to be lhs = y.
- Which can then be copy propagated.
-
- Similarly for negation. */
- if ((rhs_code == BIT_NOT_EXPR || rhs_code == NEGATE_EXPR)
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
- {
- /* Get the definition statement for our RHS. */
- tree rhs_def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
-
- /* See if the RHS_DEF_STMT has the same form as our statement. */
- if (TREE_CODE (rhs_def_stmt) == MODIFY_EXPR
- && TREE_CODE (TREE_OPERAND (rhs_def_stmt, 1)) == rhs_code)
- {
- tree rhs_def_operand;
-
- rhs_def_operand = TREE_OPERAND (TREE_OPERAND (rhs_def_stmt, 1), 0);
-
- /* Verify that RHS_DEF_OPERAND is a suitable SSA variable. */
- if (TREE_CODE (rhs_def_operand) == SSA_NAME
- && ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs_def_operand))
- result = update_rhs_and_lookup_avail_expr (stmt,
- rhs_def_operand,
- insert);
- }
- }
-
- /* If we have z = (x OP C1), see if we earlier had x = y OP C2.
- If OP is associative, create and fold (y OP C2) OP C1 which
- should result in (y OP C3), use that as the RHS for the
- assignment. Add minus to this, as we handle it specially below. */
- if ((associative_tree_code (rhs_code) || rhs_code == MINUS_EXPR)
- && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
- && is_gimple_min_invariant (TREE_OPERAND (rhs, 1)))
- {
- tree rhs_def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
-
- /* If the statement defines an induction variable, do not propagate
- its value, so that we do not create overlapping life ranges. */
- if (simple_iv_increment_p (rhs_def_stmt))
- goto dont_fold_assoc;
-
- /* See if the RHS_DEF_STMT has the same form as our statement. */
- if (TREE_CODE (rhs_def_stmt) == MODIFY_EXPR)
- {
- tree rhs_def_rhs = TREE_OPERAND (rhs_def_stmt, 1);
- enum tree_code rhs_def_code = TREE_CODE (rhs_def_rhs);
-
- if ((rhs_code == rhs_def_code && unsafe_associative_fp_binop (rhs))
- || (rhs_code == PLUS_EXPR && rhs_def_code == MINUS_EXPR)
- || (rhs_code == MINUS_EXPR && rhs_def_code == PLUS_EXPR))
- {
- tree def_stmt_op0 = TREE_OPERAND (rhs_def_rhs, 0);
- tree def_stmt_op1 = TREE_OPERAND (rhs_def_rhs, 1);
-
- if (TREE_CODE (def_stmt_op0) == SSA_NAME
- && ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def_stmt_op0)
- && is_gimple_min_invariant (def_stmt_op1))
- {
- tree outer_const = TREE_OPERAND (rhs, 1);
- tree type = TREE_TYPE (TREE_OPERAND (stmt, 0));
- tree t;
-
- /* If we care about correct floating point results, then
- don't fold x + c1 - c2. Note that we need to take both
- the codes and the signs to figure this out. */
- if (FLOAT_TYPE_P (type)
- && !flag_unsafe_math_optimizations
- && (rhs_def_code == PLUS_EXPR
- || rhs_def_code == MINUS_EXPR))
- {
- bool neg = false;
-
- neg ^= (rhs_code == MINUS_EXPR);
- neg ^= (rhs_def_code == MINUS_EXPR);
- neg ^= real_isneg (TREE_REAL_CST_PTR (outer_const));
- neg ^= real_isneg (TREE_REAL_CST_PTR (def_stmt_op1));
-
- if (neg)
- goto dont_fold_assoc;
- }
-
- /* Ho hum. So fold will only operate on the outermost
- thingy that we give it, so we have to build the new
- expression in two pieces. This requires that we handle
- combinations of plus and minus. */
- if (rhs_def_code != rhs_code)
- {
- if (rhs_def_code == MINUS_EXPR)
- t = build (MINUS_EXPR, type, outer_const, def_stmt_op1);
- else
- t = build (MINUS_EXPR, type, def_stmt_op1, outer_const);
- rhs_code = PLUS_EXPR;
- }
- else if (rhs_def_code == MINUS_EXPR)
- t = build (PLUS_EXPR, type, def_stmt_op1, outer_const);
- else
- t = build (rhs_def_code, type, def_stmt_op1, outer_const);
- t = local_fold (t);
- t = build (rhs_code, type, def_stmt_op0, t);
- t = local_fold (t);
-
- /* If the result is a suitable looking gimple expression,
- then use it instead of the original for STMT. */
- if (TREE_CODE (t) == SSA_NAME
- || (UNARY_CLASS_P (t)
- && TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME)
- || ((BINARY_CLASS_P (t) || COMPARISON_CLASS_P (t))
- && TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME
- && is_gimple_val (TREE_OPERAND (t, 1))))
- result = update_rhs_and_lookup_avail_expr (stmt, t, insert);
- }
- }
- }
- dont_fold_assoc:;
- }
-
- /* Optimize *"foo" into 'f'. This is done here rather than
- in fold to avoid problems with stuff like &*"foo". */
- if (TREE_CODE (rhs) == INDIRECT_REF || TREE_CODE (rhs) == ARRAY_REF)
- {
- tree t = fold_read_from_constant_string (rhs);
-
- if (t)
- result = update_rhs_and_lookup_avail_expr (stmt, t, insert);
- }
-
- return result;
-}
-
-/* COND is a condition of the form:
-
- x == const or x != const
-
- Look back to x's defining statement and see if x is defined as
-
- x = (type) y;
-
- If const is unchanged if we convert it to type, then we can build
- the equivalent expression:
-
-
- y == const or y != const
-
- Which may allow further optimizations.
-
- Return the equivalent comparison or NULL if no such equivalent comparison
- was found. */
-
-static tree
-find_equivalent_equality_comparison (tree cond)
-{
- tree op0 = TREE_OPERAND (cond, 0);
- tree op1 = TREE_OPERAND (cond, 1);
- tree def_stmt = SSA_NAME_DEF_STMT (op0);
-
- /* OP0 might have been a parameter, so first make sure it
- was defined by a MODIFY_EXPR. */
- if (def_stmt && TREE_CODE (def_stmt) == MODIFY_EXPR)
- {
- tree def_rhs = TREE_OPERAND (def_stmt, 1);
-
-
- /* If either operand to the comparison is a pointer to
- a function, then we can not apply this optimization
- as some targets require function pointers to be
- canonicalized and in this case this optimization would
- eliminate a necessary canonicalization. */
- if ((POINTER_TYPE_P (TREE_TYPE (op0))
- && TREE_CODE (TREE_TYPE (TREE_TYPE (op0))) == FUNCTION_TYPE)
- || (POINTER_TYPE_P (TREE_TYPE (op1))
- && TREE_CODE (TREE_TYPE (TREE_TYPE (op1))) == FUNCTION_TYPE))
- return NULL;
-
- /* Now make sure the RHS of the MODIFY_EXPR is a typecast. */
- if ((TREE_CODE (def_rhs) == NOP_EXPR
- || TREE_CODE (def_rhs) == CONVERT_EXPR)
- && TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME)
- {
- tree def_rhs_inner = TREE_OPERAND (def_rhs, 0);
- tree def_rhs_inner_type = TREE_TYPE (def_rhs_inner);
- tree new;
-
- if (TYPE_PRECISION (def_rhs_inner_type)
- > TYPE_PRECISION (TREE_TYPE (def_rhs)))
- return NULL;
-
- /* If the inner type of the conversion is a pointer to
- a function, then we can not apply this optimization
- as some targets require function pointers to be
- canonicalized. This optimization would result in
- canonicalization of the pointer when it was not originally
- needed/intended. */
- if (POINTER_TYPE_P (def_rhs_inner_type)
- && TREE_CODE (TREE_TYPE (def_rhs_inner_type)) == FUNCTION_TYPE)
- return NULL;
-
- /* What we want to prove is that if we convert OP1 to
- the type of the object inside the NOP_EXPR that the
- result is still equivalent to SRC.
-
- If that is true, the build and return new equivalent
- condition which uses the source of the typecast and the
- new constant (which has only changed its type). */
- new = build1 (TREE_CODE (def_rhs), def_rhs_inner_type, op1);
- new = local_fold (new);
- if (is_gimple_val (new) && tree_int_cst_equal (new, op1))
- return build (TREE_CODE (cond), TREE_TYPE (cond),
- def_rhs_inner, new);
- }
- }
- return NULL;
-}
-
-/* STMT is a COND_EXPR for which we could not trivially determine its
- result. This routine attempts to find equivalent forms of the
- condition which we may be able to optimize better. It also
- uses simple value range propagation to optimize conditionals. */
-
-static tree
-simplify_cond_and_lookup_avail_expr (tree stmt,
- stmt_ann_t ann,
- int insert)
-{
- tree cond = COND_EXPR_COND (stmt);
-
- if (COMPARISON_CLASS_P (cond))
- {
- tree op0 = TREE_OPERAND (cond, 0);
- tree op1 = TREE_OPERAND (cond, 1);
-
- if (TREE_CODE (op0) == SSA_NAME && is_gimple_min_invariant (op1))
- {
- int limit;
- tree low, high, cond_low, cond_high;
- int lowequal, highequal, swapped, no_overlap, subset, cond_inverted;
- VEC(vrp_element_p,heap) **vrp_records;
- struct vrp_element *element;
- struct vrp_hash_elt vrp_hash_elt, *vrp_hash_elt_p;
- void **slot;
-
- /* First see if we have test of an SSA_NAME against a constant
- where the SSA_NAME is defined by an earlier typecast which
- is irrelevant when performing tests against the given
- constant. */
- if (TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR)
- {
- tree new_cond = find_equivalent_equality_comparison (cond);
-
- if (new_cond)
- {
- /* Update the statement to use the new equivalent
- condition. */
- COND_EXPR_COND (stmt) = new_cond;
-
- /* If this is not a real stmt, ann will be NULL and we
- avoid processing the operands. */
- if (ann)
- mark_stmt_modified (stmt);
-
- /* Lookup the condition and return its known value if it
- exists. */
- new_cond = lookup_avail_expr (stmt, insert);
- if (new_cond)
- return new_cond;
-
- /* The operands have changed, so update op0 and op1. */
- op0 = TREE_OPERAND (cond, 0);
- op1 = TREE_OPERAND (cond, 1);
- }
- }