]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
internal-fn.c: Include stringpool.h and tree-ssanames.h.
authorJakub Jelinek <jakub@redhat.com>
Mon, 16 Dec 2013 18:44:51 +0000 (19:44 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 16 Dec 2013 18:44:51 +0000 (19:44 +0100)
* 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

gcc/ChangeLog
gcc/internal-fn.c
gcc/tree-vrp.c

index 941753aa2b297d5dae9732204ae38556651ca924..25f85d2cea49845acddef6b1179c7e5bb403f4e1 100644 (file)
@@ -1,3 +1,13 @@
+2013-12-16  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2013-12-16  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR rtl-optimization/59466
index a0874d467b45290f0fc61006b15db7fd7a5e44f1..a0dbad139a07ca247df99932e2416ce33f6cef6f 100644 (file)
@@ -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);
index 8ab6d767f2579752c7093c287be75f119f63aacb..4de7c4d9199b22c4367ecb9aeb50579dc722fae4 100644 (file)
@@ -9299,6 +9299,68 @@ simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
   return true;
 }
 
+/* Simplify an internal fn call using ranges if possible.  */
+
+static bool
+simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
+{
+  enum tree_code subcode;
+  switch (gimple_call_internal_fn (stmt))
+    {
+    case IFN_UBSAN_CHECK_ADD:
+      subcode = PLUS_EXPR;
+      break;
+    case IFN_UBSAN_CHECK_SUB:
+      subcode = MINUS_EXPR;
+      break;
+    case IFN_UBSAN_CHECK_MUL:
+      subcode = MULT_EXPR;
+      break;
+    default:
+      return false;
+    }
+
+  value_range_t vr0 = VR_INITIALIZER;
+  value_range_t vr1 = VR_INITIALIZER;
+  tree op0 = gimple_call_arg (stmt, 0);
+  tree op1 = gimple_call_arg (stmt, 1);
+
+  if (TREE_CODE (op0) == SSA_NAME)
+    vr0 = *get_value_range (op0);
+  else if (TREE_CODE (op0) == INTEGER_CST)
+    set_value_range_to_value (&vr0, op0, NULL);
+  else
+    return false;
+
+  if (TREE_CODE (op1) == SSA_NAME)
+    vr1 = *get_value_range (op1);
+  else if (TREE_CODE (op1) == INTEGER_CST)
+    set_value_range_to_value (&vr1, op1, NULL);
+  else
+    return false;
+
+  if (!range_int_cst_p (&vr0) || !range_int_cst_p (&vr1))
+    return false;
+
+  tree r1 = int_const_binop (subcode, vr0.min, vr1.min);
+  tree r2 = int_const_binop (subcode, vr0.max, vr1.max);
+  if (r1 == NULL_TREE || TREE_OVERFLOW (r1)
+      || r2 == NULL_TREE || TREE_OVERFLOW (r2))
+    return false;
+  if (subcode == MULT_EXPR)
+    {
+      tree r3 = int_const_binop (subcode, vr0.min, vr1.max);
+      tree r4 = int_const_binop (subcode, vr0.max, vr1.min);
+      if (r3 == NULL_TREE || TREE_OVERFLOW (r3)
+         || r4 == NULL_TREE || TREE_OVERFLOW (r4))
+       return false;
+    }
+  gimple g = gimple_build_assign_with_ops (subcode, gimple_call_lhs (stmt),
+                                          op0, op1);
+  gsi_replace (gsi, g, false);
+  return true;
+}
+
 /* Simplify STMT using ranges if possible.  */
 
 static bool
@@ -9367,6 +9429,9 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
     return simplify_cond_using_ranges (stmt);
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
     return simplify_switch_using_ranges (stmt);
+  else if (is_gimple_call (stmt)
+          && gimple_call_internal_p (stmt))
+    return simplify_internal_call_using_ranges (gsi, stmt);
 
   return false;
 }