summaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c208
1 files changed, 77 insertions, 131 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 48353804972..0292f049509 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5773,137 +5773,6 @@ gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo,
return gimple_get_virt_method_for_vtable (token, v, offset, can_refer);
}
-/* Return true iff VAL is a gimple expression that is known to be
- non-negative. Restricted to floating-point inputs. */
-
-bool
-gimple_val_nonnegative_real_p (tree val)
-{
- gimple *def_stmt;
-
- gcc_assert (val && SCALAR_FLOAT_TYPE_P (TREE_TYPE (val)));
-
- /* Use existing logic for non-gimple trees. */
- if (tree_expr_nonnegative_p (val))
- return true;
-
- if (TREE_CODE (val) != SSA_NAME)
- return false;
-
- /* Currently we look only at the immediately defining statement
- to make this determination, since recursion on defining
- statements of operands can lead to quadratic behavior in the
- worst case. This is expected to catch almost all occurrences
- in practice. It would be possible to implement limited-depth
- recursion if important cases are lost. Alternatively, passes
- that need this information (such as the pow/powi lowering code
- in the cse_sincos pass) could be revised to provide it through
- dataflow propagation. */
-
- def_stmt = SSA_NAME_DEF_STMT (val);
-
- if (is_gimple_assign (def_stmt))
- {
- tree op0, op1;
-
- /* See fold-const.c:tree_expr_nonnegative_p for additional
- cases that could be handled with recursion. */
-
- switch (gimple_assign_rhs_code (def_stmt))
- {
- case ABS_EXPR:
- /* Always true for floating-point operands. */
- return true;
-
- case MULT_EXPR:
- /* True if the two operands are identical (since we are
- restricted to floating-point inputs). */
- op0 = gimple_assign_rhs1 (def_stmt);
- op1 = gimple_assign_rhs2 (def_stmt);
-
- if (op0 == op1
- || operand_equal_p (op0, op1, 0))
- return true;
-
- default:
- return false;
- }
- }
- else if (is_gimple_call (def_stmt))
- {
- tree fndecl = gimple_call_fndecl (def_stmt);
- if (fndecl
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
- {
- tree arg1;
-
- switch (DECL_FUNCTION_CODE (fndecl))
- {
- CASE_FLT_FN (BUILT_IN_ACOS):
- CASE_FLT_FN (BUILT_IN_ACOSH):
- CASE_FLT_FN (BUILT_IN_CABS):
- CASE_FLT_FN (BUILT_IN_COSH):
- CASE_FLT_FN (BUILT_IN_ERFC):
- CASE_FLT_FN (BUILT_IN_EXP):
- CASE_FLT_FN (BUILT_IN_EXP10):
- CASE_FLT_FN (BUILT_IN_EXP2):
- CASE_FLT_FN (BUILT_IN_FABS):
- CASE_FLT_FN (BUILT_IN_FDIM):
- CASE_FLT_FN (BUILT_IN_HYPOT):
- CASE_FLT_FN (BUILT_IN_POW10):
- return true;
-
- CASE_FLT_FN (BUILT_IN_SQRT):
- /* sqrt(-0.0) is -0.0, and sqrt is not defined over other
- nonnegative inputs. */
- if (!HONOR_SIGNED_ZEROS (val))
- return true;
-
- break;
-
- CASE_FLT_FN (BUILT_IN_POWI):
- /* True if the second argument is an even integer. */
- arg1 = gimple_call_arg (def_stmt, 1);
-
- if (TREE_CODE (arg1) == INTEGER_CST
- && (TREE_INT_CST_LOW (arg1) & 1) == 0)
- return true;
-
- break;
-
- CASE_FLT_FN (BUILT_IN_POW):
- /* True if the second argument is an even integer-valued
- real. */
- arg1 = gimple_call_arg (def_stmt, 1);
-
- if (TREE_CODE (arg1) == REAL_CST)
- {
- REAL_VALUE_TYPE c;
- HOST_WIDE_INT n;
-
- c = TREE_REAL_CST (arg1);
- n = real_to_integer (&c);
-
- if ((n & 1) == 0)
- {
- REAL_VALUE_TYPE cint;
- real_from_integer (&cint, VOIDmode, n, SIGNED);
- if (real_identical (&c, &cint))
- return true;
- }
- }
-
- break;
-
- default:
- return false;
- }
- }
- }
-
- return false;
-}
-
/* Given a pointer value OP0, return a simplified version of an
indirection through OP0, or NULL_TREE if no simplification is
possible. Note that the resulting type may be different from
@@ -6280,3 +6149,80 @@ gimple_convert (gimple_seq *seq, location_t loc, tree type, tree op)
return op;
return gimple_build (seq, loc, NOP_EXPR, type, op);
}
+
+/* Return true if the result of assignment STMT is known to be non-negative.
+ If the return value is based on the assumption that signed overflow is
+ undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
+ *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */
+
+static bool
+gimple_assign_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
+ int depth)
+{
+ enum tree_code code = gimple_assign_rhs_code (stmt);
+ switch (get_gimple_rhs_class (code))
+ {
+ case GIMPLE_UNARY_RHS:
+ return tree_unary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
+ gimple_expr_type (stmt),
+ gimple_assign_rhs1 (stmt),
+ strict_overflow_p, depth);
+ case GIMPLE_BINARY_RHS:
+ return tree_binary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
+ gimple_expr_type (stmt),
+ gimple_assign_rhs1 (stmt),
+ gimple_assign_rhs2 (stmt),
+ strict_overflow_p, depth);
+ case GIMPLE_TERNARY_RHS:
+ return false;
+ case GIMPLE_SINGLE_RHS:
+ return tree_single_nonnegative_warnv_p (gimple_assign_rhs1 (stmt),
+ strict_overflow_p, depth);
+ case GIMPLE_INVALID_RHS:
+ break;
+ }
+ gcc_unreachable ();
+}
+
+/* Return true if return value of call STMT is known to be non-negative.
+ If the return value is based on the assumption that signed overflow is
+ undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
+ *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */
+
+static bool
+gimple_call_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
+ int depth)
+{
+ tree arg0 = gimple_call_num_args (stmt) > 0 ?
+ gimple_call_arg (stmt, 0) : NULL_TREE;
+ tree arg1 = gimple_call_num_args (stmt) > 1 ?
+ gimple_call_arg (stmt, 1) : NULL_TREE;
+
+ return tree_call_nonnegative_warnv_p (gimple_expr_type (stmt),
+ gimple_call_fndecl (stmt),
+ arg0,
+ arg1,
+ strict_overflow_p, depth);
+}
+
+/* Return true if STMT is known to compute a non-negative value.
+ If the return value is based on the assumption that signed overflow is
+ undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
+ *STRICT_OVERFLOW_P. DEPTH is the current nesting depth of the query. */
+
+bool
+gimple_stmt_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
+ int depth)
+{
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_ASSIGN:
+ return gimple_assign_nonnegative_warnv_p (stmt, strict_overflow_p,
+ depth);
+ case GIMPLE_CALL:
+ return gimple_call_nonnegative_warnv_p (stmt, strict_overflow_p,
+ depth);
+ default:
+ return false;
+ }
+}