From 55c8849f5d8ca231dba2e4ed2c40c4d435c84ae3 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Fri, 20 May 2016 21:46:58 +0000 Subject: [PATCH] tree-vrp.c (compare_values_warnv): Simplify handling of symbolic ranges by calling get_single_symbol and tidy up. * 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) : 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 | 6 ++ gcc/ada/ChangeLog | 7 ++ gcc/ada/gcc-interface/decl.c | 10 +- gcc/ada/gcc-interface/utils.c | 18 +++- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gnat.dg/opt53.adb | 12 +++ gcc/testsuite/gnat.dg/opt54.adb | 12 +++ gcc/tree-vrp.c | 164 +++++++++++--------------------- 8 files changed, 121 insertions(+), 113 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/opt53.adb create mode 100644 gcc/testsuite/gnat.dg/opt54.adb diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 68c61dd8440..8585175482a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2016-05-20 Eric Botcazou + + * 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 * bitmap.c (bitmap_find_bit): Remove useless test. diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 49c463a848a..525b89f9c6e 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,10 @@ +2016-05-20 Eric Botcazou + + * gcc-interface/decl.c (gnat_to_gnu_entity) : + 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 * gcc-interface/decl.c (gnat_to_gnu_entity) : Do not build diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index b51200f3c8f..6b6bc07684d 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -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 diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 74940655c68..798048a903d 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -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)), diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b4ae11342fd..1a6a460f621 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-05-20 Eric Botcazou + + * gnat.dg/opt53.adb: New test. + * gnat.dg/opt54.adb: Likewise. + 2016-05-20 Martin Jambor PR tree-optimization/70884 diff --git a/gcc/testsuite/gnat.dg/opt53.adb b/gcc/testsuite/gnat.dg/opt53.adb new file mode 100644 index 00000000000..936277db85f --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt53.adb @@ -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 index 00000000000..b4aaa0900e6 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt54.adb @@ -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" } } diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 92d889cd1e2..68f2e905424 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -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))) -- 2.30.2