aboutsummaryrefslogtreecommitdiff
path: root/gcc/internal-fn.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2016-06-24 13:03:27 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2016-06-24 13:03:27 +0200
commita86451b9b20415805e6316638c349cce86252893 (patch)
tree5dbe637ae3f46f81d9ccbd90d3728bb4271209fe /gcc/internal-fn.c
parent43535362e718a0ecb559eb6b1b90cf7892324f08 (diff)
downloadgcc-a86451b9b20415805e6316638c349cce86252893.zip
gcc-a86451b9b20415805e6316638c349cce86252893.tar.gz
gcc-a86451b9b20415805e6316638c349cce86252893.tar.bz2
internal-fn.c (expand_arith_set_overflow): New function.
* internal-fn.c (expand_arith_set_overflow): New function. (expand_addsub_overflow, expand_neg_overflow, expand_mul_overflow): Use it. (expand_arith_overflow_result_store): Likewise. Handle precision smaller than mode precision. * tree-vrp.c (extract_range_basic): For imag part, handle properly signed 1-bit precision result. * doc/extend.texi (__builtin_add_overflow): Document that last argument can't be pointer to enumerated or boolean type. (__builtin_add_overflow_p): Document that last argument can't have enumerated or boolean type. * c-common.c (check_builtin_function_arguments): Require last argument of BUILT_IN_*_OVERFLOW_P to have INTEGER_TYPE type. Adjust wording of diagnostics for BUILT_IN_*_OVERLFLOW if the last argument is pointer to enumerated or boolean type. * c-c++-common/builtin-arith-overflow-1.c (generic_wrong_type, f3, f4): Adjust expected diagnostics. * c-c++-common/torture/builtin-arith-overflow.h (TP): New macro. (T): If OVFP is defined, redefine to TP. * c-c++-common/torture/builtin-arith-overflow-12.c: Adjust comment. * c-c++-common/torture/builtin-arith-overflow-p-1.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-2.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-3.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-4.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-5.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-6.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-7.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-8.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-9.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-10.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-11.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-12.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-13.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-14.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-15.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-16.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-17.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-18.c: New test. * c-c++-common/torture/builtin-arith-overflow-p-19.c: New test. * g++.dg/ext/builtin-arith-overflow-1.C: Pass 0 instead of C as last argument to __builtin_add_overflow_p. From-SVN: r237754
Diffstat (limited to 'gcc/internal-fn.c')
-rw-r--r--gcc/internal-fn.c60
1 files changed, 51 insertions, 9 deletions
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index c867ddc..de850fd 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -405,9 +405,23 @@ get_min_precision (tree arg, signop sign)
return prec + (orig_sign != sign);
}
+/* Helper for expand_*_overflow. Set the __imag__ part to true
+ (1 except for signed:1 type, in which case store -1). */
+
+static void
+expand_arith_set_overflow (tree lhs, rtx target)
+{
+ if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs))) == 1
+ && !TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs))))
+ write_complex_part (target, constm1_rtx, true);
+ else
+ write_complex_part (target, const1_rtx, true);
+}
+
/* 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,
@@ -424,7 +438,35 @@ expand_arith_overflow_result_store (tree lhs, rtx target,
do_compare_rtx_and_jump (res, convert_modes (mode, tgtmode, lres, uns),
EQ, true, mode, NULL_RTX, NULL, done_label,
PROB_VERY_LIKELY);
- write_complex_part (target, const1_rtx, true);
+ expand_arith_set_overflow (lhs, target);
+ 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);
+ expand_arith_set_overflow (lhs, target);
emit_label (done_label);
}
write_complex_part (target, lres, false);
@@ -861,7 +903,7 @@ expand_addsub_overflow (location_t loc, tree_code code, tree lhs,
do_pending_stack_adjust ();
}
else if (lhs)
- write_complex_part (target, const1_rtx, true);
+ expand_arith_set_overflow (lhs, target);
/* We're done. */
emit_label (done_label);
@@ -956,7 +998,7 @@ expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan)
do_pending_stack_adjust ();
}
else if (lhs)
- write_complex_part (target, const1_rtx, true);
+ expand_arith_set_overflow (lhs, target);
/* We're done. */
emit_label (done_label);
@@ -1082,7 +1124,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
NULL, do_main_label, PROB_VERY_LIKELY);
do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
NULL, do_main_label, PROB_VERY_LIKELY);
- write_complex_part (target, const1_rtx, true);
+ expand_arith_set_overflow (lhs, target);
emit_label (do_main_label);
goto do_main;
default:
@@ -1213,7 +1255,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
is, thus we can keep do_main code oring in overflow as is. */
do_compare_rtx_and_jump (tem, const0_rtx, EQ, true, mode, NULL_RTX,
NULL, do_main_label, PROB_VERY_LIKELY);
- write_complex_part (target, const1_rtx, true);
+ expand_arith_set_overflow (lhs, target);
emit_label (do_main_label);
goto do_main;
default:
@@ -1617,7 +1659,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
do_pending_stack_adjust ();
}
else if (lhs)
- write_complex_part (target, const1_rtx, true);
+ expand_arith_set_overflow (lhs, target);
/* We're done. */
emit_label (done_label);
@@ -1628,7 +1670,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
rtx_code_label *all_done_label = gen_label_rtx ();
do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
NULL, all_done_label, PROB_VERY_LIKELY);
- write_complex_part (target, const1_rtx, true);
+ expand_arith_set_overflow (lhs, target);
emit_label (all_done_label);
}
@@ -1639,7 +1681,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
rtx_code_label *set_noovf = gen_label_rtx ();
do_compare_rtx_and_jump (op1, const0_rtx, GE, false, mode, NULL_RTX,
NULL, all_done_label, PROB_VERY_LIKELY);
- write_complex_part (target, const1_rtx, true);
+ expand_arith_set_overflow (lhs, target);
do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
NULL, set_noovf, PROB_VERY_LIKELY);
do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,