aboutsummaryrefslogtreecommitdiff
path: root/gcc/internal-fn.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2013-12-16 19:44:51 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2013-12-16 19:44:51 +0100
commit97286431624c245b32ae05c33e9af2876eda55ee (patch)
tree41dc923f102f79eeb2f9561e2cba92cf1201e9c7 /gcc/internal-fn.c
parent91c5ee5b4ac9c85b6cbf596dc7917910b0d7b1b3 (diff)
downloadgcc-97286431624c245b32ae05c33e9af2876eda55ee.zip
gcc-97286431624c245b32ae05c33e9af2876eda55ee.tar.gz
gcc-97286431624c245b32ae05c33e9af2876eda55ee.tar.bz2
internal-fn.c: Include stringpool.h and tree-ssanames.h.
* internal-fn.c: Include stringpool.h and tree-ssanames.h. (ubsan_expand_si_overflow_addsub_check): In the generic expansion, try to improve generated code if one of the arguments is constant or get_range_info says that one of the argument is always negative or always non-negative. * tree-vrp.c (simplify_internal_call_using_ranges): New function. (simplify_stmt_using_ranges): Call it. From-SVN: r206025
Diffstat (limited to 'gcc/internal-fn.c')
-rw-r--r--gcc/internal-fn.c75
1 files changed, 65 insertions, 10 deletions
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index a0874d4..a0dbad1 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -34,6 +34,8 @@ along with GCC; see the file COPYING3. If not see
#include "ubsan.h"
#include "target.h"
#include "predict.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
/* The names of each internal function, indexed by function number. */
const char *const internal_fn_name_array[] = {
@@ -211,28 +213,81 @@ ubsan_expand_si_overflow_addsub_check (tree_code code, gimple stmt)
if (icode == CODE_FOR_nothing)
{
rtx sub_check = gen_label_rtx ();
+ int pos_neg = 3;
/* Compute the operation. On RTL level, the addition is always
unsigned. */
res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
+ /* If we can prove one of the arguments is always non-negative
+ or always negative, we can do just one comparison and
+ conditional jump instead of 2 at runtime, 3 present in the
+ emitted code. If one of the arguments is CONST_INT, all we
+ need is to make sure it is op1, then the first
+ emit_cmp_and_jump_insns will be just folded. Otherwise try
+ to use range info if available. */
+ if (CONST_INT_P (op0))
+ {
+ rtx tem = op0;
+ op0 = op1;
+ op1 = tem;
+ }
+ else if (CONST_INT_P (op1))
+ ;
+ else if (TREE_CODE (arg0) == SSA_NAME)
+ {
+ double_int arg0_min, arg0_max;
+ if (get_range_info (arg0, &arg0_min, &arg0_max) == VR_RANGE)
+ {
+ if (!arg0_min.is_negative ())
+ pos_neg = 1;
+ else if (arg0_max.is_negative ())
+ pos_neg = 2;
+ }
+ if (pos_neg != 3)
+ {
+ rtx tem = op0;
+ op0 = op1;
+ op1 = tem;
+ }
+ }
+ if (pos_neg == 3 && !CONST_INT_P (op1) && TREE_CODE (arg1) == SSA_NAME)
+ {
+ double_int arg1_min, arg1_max;
+ if (get_range_info (arg1, &arg1_min, &arg1_max) == VR_RANGE)
+ {
+ if (!arg1_min.is_negative ())
+ pos_neg = 1;
+ else if (arg1_max.is_negative ())
+ pos_neg = 2;
+ }
+ }
+
/* If the op1 is negative, we have to use a different check. */
- emit_cmp_and_jump_insns (op1, const0_rtx, LT, NULL_RTX, mode,
- false, sub_check, PROB_EVEN);
+ if (pos_neg == 3)
+ emit_cmp_and_jump_insns (op1, const0_rtx, LT, NULL_RTX, mode,
+ false, sub_check, PROB_EVEN);
/* Compare the result of the operation with one of the operands. */
- emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? GE : LE,
- NULL_RTX, mode, false, done_label,
- PROB_VERY_LIKELY);
+ if (pos_neg & 1)
+ emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? GE : LE,
+ NULL_RTX, mode, false, done_label,
+ PROB_VERY_LIKELY);
+
/* If we get here, we have to print the error. */
- emit_jump (do_error);
+ if (pos_neg == 3)
+ {
+ emit_jump (do_error);
+
+ emit_label (sub_check);
+ }
- emit_label (sub_check);
/* We have k = a + b for b < 0 here. k <= a must hold. */
- emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? LE : GE,
- NULL_RTX, mode, false, done_label,
- PROB_VERY_LIKELY);
+ if (pos_neg & 2)
+ emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? LE : GE,
+ NULL_RTX, mode, false, done_label,
+ PROB_VERY_LIKELY);
}
emit_label (do_error);