@@ -1303,11 +1303,21 @@ cxx_eval_internal_function (const conste
{
location_t loc = EXPR_LOC_OR_LOC (t, input_location);
tree type = TREE_TYPE (TREE_TYPE (t));
- tree result = fold_binary_loc (loc, opcode, type,
- fold_convert_loc (loc, type, arg0),
- fold_convert_loc (loc, type, arg1));
+ tree itype = type;
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ itype = build_nonstandard_integer_type (1, 1);
+ tree result = fold_binary_loc (loc, opcode, itype,
+ fold_convert_loc (loc, itype, arg0),
+ fold_convert_loc (loc, itype, arg1));
tree ovf
= build_int_cst (type, arith_overflowed_p (opcode, type, arg0, arg1));
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ {
+ result = fold_binary_loc (loc, NE_EXPR, type, result,
+ build_int_cst (itype, 0));
+ if (integer_onep (ovf))
+ result = ovf;
+ }
/* Reset TREE_OVERFLOW to avoid warnings for the overflow. */
if (TREE_OVERFLOW (result))
TREE_OVERFLOW (result) = 0;
@@ -407,7 +407,8 @@ get_min_precision (tree arg, signop sign
/* Helper for expand_*_overflow. Store RES into the __real__ part
of TARGET. If RES has larger MODE than __real__ part of TARGET,
- set the __imag__ part to 1 if RES doesn't fit into it. */
+ set the __imag__ part to 1 if RES doesn't fit into it. Similarly
+ if LHS has smaller precision than its mode. */
static void
expand_arith_overflow_result_store (tree lhs, rtx target,
@@ -427,6 +428,40 @@ expand_arith_overflow_result_store (tree
write_complex_part (target, const1_rtx, true);
emit_label (done_label);
}
+ int prec = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs)));
+ int tgtprec = GET_MODE_PRECISION (tgtmode);
+ if (prec < tgtprec)
+ {
+ rtx_code_label *done_label = gen_label_rtx ();
+ int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
+ res = lres;
+ if (uns)
+ {
+ rtx mask
+ = immed_wide_int_const (wi::shifted_mask (0, prec, false, tgtprec),
+ tgtmode);
+ lres = expand_simple_binop (tgtmode, AND, res, mask, NULL_RTX,
+ true, OPTAB_DIRECT);
+ }
+ else
+ {
+ lres = expand_shift (LSHIFT_EXPR, tgtmode, res, tgtprec - prec,
+ NULL_RTX, 1);
+ lres = expand_shift (RSHIFT_EXPR, tgtmode, lres, tgtprec - prec,
+ NULL_RTX, 0);
+ }
+ do_compare_rtx_and_jump (res, lres,
+ EQ, true, tgtmode, NULL_RTX, NULL, done_label,
+ PROB_VERY_LIKELY);
+ write_complex_part (target, const1_rtx, true);
+ emit_label (done_label);
+ }
+ /* For bool, make sure the result is 1 whenever overflow is 1, because
+ cast to bool is != comparison of the infinite precision result with 0. */
+ if (TREE_CODE (TREE_TYPE (TREE_TYPE (lhs))) == BOOLEAN_TYPE)
+ lres = expand_simple_binop (tgtmode, IOR, lres,
+ read_complex_part (target, true), NULL_RTX,
+ true, OPTAB_DIRECT);
write_complex_part (target, lres, false);
}
@@ -1139,6 +1139,12 @@ maybe_optimize_arith_overflow (gimple_st
if (lhs == NULL || TREE_CODE (lhs) != SSA_NAME)
return;
+ tree type = TREE_TYPE (TREE_TYPE (lhs));
+ /* Punt on arith overflow to bool, there we always need the overflow
+ computation. */
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ return;
+
imm_use_iterator imm_iter;
use_operand_p use_p;
bool has_debug_uses = false;
@@ -1166,7 +1172,6 @@ maybe_optimize_arith_overflow (gimple_st
tree arg0 = gimple_call_arg (stmt, 0);
tree arg1 = gimple_call_arg (stmt, 1);
location_t loc = gimple_location (stmt);
- tree type = TREE_TYPE (TREE_TYPE (lhs));
tree utype = type;
if (!TYPE_UNSIGNED (type))
utype = build_nonstandard_integer_type (TYPE_PRECISION (type), 1);
@@ -118,14 +118,14 @@ generic_wrong_type (int a, int b)
{
void *p = 0;
double d = 0;
- int x = __builtin_add_overflow (a, b, p); /* { dg-error "does not have pointer to integer type" } */
- x += __builtin_sub_overflow (a, b, &p); /* { dg-error "does not have pointer to integer type" } */
- x += __builtin_mul_overflow (a, b, &d); /* { dg-error "does not have pointer to integer type" } */
+ int x = __builtin_add_overflow (a, b, p); /* { dg-error "does not have pointer to integral type" } */
+ x += __builtin_sub_overflow (a, b, &p); /* { dg-error "does not have pointer to integral type" } */
+ x += __builtin_mul_overflow (a, b, &d); /* { dg-error "does not have pointer to integral type" } */
/* Also verify literal arguments. */
- x += __builtin_add_overflow (1, 1, p); /* { dg-error "does not have pointer to integer type" } */
- x += __builtin_sub_overflow (1, 1, &p); /* { dg-error "does not have pointer to integer type" } */
- x += __builtin_mul_overflow (1, 1, &d); /* { dg-error "does not have pointer to integer type" } */
+ x += __builtin_add_overflow (1, 1, p); /* { dg-error "does not have pointer to integral type" } */
+ x += __builtin_sub_overflow (1, 1, &p); /* { dg-error "does not have pointer to integral type" } */
+ x += __builtin_mul_overflow (1, 1, &d); /* { dg-error "does not have pointer to integral type" } */
return x;
}
@@ -236,7 +236,7 @@ f3 (float fa, int a, _Complex long int c
x += __builtin_sub_overflow_p (ca, b, eb); /* { dg-error "argument 1 in call to function\[^\n\r]*does not have integral type" } */
x += __builtin_mul_overflow_p (a, fb, bb); /* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */
x += __builtin_add_overflow_p (a, pb, a); /* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */
- x += __builtin_sub_overflow_p (a, eb, eb);
+ x += __builtin_sub_overflow_p (a, eb, eb); /* { dg-error "argument 3 in call to function\[^\n\r]*has enumerated type" } */
x += __builtin_mul_overflow_p (a, bb, bb);
x += __builtin_add_overflow_p (a, b, fa); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */
x += __builtin_sub_overflow_p (a, b, ca); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */
@@ -247,11 +247,11 @@ f3 (float fa, int a, _Complex long int c
int
f4 (float *fp, double *dp, _Complex int *cp, enum E *ep, bool *bp, long long int *llp)
{
- int x = __builtin_add_overflow (1, 2, fp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
- x += __builtin_sub_overflow (1, 2, dp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
- x += __builtin_mul_overflow (1, 2, cp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
- x += __builtin_add_overflow (1, 2, ep); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
- x += __builtin_sub_overflow (1, 2, bp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integer type" } */
+ int x = __builtin_add_overflow (1, 2, fp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integral type" } */
+ x += __builtin_sub_overflow (1, 2, dp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integral type" } */
+ x += __builtin_mul_overflow (1, 2, cp); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have pointer to integral type" } */
+ x += __builtin_add_overflow (1, 2, ep); /* { dg-error "argument 3 in call to function\[^\n\r]*has pointer to enumerated type" } */
+ x += __builtin_sub_overflow (1, 2, bp);
x += __builtin_mul_overflow (1, 2, llp);
return x;
}
@@ -1,11 +1,11 @@
// { dg-do compile }
-enum A { B = 1, C = 2, D = __builtin_add_overflow_p (B, C, C) };
-int e[__builtin_add_overflow_p (B, C, C) + 1];
+enum A { B = 1, C = 2, D = __builtin_add_overflow_p (B, C, 0) };
+int e[__builtin_add_overflow_p (B, C, 0) + 1];
template <int N> int foo (int);
void
bar ()
{
- foo <__builtin_add_overflow_p (B, C, C) + 1> (0);
+ foo <__builtin_add_overflow_p (B, C, 0) + 1> (0);
}
@@ -3707,7 +3707,7 @@ match_uaddsub_overflow (gimple_stmt_iter
gimple *use_stmt;
gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR);
- if (!INTEGRAL_TYPE_P (type)
+ if (TREE_CODE (type) != INTEGER_TYPE
|| !TYPE_UNSIGNED (type)
|| has_zero_uses (lhs)
|| has_single_use (lhs)
@@ -3226,15 +3226,28 @@ gimple_fold_call (gimple_stmt_iterator *
else if (TREE_CODE (arg0) == INTEGER_CST
&& TREE_CODE (arg1) == INTEGER_CST)
{
- if (cplx_result)
+ if (!cplx_result)
+ result = int_const_binop (subcode, arg0, arg1);
+ else if (TREE_CODE (type) == BOOLEAN_TYPE)
+ {
+ tree itype = build_nonstandard_integer_type (1, 1);
+ result = int_const_binop (subcode,
+ fold_convert (itype, arg0),
+ fold_convert (itype, arg1));
+ result = fold_build2 (NE_EXPR, type, result,
+ build_int_cst (itype, 0));
+ }
+ else
result = int_const_binop (subcode, fold_convert (type, arg0),
fold_convert (type, arg1));
- else
- result = int_const_binop (subcode, arg0, arg1);
if (result && arith_overflowed_p (subcode, type, arg0, arg1))
{
if (cplx_result)
- overflow = build_one_cst (type);
+ {
+ overflow = build_one_cst (type);
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ result = overflow;
+ }
else
result = NULL_TREE;
}
@@ -3249,7 +3262,11 @@ gimple_fold_call (gimple_stmt_iterator *
{
if (arith_overflowed_p (PLUS_EXPR, type, result,
integer_zero_node))
- overflow = build_one_cst (type);
+ {
+ overflow = build_one_cst (type);
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ result = overflow;
+ }
}
else if ((!TYPE_UNSIGNED (TREE_TYPE (result))
&& TYPE_UNSIGNED (type))
@@ -3259,7 +3276,16 @@ gimple_fold_call (gimple_stmt_iterator *
&& !TYPE_UNSIGNED (type)))))
result = NULL_TREE;
if (result)
- result = fold_convert (type, result);
+ {
+ if (TREE_CODE (type) != BOOLEAN_TYPE
+ || TREE_CODE (TREE_TYPE (result)) == BOOLEAN_TYPE)
+ result = fold_convert (type, result);
+ else
+ result
+ = fold_build2 (NE_EXPR, type, result,
+ build_int_cst (TREE_TYPE (result),
+ 0));
+ }
}
}
}
@@ -9983,10 +9983,16 @@ check_builtin_function_arguments (locati
return false;
}
if (TREE_CODE (TREE_TYPE (args[2])) != POINTER_TYPE
- || TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) != INTEGER_TYPE)
+ || !INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (args[2]))))
{
error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
- "does not have pointer to integer type", fndecl);
+ "does not have pointer to integral type", fndecl);
+ return false;
+ }
+ else if (TREE_CODE (TREE_TYPE (TREE_TYPE (args[2]))) == ENUMERAL_TYPE)
+ {
+ error_at (ARG_LOCATION (2), "argument 3 in call to function %qE "
+ "has pointer to enumerated type", fndecl);
return false;
}
return true;
@@ -10006,6 +10012,12 @@ check_builtin_function_arguments (locati
"%qE does not have integral type", i + 1, fndecl);
return false;
}
+ if (TREE_CODE (TREE_TYPE (args[2])) == ENUMERAL_TYPE)
+ {
+ error_at (ARG_LOCATION (2), "argument 3 in call to function "
+ "%qE has enumerated type", fndecl);
+ return false;
+ }
return true;
}
return false;
@@ -9833,8 +9833,8 @@ performed in infinite signed precision,
behavior for all argument values.
The first built-in function allows arbitrary integral types for operands and
-the result type must be pointer to some integer type, the rest of the built-in
-functions have explicit integer types.
+the result type must be pointer to some integral type other than enumerated type,
+the rest of the built-in functions have explicit integer types.
The compiler will attempt to use hardware instructions to implement
these built-in functions where possible, like conditional jump on overflow
@@ -9879,7 +9879,8 @@ would overflow.
These built-in functions are similar to @code{__builtin_add_overflow},
@code{__builtin_sub_overflow}, or @code{__builtin_mul_overflow}, except that
they don't store the result of the arithmetic operation anywhere and the
-last argument is not a pointer, but some integral expression.
+last argument is not a pointer, but some expression with integral type other
+than enumerated type.
The built-in functions promote the first two operands into infinite precision signed type
and perform addition on those promoted operands. The result is then
@@ -4019,6 +4019,8 @@ extract_range_basic (value_range *vr, gi
set_value_range (vr, VR_RANGE, build_int_cst (type, 0),
build_int_cst (type, 1), NULL);
}
+ else if (TREE_CODE (type) == BOOLEAN_TYPE)
+ return;
else if (types_compatible_p (type, TREE_TYPE (op0))
&& types_compatible_p (type, TREE_TYPE (op1)))
{