tree-vrp.c (compare_values_warnv): Simplify handling of symbolic ranges by calling...
authorEric Botcazou <ebotcazou@adacore.com>
Fri, 20 May 2016 21:46:58 +0000 (21:46 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Fri, 20 May 2016 21:46:58 +0000 (21:46 +0000)
* tree-vrp.c (compare_values_warnv): Simplify handling of symbolic
ranges by calling get_single_symbol and tidy up.  Look more closely
into NAME + CST1 vs CST2 comparisons if type overflow is undefined.
ada/
* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Signed_Integer_Subtype>:
Make same-sized subtypes of signed base types signed.
* gcc-interface/utils.c (make_type_from_size): Adjust to above change.
(unchecked_convert): Likewise.

From-SVN: r236548

gcc/ChangeLog
gcc/ada/ChangeLog
gcc/ada/gcc-interface/decl.c
gcc/ada/gcc-interface/utils.c
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/opt53.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/opt54.adb [new file with mode: 0644]
gcc/tree-vrp.c

index 68c61dd84403fd062e2844f74804143189e7036a..8585175482a8260131ed9b47233f3f8a24ebb908 100644 (file)
@@ -1,3 +1,9 @@
+2016-05-20  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * tree-vrp.c (compare_values_warnv): Simplify handling of symbolic
+       ranges by calling get_single_symbol and tidy up.  Look more closely
+       into NAME + CST1 vs CST2 comparisons if type overflow is undefined.
+
 2016-05-20  Jeff Law  <law@redhat.com>
 
        * bitmap.c (bitmap_find_bit): Remove useless test.
index 49c463a848a55f1e17839e2011ea4d49b50eeb07..525b89f9c6edc76e5bee11548f8b4d586f971565 100644 (file)
@@ -1,3 +1,10 @@
+2016-05-20  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Signed_Integer_Subtype>:
+       Make same-sized subtypes of signed base types signed.
+       * gcc-interface/utils.c (make_type_from_size): Adjust to above change.
+       (unchecked_convert): Likewise.
+
 2016-05-16  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Variable>: Do not build
index b51200f3c8faeb9961897d2c4718353ef93aa896..6b6bc07684dcb82ee8b1c2b2144aca95bcd87ad6 100644 (file)
@@ -1814,7 +1814,12 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
       /* First subtypes of Character are treated as Character; otherwise
         this should be an unsigned type if the base type is unsigned or
         if the lower bound is constant and non-negative or if the type
-        is biased.  */
+        is biased.  However, even if the lower bound is constant and
+        non-negative, we use a signed type for a subtype with the same
+        size as its signed base type, because this eliminates useless
+        conversions to it and gives more leeway to the optimizer; but
+        this means that we will need to explicitly test for this case
+        when we change the representation based on the RM size.  */
       if (kind == E_Enumeration_Subtype
          && No (First_Literal (Etype (gnat_entity)))
          && Esize (gnat_entity) == RM_Size (gnat_entity)
@@ -1822,7 +1827,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
          && flag_signed_char)
        gnu_type = make_signed_type (CHAR_TYPE_SIZE);
       else if (Is_Unsigned_Type (Etype (gnat_entity))
-              || Is_Unsigned_Type (gnat_entity)
+              || (Esize (Etype (gnat_entity)) != Esize (gnat_entity)
+                  && Is_Unsigned_Type (gnat_entity))
               || Has_Biased_Representation (gnat_entity))
        gnu_type = make_unsigned_type (esize);
       else
index 74940655c68ca5396ea4e85d1d4f259c275d46aa..798048a903d4d861b21ba65c23df97712df3a255 100644 (file)
@@ -1116,7 +1116,14 @@ make_type_from_size (tree type, tree size_tree, bool for_biased)
        break;
 
       biased_p |= for_biased;
-      if (TYPE_UNSIGNED (type) || biased_p)
+
+      /* The type should be an unsigned type if the original type is unsigned
+        or if the lower bound is constant and non-negative or if the type is
+        biased, see E_Signed_Integer_Subtype case of gnat_to_gnu_entity.  */
+      if (TYPE_UNSIGNED (type)
+         || (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
+             && tree_int_cst_sgn (TYPE_MIN_VALUE (type)) >= 0)
+         || biased_p)
        new_type = make_unsigned_type (size);
       else
        new_type = make_signed_type (size);
@@ -5111,7 +5118,9 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
   /* If the result is an integral type whose precision is not equal to its
      size, sign- or zero-extend the result.  We need not do this if the input
      is an integral type of the same precision and signedness or if the output
-     is a biased type or if both the input and output are unsigned.  */
+     is a biased type or if both the input and output are unsigned, or if the
+     lower bound is constant and non-negative, see E_Signed_Integer_Subtype
+     case of gnat_to_gnu_entity.  */
   if (!notrunc_p
       && INTEGRAL_TYPE_P (type)
       && TYPE_RM_SIZE (type)
@@ -5123,7 +5132,10 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
                                    ? TYPE_RM_SIZE (etype)
                                    : TYPE_SIZE (etype)) == 0)
       && !(code == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (type))
-      && !(TYPE_UNSIGNED (type) && TYPE_UNSIGNED (etype)))
+      && !((TYPE_UNSIGNED (type)
+           || (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
+               && tree_int_cst_sgn (TYPE_MIN_VALUE (type)) >= 0))
+          && TYPE_UNSIGNED (etype)))
     {
       tree base_type
        = gnat_type_for_size (TREE_INT_CST_LOW (TYPE_SIZE (type)),
index b4ae11342fdd012ca68aa20bf08f69559c7d95bd..1a6a460f621ce65c0a547036a11f3866ab4ae0bd 100644 (file)
@@ -1,3 +1,8 @@
+2016-05-20  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gnat.dg/opt53.adb: New test.
+       * gnat.dg/opt54.adb: Likewise.
+
 2016-05-20  Martin Jambor  <mjambor@suse.cz>
 
        PR tree-optimization/70884
diff --git a/gcc/testsuite/gnat.dg/opt53.adb b/gcc/testsuite/gnat.dg/opt53.adb
new file mode 100644 (file)
index 0000000..936277d
--- /dev/null
@@ -0,0 +1,12 @@
+-- { dg-do compile }
+-- { dg-options "-O2 -fdump-tree-optimized" }
+
+function Opt53 (Val, Max : Positive) return Positive is
+begin
+   if Val >= Max then
+      return Max;
+   end if;
+   return Val + 1;
+end;
+
+-- { dg-final { scan-tree-dump-not "gnat_rcheck" "optimized" } }
diff --git a/gcc/testsuite/gnat.dg/opt54.adb b/gcc/testsuite/gnat.dg/opt54.adb
new file mode 100644 (file)
index 0000000..b4aaa09
--- /dev/null
@@ -0,0 +1,12 @@
+-- { dg-do compile }
+-- { dg-options "-O2 -fdump-tree-optimized" }
+
+function Opt54 (Val, Max : Integer) return Integer is
+begin
+   if Val >= Max then
+      return Max;
+   end if;
+   return Val + 1;
+end;
+
+-- { dg-final { scan-tree-dump-not "gnat_rcheck" "optimized" } }
index 92d889cd1e2e0d18924dd1f4c4cb48d587a15b80..68f2e905424999e2a639c02ae74b160ebfe8a067 100644 (file)
@@ -1187,129 +1187,77 @@ compare_values_warnv (tree val1, tree val2, bool *strict_overflow_p)
   val2 = fold_convert (TREE_TYPE (val1), val2);
   STRIP_USELESS_TYPE_CONVERSION (val2);
 
-  if ((TREE_CODE (val1) == SSA_NAME
-       || (TREE_CODE (val1) == NEGATE_EXPR
-          && TREE_CODE (TREE_OPERAND (val1, 0)) == SSA_NAME)
-       || TREE_CODE (val1) == PLUS_EXPR
-       || TREE_CODE (val1) == MINUS_EXPR)
-      && (TREE_CODE (val2) == SSA_NAME
-         || (TREE_CODE (val2) == NEGATE_EXPR
-             && TREE_CODE (TREE_OPERAND (val2, 0)) == SSA_NAME)
-         || TREE_CODE (val2) == PLUS_EXPR
-         || TREE_CODE (val2) == MINUS_EXPR))
-    {
-      tree n1, c1, n2, c2;
-      enum tree_code code1, code2;
-
-      /* If VAL1 and VAL2 are of the form '[-]NAME [+-] CST' or 'NAME',
-        return -1 or +1 accordingly.  If VAL1 and VAL2 don't use the
-        same name, return -2.  */
-      if (TREE_CODE (val1) == SSA_NAME || TREE_CODE (val1) == NEGATE_EXPR)
-       {
-         code1 = SSA_NAME;
-         n1 = val1;
-         c1 = NULL_TREE;
-       }
-      else
-       {
-         code1 = TREE_CODE (val1);
-         n1 = TREE_OPERAND (val1, 0);
-         c1 = TREE_OPERAND (val1, 1);
-         if (tree_int_cst_sgn (c1) == -1)
-           {
-             if (is_negative_overflow_infinity (c1))
-               return -2;
-             c1 = fold_unary_to_constant (NEGATE_EXPR, TREE_TYPE (c1), c1);
-             if (!c1)
-               return -2;
-             code1 = code1 == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR;
-           }
-       }
-
-      if (TREE_CODE (val2) == SSA_NAME || TREE_CODE (val2) == NEGATE_EXPR)
-       {
-         code2 = SSA_NAME;
-         n2 = val2;
-         c2 = NULL_TREE;
-       }
-      else
-       {
-         code2 = TREE_CODE (val2);
-         n2 = TREE_OPERAND (val2, 0);
-         c2 = TREE_OPERAND (val2, 1);
-         if (tree_int_cst_sgn (c2) == -1)
-           {
-             if (is_negative_overflow_infinity (c2))
-               return -2;
-             c2 = fold_unary_to_constant (NEGATE_EXPR, TREE_TYPE (c2), c2);
-             if (!c2)
-               return -2;
-             code2 = code2 == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR;
-           }
-       }
-
-      /* Both values must use the same name.  */
-      if (TREE_CODE (n1) == NEGATE_EXPR && TREE_CODE (n2) == NEGATE_EXPR)
-       {
-         n1 = TREE_OPERAND (n1, 0);
-         n2 = TREE_OPERAND (n2, 0);
-       }
-      if (n1 != n2)
+  const bool overflow_undefined
+    = INTEGRAL_TYPE_P (TREE_TYPE (val1))
+      && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (val1));
+  tree inv1, inv2;
+  bool neg1, neg2;
+  tree sym1 = get_single_symbol (val1, &neg1, &inv1);
+  tree sym2 = get_single_symbol (val2, &neg2, &inv2);
+
+  /* If VAL1 and VAL2 are of the form '[-]NAME [+ CST]', return -1 or +1
+     accordingly.  If VAL1 and VAL2 don't use the same name, return -2.  */
+  if (sym1 && sym2)
+    {
+      /* Both values must use the same name with the same sign.  */
+      if (sym1 != sym2 || neg1 != neg2)
        return -2;
 
-      if (code1 == SSA_NAME && code2 == SSA_NAME)
-       /* NAME == NAME  */
+      /* [-]NAME + CST == [-]NAME + CST.  */
+      if (inv1 == inv2)
        return 0;
 
       /* If overflow is defined we cannot simplify more.  */
-      if (!TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (val1)))
+      if (!overflow_undefined)
        return -2;
 
       if (strict_overflow_p != NULL
-         && (code1 == SSA_NAME || !TREE_NO_WARNING (val1))
-         && (code2 == SSA_NAME || !TREE_NO_WARNING (val2)))
+         && (!inv1 || !TREE_NO_WARNING (val1))
+         && (!inv2 || !TREE_NO_WARNING (val2)))
        *strict_overflow_p = true;
 
-      if (code1 == SSA_NAME)
-       {
-         if (code2 == PLUS_EXPR)
-           /* NAME < NAME + CST  */
-           return -1;
-         else if (code2 == MINUS_EXPR)
-           /* NAME > NAME - CST  */
-           return 1;
-       }
-      else if (code1 == PLUS_EXPR)
-       {
-         if (code2 == SSA_NAME)
-           /* NAME + CST > NAME  */
-           return 1;
-         else if (code2 == PLUS_EXPR)
-           /* NAME + CST1 > NAME + CST2, if CST1 > CST2  */
-           return compare_values_warnv (c1, c2, strict_overflow_p);
-         else if (code2 == MINUS_EXPR)
-           /* NAME + CST1 > NAME - CST2  */
-           return 1;
-       }
-      else if (code1 == MINUS_EXPR)
+      if (!inv1)
+       inv1 = build_int_cst (TREE_TYPE (val1), 0);
+      if (!inv2)
+       inv2 = build_int_cst (TREE_TYPE (val2), 0);
+
+      return compare_values_warnv (inv1, inv2, strict_overflow_p);
+    }
+
+  const bool cst1 = is_gimple_min_invariant (val1);
+  const bool cst2 = is_gimple_min_invariant (val2);
+
+  /* If one is of the form '[-]NAME + CST' and the other is constant, then
+     it might be possible to say something depending on the constants.  */
+  if ((sym1 && inv1 && cst2) || (sym2 && inv2 && cst1))
+    {
+      if (!overflow_undefined)
+       return -2;
+
+      if (strict_overflow_p != NULL
+         && (!sym1 || !TREE_NO_WARNING (val1))
+         && (!sym2 || !TREE_NO_WARNING (val2)))
+       *strict_overflow_p = true;
+
+      const signop sgn = TYPE_SIGN (TREE_TYPE (val1));
+      tree cst = cst1 ? val1 : val2;
+      tree inv = cst1 ? inv2 : inv1;
+
+      /* Compute the difference between the constants.  If it overflows or
+        underflows, this means that we can trivially compare the NAME with
+        it and, consequently, the two values with each other.  */
+      wide_int diff = wi::sub (cst, inv);
+      if (wi::cmp (0, inv, sgn) != wi::cmp (diff, cst, sgn))
        {
-         if (code2 == SSA_NAME)
-           /* NAME - CST < NAME  */
-           return -1;
-         else if (code2 == PLUS_EXPR)
-           /* NAME - CST1 < NAME + CST2  */
-           return -1;
-         else if (code2 == MINUS_EXPR)
-           /* NAME - CST1 > NAME - CST2, if CST1 < CST2.  Notice that
-              C1 and C2 are swapped in the call to compare_values.  */
-           return compare_values_warnv (c2, c1, strict_overflow_p);
+         const int res = wi::cmp (cst, inv, sgn);
+         return cst1 ? res : -res;
        }
 
-      gcc_unreachable ();
+      return -2;
     }
 
-  /* We cannot compare non-constants.  */
-  if (!is_gimple_min_invariant (val1) || !is_gimple_min_invariant (val2))
+  /* We cannot say anything more for non-constants.  */
+  if (!cst1 || !cst2)
     return -2;
 
   if (!POINTER_TYPE_P (TREE_TYPE (val1)))