diff options
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index f96427f411c..5d38aabf312 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -418,9 +418,11 @@ negate_expr_p (tree t) && TYPE_OVERFLOW_WRAPS (type)); case FIXED_CST: - case NEGATE_EXPR: return true; + case NEGATE_EXPR: + return !TYPE_OVERFLOW_SANITIZED (type); + case REAL_CST: /* We want to canonicalize to positive real constants. Pretend that only negative ones can be easily negated. */ @@ -566,7 +568,9 @@ fold_negate_expr (location_t loc, tree t) case INTEGER_CST: tem = fold_negate_const (t, type); if (TREE_OVERFLOW (tem) == TREE_OVERFLOW (t) - || !TYPE_OVERFLOW_TRAPS (type)) + || (!TYPE_OVERFLOW_TRAPS (type) + && TYPE_OVERFLOW_WRAPS (type)) + || (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0) return tem; break; @@ -623,7 +627,9 @@ fold_negate_expr (location_t loc, tree t) break; case NEGATE_EXPR: - return TREE_OPERAND (t, 0); + if (!TYPE_OVERFLOW_SANITIZED (type)) + return TREE_OPERAND (t, 0); + break; case PLUS_EXPR: if (!HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type)) @@ -4732,8 +4738,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type, case GE_EXPR: case GT_EXPR: if (TYPE_UNSIGNED (TREE_TYPE (arg1))) - arg1 = fold_convert_loc (loc, signed_type_for - (TREE_TYPE (arg1)), arg1); + break; tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, tem)); case UNLE_EXPR: @@ -4743,8 +4748,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type, case LE_EXPR: case LT_EXPR: if (TYPE_UNSIGNED (TREE_TYPE (arg1))) - arg1 = fold_convert_loc (loc, signed_type_for - (TREE_TYPE (arg1)), arg1); + break; tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); return negate_expr (fold_convert_loc (loc, type, tem)); default: @@ -8322,9 +8326,14 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) && integer_onep (TREE_OPERAND (arg0, 1))) || (TREE_CODE (arg0) == PLUS_EXPR && integer_all_onesp (TREE_OPERAND (arg0, 1))))) - return fold_build1_loc (loc, NEGATE_EXPR, type, - fold_convert_loc (loc, type, - TREE_OPERAND (arg0, 0))); + { + /* Perform the negation in ARG0's type and only then convert + to TYPE as to avoid introducing undefined behavior. */ + tree t = fold_build1_loc (loc, NEGATE_EXPR, + TREE_TYPE (TREE_OPERAND (arg0, 0)), + TREE_OPERAND (arg0, 0)); + return fold_convert_loc (loc, type, t); + } /* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify. */ else if (TREE_CODE (arg0) == BIT_XOR_EXPR && (tem = fold_unary_loc (loc, BIT_NOT_EXPR, type, @@ -10870,14 +10879,20 @@ fold_binary_loc (location_t loc, } } /* A - (-B) -> A + B */ - if (TREE_CODE (arg1) == NEGATE_EXPR) + if (TREE_CODE (arg1) == NEGATE_EXPR + && (!INTEGRAL_TYPE_P (type) + || TYPE_OVERFLOW_WRAPS (type) + || (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)) return fold_build2_loc (loc, PLUS_EXPR, type, op0, fold_convert_loc (loc, type, TREE_OPERAND (arg1, 0))); /* (-A) - B -> (-B) - A where B is easily negated and we can swap. */ if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1) - && reorder_operands_p (arg0, arg1)) + && reorder_operands_p (arg0, arg1) + && (!INTEGRAL_TYPE_P (type) + || TYPE_OVERFLOW_WRAPS (type) + || (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)) return fold_build2_loc (loc, MINUS_EXPR, type, fold_convert_loc (loc, type, negate_expr (arg1)), @@ -11021,6 +11036,9 @@ fold_binary_loc (location_t loc, /* A - B -> A + (-B) if B is easily negatable. */ if (negate_expr_p (arg1) + && (!INTEGRAL_TYPE_P (type) + || TYPE_OVERFLOW_WRAPS (type) + || (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0) && ((FLOAT_TYPE_P (type) /* Avoid this transformation if B is a positive REAL_CST. */ && (TREE_CODE (arg1) != REAL_CST |