diff options
author | Jakub Jelinek <jakub@redhat.com> | 2016-06-24 13:03:27 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2016-06-24 13:03:27 +0200 |
commit | a86451b9b20415805e6316638c349cce86252893 (patch) | |
tree | 5dbe637ae3f46f81d9ccbd90d3728bb4271209fe /gcc/internal-fn.c | |
parent | 43535362e718a0ecb559eb6b1b90cf7892324f08 (diff) | |
download | gcc-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.c | 60 |
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, |