diff options
Diffstat (limited to 'gcc/tree.c')
-rw-r--r-- | gcc/tree.c | 82 |
1 files changed, 82 insertions, 0 deletions
@@ -14205,6 +14205,88 @@ verify_type (const_tree t) } +/* Return 1 if ARG interpreted as signed in its precision is known to be + always positive or 2 if ARG is known to be always negative, or 3 if + ARG may be positive or negative. */ + +int +get_range_pos_neg (tree arg) +{ + if (arg == error_mark_node) + return 3; + + int prec = TYPE_PRECISION (TREE_TYPE (arg)); + int cnt = 0; + if (TREE_CODE (arg) == INTEGER_CST) + { + wide_int w = wi::sext (arg, prec); + if (wi::neg_p (w)) + return 2; + else + return 1; + } + while (CONVERT_EXPR_P (arg) + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0))) + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec) + { + arg = TREE_OPERAND (arg, 0); + /* Narrower value zero extended into wider type + will always result in positive values. */ + if (TYPE_UNSIGNED (TREE_TYPE (arg)) + && TYPE_PRECISION (TREE_TYPE (arg)) < prec) + return 1; + prec = TYPE_PRECISION (TREE_TYPE (arg)); + if (++cnt > 30) + return 3; + } + + if (TREE_CODE (arg) != SSA_NAME) + return 3; + wide_int arg_min, arg_max; + while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE) + { + gimple *g = SSA_NAME_DEF_STMT (arg); + if (is_gimple_assign (g) + && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g))) + { + tree t = gimple_assign_rhs1 (g); + if (INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TYPE_PRECISION (TREE_TYPE (t)) <= prec) + { + if (TYPE_UNSIGNED (TREE_TYPE (t)) + && TYPE_PRECISION (TREE_TYPE (t)) < prec) + return 1; + prec = TYPE_PRECISION (TREE_TYPE (t)); + arg = t; + if (++cnt > 30) + return 3; + continue; + } + } + return 3; + } + if (TYPE_UNSIGNED (TREE_TYPE (arg))) + { + /* For unsigned values, the "positive" range comes + below the "negative" range. */ + if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED)) + return 1; + if (wi::neg_p (wi::sext (arg_min, prec), SIGNED)) + return 2; + } + else + { + if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED)) + return 1; + if (wi::neg_p (wi::sext (arg_max, prec), SIGNED)) + return 2; + } + return 3; +} + + + + /* Return true if ARG is marked with the nonnull attribute in the current function signature. */ |