aboutsummaryrefslogtreecommitdiff
path: root/gcc/range-op-float.cc
AgeCommit message (Collapse)AuthorFilesLines
2023-06-13fix frange_nextafter odr violationAlexandre Oliva1-3/+3
C++ requires inline functions to be declared inline and defined in every translation unit that uses them. frange_nextafter is used in gimple-range-op.cc but it's only defined as inline in range-op-float.cc. Drop the extraneous inline specifier. Other non-static inline functions in range-op-float.cc are not referenced elsewhere, so I'm making them static. for gcc/ChangeLog * range-op-float.cc (frange_nextafter): Drop inline. (frelop_early_resolve): Add static. (frange_float): Likewise.
2023-06-12Add some overrides.Andrew MacLeod1-0/+10
PR tree-optimization/110205 * range-op-float.cc (range_operator::fold_range): Add default FII fold routine. * range-op-mixed.h (class operator_gt): Add missing final overrides. * range-op.cc (range_op_handler::fold_range): Add RO_FII case. (operator_lshift ::update_bitmask): Add final override. (operator_rshift ::update_bitmask): Add final override. * range-op.h (range_operator::fold_range): Add FII prototype.
2023-06-12Remove type from range_op_handler table selectionAndrew MacLeod1-3/+3
With the unified table complete, we no loonger need to specify a type to choose a table when setting a range_op_handler. * gimple-range-gori.cc (gori_compute::condexpr_adjust): Do not pass type. * gimple-range-op.cc (get_code): Rename from get_code_and_type and simplify. (gimple_range_op_handler::supported_p): No need for type. (gimple_range_op_handler::gimple_range_op_handler): Ditto. (cfn_copysign::fold_range): Ditto. (cfn_ubsan::fold_range): Ditto. * ipa-cp.cc (ipa_vr_operation_and_type_effects): Ditto. * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Ditto. * range-op-float.cc (operator_plus::op1_range): Ditto. (operator_mult::op1_range): Ditto. (range_op_float_tests): Ditto. * range-op.cc (get_op_handler): Remove. (range_op_handler::set_op_handler): Remove. (operator_plus::op1_range): No need for type. (operator_minus::op1_range): Ditto. (operator_mult::op1_range): Ditto. (operator_exact_divide::op1_range): Ditto. (operator_cast::op1_range): Ditto. (perator_bitwise_not::fold_range): Ditto. (operator_negate::fold_range): Ditto. * range-op.h (range_op_handler::range_op_handler): Remove type param. (range_cast): No need for type. (range_op_table::operator[]): Check for enum_code >= 0. * tree-data-ref.cc (compute_distributive_range): No need for type. * tree-ssa-loop-unswitch.cc (unswitch_predicate): Ditto. * value-query.cc (range_query::get_tree_range): Ditto. * value-relation.cc (relation_oracle::validate_relation): Ditto. * vr-values.cc (range_of_var_in_loop): Ditto. (simplify_using_ranges::fold_cond_with_ops): Ditto.
2023-06-09Unify MULT_EXPR range operatorAndrew MacLeod1-180/+169
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_mult_div_base): Delete. (foperator_mult_div_base::find_range): Make static local function. (foperator_mult): Remove. Move prototypes to range-op-mixed.h (operator_mult::op1_range): Rename from foperator_mult. (operator_mult::op2_range): Ditto. (operator_mult::rv_fold): Ditto. (float_table::float_table): Remove MULT_EXPR. (class foperator_div): Inherit from range_operator. (float_table::float_table): Delete. * range-op-mixed.h (class operator_mult): Combined from integer and float files. * range-op.cc (float_tree_table): Delete. (op_mult): New object. (unified_table::unified_table): Add MULT_EXPR. (get_op_handler): Do not check float table any longer. (class cross_product_operator): Move to range-op-mixed.h. (class operator_mult): Move to range-op-mixed.h. (integral_table::integral_table): Remove MULT_EXPR. (pointer_table::pointer_table): Remove MULT_EXPR. * range-op.h (float_table): Remove.
2023-06-09Unify NEGATE_EXPR range operatorAndrew MacLeod1-45/+41
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_negate): Remove. Move prototypes to range-op-mixed.h (operator_negate::fold_range): Rename from foperator_negate. (operator_negate::op1_range): Ditto. (float_table::float_table): Remove NEGATE_EXPR. * range-op-mixed.h (class operator_negate): Combined from integer and float files. * range-op.cc (op_negate): New object. (unified_table::unified_table): Add NEGATE_EXPR. (class operator_negate): Move to range-op-mixed.h. (integral_table::integral_table): Remove NEGATE_EXPR. (pointer_table::pointer_table): Remove NEGATE_EXPR.
2023-06-09Unify MINUS_EXPR range operatorAndrew MacLeod1-49/+44
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_minus): Remove. Move prototypes to range-op-mixed.h (operator_minus::fold_range): Rename from foperator_minus. (operator_minus::op1_range): Ditto. (operator_minus::op2_range): Ditto. (operator_minus::rv_fold): Ditto. (float_table::float_table): Remove MINUS_EXPR. * range-op-mixed.h (class operator_minus): Combined from integer and float files. * range-op.cc (op_minus): New object. (unified_table::unified_table): Add MINUS_EXPR. (class operator_minus): Move to range-op-mixed.h. (integral_table::integral_table): Remove MINUS_EXPR. (pointer_table::pointer_table): Remove MINUS_EXPR.
2023-06-09Unify ABS_EXPR range operatorAndrew MacLeod1-20/+6
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_abs): Remove. Move prototypes to range-op-mixed.h (operator_abs::fold_range): Rename from foperator_abs. (operator_abs::op1_range): Ditto. (float_table::float_table): Remove ABS_EXPR. * range-op-mixed.h (class operator_abs): Combined from integer and float files. * range-op.cc (op_abs): New object. (unified_table::unified_table): Add ABS_EXPR. (class operator_abs): Move to range-op-mixed.h. (integral_table::integral_table): Remove ABS_EXPR. (pointer_table::pointer_table): Remove ABS_EXPR.
2023-06-09Unify PLUS_EXPR range operatorAndrew MacLeod1-50/+44
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_plus): Remove. Move prototypes to range-op-mixed.h (operator_plus::fold_range): Rename from foperator_plus. (operator_plus::op1_range): Ditto. (operator_plus::op2_range): Ditto. (operator_plus::rv_fold): Ditto. (float_table::float_table): Remove PLUS_EXPR. * range-op-mixed.h (class operator_plus): Combined from integer and float files. * range-op.cc (op_plus): New object. (unified_table::unified_table): Add PLUS_EXPR. (class operator_plus): Move to range-op-mixed.h. (integral_table::integral_table): Remove PLUS_EXPR. (pointer_table::pointer_table): Remove PLUS_EXPR.
2023-06-09Unify operator_cst range operatorAndrew MacLeod1-0/+7
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (operator_cst::fold_range): New. * range-op-mixed.h (class operator_cst): Move from integer file. * range-op.cc (op_cst): New object. (unified_table::unified_table): Add op_cst. Also use for REAL_CST. (class operator_cst): Move to range-op-mixed.h. (integral_table::integral_table): Remove op_cst. (pointer_table::pointer_table): Remove op_cst.
2023-06-09Unify Identity range operatorAndrew MacLeod1-25/+15
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_identity): Remove. Move prototypes to range-op-mixed.h (operator_identity::fold_range): Rename from foperator_identity. (operator_identity::op1_range): Ditto. (float_table::float_table): Remove fop_identity. * range-op-mixed.h (class operator_identity): Combined from integer and float files. * range-op.cc (op_identity): New object. (unified_table::unified_table): Add op_identity. (class operator_identity): Move to range-op-mixed.h. (integral_table::integral_table): Remove identity. (pointer_table::pointer_table): Remove identity.
2023-06-09Unify GE_EXPR range operatorAndrew MacLeod1-40/+14
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_ge): Remove. Move prototypes to range-op-mixed.h (operator_ge::fold_range): Rename from foperator_ge. (operator_ge::op1_range): Ditto. (float_table::float_table): Remove GE_EXPR. * range-op-mixed.h (class operator_ge): Combined from integer and float files. * range-op.cc (op_ge): New object. (unified_table::unified_table): Add GE_EXPR. (class operator_ge): Move to range-op-mixed.h. (ge_op1_op2_relation): Fold into operator_ge::op1_op2_relation. (integral_table::integral_table): Remove GE_EXPR. (pointer_table::pointer_table): Remove GE_EXPR. * range-op.h (ge_op1_op2_relation): Delete.
2023-06-09Unify GT_EXPR range operatorAndrew MacLeod1-37/+15
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_gt): Remove. Move prototypes to range-op-mixed.h (operator_gt::fold_range): Rename from foperator_gt. (operator_gt::op1_range): Ditto. (float_table::float_table): Remove GT_EXPR. * range-op-mixed.h (class operator_gt): Combined from integer and float files. * range-op.cc (op_gt): New object. (unified_table::unified_table): Add GT_EXPR. (class operator_gt): Move to range-op-mixed.h. (gt_op1_op2_relation): Fold into operator_gt::op1_op2_relation. (integral_table::integral_table): Remove GT_EXPR. (pointer_table::pointer_table): Remove GT_EXPR. * range-op.h (gt_op1_op2_relation): Delete.
2023-06-09Unify LE_EXPR range operatorAndrew MacLeod1-37/+15
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_le): Remove. Move prototypes to range-op-mixed.h (operator_le::fold_range): Rename from foperator_le. (operator_le::op1_range): Ditto. (float_table::float_table): Remove LE_EXPR. * range-op-mixed.h (class operator_le): Combined from integer and float files. * range-op.cc (op_le): New object. (unified_table::unified_table): Add LE_EXPR. (class operator_le): Move to range-op-mixed.h. (le_op1_op2_relation): Fold into operator_le::op1_op2_relation. (integral_table::integral_table): Remove LE_EXPR. (pointer_table::pointer_table): Remove LE_EXPR. * range-op.h (le_op1_op2_relation): Delete.
2023-06-09Unify LT_EXPR range operatorAndrew MacLeod1-37/+15
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_lt): Remove. Move prototypes to range-op-mixed.h (operator_lt::fold_range): Rename from foperator_lt. (operator_lt::op1_range): Ditto. (float_table::float_table): Remove LT_EXPR. * range-op-mixed.h (class operator_lt): Combined from integer and float files. * range-op.cc (op_lt): New object. (unified_table::unified_table): Add LT_EXPR. (class operator_lt): Move to range-op-mixed.h. (lt_op1_op2_relation): Fold into operator_lt::op1_op2_relation. (integral_table::integral_table): Remove LT_EXPR. (pointer_table::pointer_table): Remove LT_EXPR. * range-op.h (lt_op1_op2_relation): Delete.
2023-06-09Unify NE_EXPR range operatorAndrew MacLeod1-27/+9
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_not_equal): Remove. Move prototypes to range-op-mixed.h (operator_equal::fold_range): Rename from foperator_not_equal. (operator_equal::op1_range): Ditto. (float_table::float_table): Remove NE_EXPR. * range-op-mixed.h (class operator_not_equal): Combined from integer and float files. * range-op.cc (op_equal): New object. (unified_table::unified_table): Add NE_EXPR. (class operator_not_equal): Move to range-op-mixed.h. (not_equal_op1_op2_relation): Fold into operator_not_equal::op1_op2_relation. (integral_table::integral_table): Remove NE_EXPR. (pointer_table::pointer_table): Remove NE_EXPR. * range-op.h (not_equal_op1_op2_relation): Delete.
2023-06-09Unify EQ_EXPR range operatorAndrew MacLeod1-29/+12
Move the declaration of the class to the range-op-mixed header, add the floating point prototypes as well, and use it in the new unified table. * range-op-float.cc (foperator_equal): Remove. Move prototypes to range-op-mixed.h (operator_equal::fold_range): Rename from foperator_equal. (operator_equal::op1_range): Ditto. (float_table::float_table): Remove EQ_EXPR. * range-op-mixed.h (class operator_equal): Combined from integer and float files. * range-op.cc (op_equal): New object. (unified_table::unified_table): Add EQ_EXPR. (class operator_equal): Move to range-op-mixed.h. (equal_op1_op2_relation): Fold into operator_equal::op1_op2_relation. (integral_table::integral_table): Remove EQ_EXPR. (pointer_table::pointer_table): Remove EQ_EXPR. * range-op.h (equal_op1_op2_relation): Delete.
2023-06-09Provide a unified range-op table.Andrew MacLeod1-15/+14
Create a table to prepare for unifying all operations into a single table. Move any operators which only occur in one table to the approriate initialization routine. Provide a mixed header file for range-ops with multiple categories. * range-op-float.cc (class float_table): Move to header. (float_table::float_table): Move float only operators to... (range_op_table::initialize_float_ops): Here. * range-op-mixed.h: New. * range-op.cc (integral_tree_table, pointer_tree_table): Moved to top of file. (float_tree_table): Moved from range-op-float.cc. (unified_tree_table): New. (unified_table::unified_table): New. Call initialize routines. (get_op_handler): Check unified table first. (range_op_handler::range_op_handler): Handle no type constructor. (integral_table::integral_table): Move integral only operators to... (range_op_table::initialize_integral_ops): Here. (pointer_table::pointer_table): Move pointer only operators to... (range_op_table::initialize_pointer_ops): Here. * range-op.h (enum bool_range_state): Move to range-op-mixed.h. (get_bool_state): Ditto. (empty_range_varying): Ditto. (relop_early_resolve): Ditto. (class range_op_table): Add new init methods for range types. (class integral_table): Move declaration to here. (class pointer_table): Move declaration to here. (class float_table): Move declaration to here.
2023-06-08Unify range_operators to one class.Andrew MacLeod1-121/+101
Range_operator and range_operator_float are 2 different classes, making generalized dispatch difficult. The distinction between what is a float operator and what is an integral operator also blurs when some methods have multiple types. ie, casts : INT = FLOAT and FLOAT = INT This patch unifies all possible invocation patterns in one class, and switches the float table to use the general range_op_table. * gimple-range-op.cc (cfn_constant_float_p): Change base class. (cfn_pass_through_arg1): Adjust using statemenmt. (cfn_signbit): Change base class, adjust using statement. (cfn_copysign): Ditto. (cfn_sqrt): Ditto. (cfn_sincos): Ditto. * range-op-float.cc (fold_range): Change class to range_operator. (rv_fold): Ditto. (op1_range): Ditto (op2_range): Ditto (lhs_op1_relation): Ditto. (lhs_op2_relation): Ditto. (op1_op2_relation): Ditto. (foperator_*): Ditto. (class float_table): New. Inherit from range_op_table. (floating_tree_table) Change to range_op_table pointer. (class floating_op_table): Delete. * range-op.cc (operator_equal): Adjust using statement. (operator_not_equal): Ditto. (operator_lt, operator_le, operator_gt, operator_ge): Ditto. (operator_minus, operator_cast): Ditto. (operator_bitwise_and, pointer_plus_operator): Ditto. (get_float_handle): Change return type. * range-op.h (range_operator_float): Delete. Relocate all methods into class range_operator. (range_op_handler::m_float): Change type to range_operator. (floating_op_table): Delete. (floating_tree_table): Change type.
2023-06-08Fix floating point bug in fold_range.Andrew MacLeod1-1/+1
We currently do not have any floating point operators where operand 1 is a different type than the LHS. When we eventually do there is a bug in fold_range. If either operand is a known NAN, it returns a NAN of the type of operand 1 instead of the result type. * range-op-float.cc (range_operator_float::fold_range): Return NAN of the result type.
2023-05-06gimple-range-op: Improve handling of sqrt rangesJakub Jelinek1-1/+1
The previous patch just added basic intrinsic ranges for sqrt ([-0.0, +Inf] +-NAN being the general result range of the function and [-0.0, +Inf] the general operand range if result isn't NAN etc.), the following patch intersects those ranges with particular range computed from argument or result's exact range with the expected error in ulps taken into account and adds a function (frange_arithmetic variant) which can be used by other functions as well as helper. 2023-05-06 Jakub Jelinek <jakub@redhat.com> * value-range.h (frange_arithmetic): Declare. * range-op-float.cc (frange_arithmetic): No longer static. * gimple-range-op.cc (frange_mpfr_arg1): New function. (cfn_sqrt::fold_range): Intersect the generic boundaries range with range computed from sqrt of the particular bounds. (cfn_sqrt::op1_range): Intersect the generic boundaries range with range computed from squared particular bounds. * gcc.dg/tree-ssa/range-sqrt-2.c: New test.
2023-04-18Declare dconstm0 to go along with dconst0 and friends.Aldy Hernandez1-3/+3
Negating dconst0 is getting pretty old, and we will keep adding copies of the same idiom. Fixed by adding a dconstm0 constant to go along with dconst1, dconstm1, etc. gcc/ChangeLog: * emit-rtl.cc (init_emit_once): Initialize dconstm0. * gimple-range-op.cc (class cfn_signbit): Remove dconstm0 declaration. * range-op-float.cc (zero_range): Use dconstm0. (zero_to_inf_range): Same. * real.h (dconstm0): New. * value-range.cc (frange::flush_denormals_to_zero): Use dconstm0. (frange::set_zero): Do not declare dconstm0.
2023-04-04range-op-float: Fix reverse ops of comparisons [PR109386]Jakub Jelinek1-16/+16
I've missed one of my recent range-op-float.cc changes (likely the r13-6967 one) caused FAIL: libphobos.phobos/std/math/algebraic.d execution test FAIL: libphobos.phobos_shared/std/math/algebraic.d execution test regressions, distilled into a C testcase below. In the testcase, we have !(u >= v) condition where both u and v are results of fabs*, which guards t1 = u u<= __FLT_MAX__; and t2 = v u<= __FLT_MAX__; comparisons. From false u >= v where u and v have [0.0, +Inf] NAN ranges we (incorrectly deduce that one of them is [nextafterf (0.0, 1.0), +Inf] NAN and the other is [0.0, nextafterf (+Inf, 0.0)] NAN and from that deduce that one of the comparisons is always true, because UNLE_EXPR with the maximum representable number are false only if the value is +Inf and our ranges tell that is not possible. The bug is that the u >= v comparison determines a sensible range only when it is true - we then know neither operand can be NAN and it behaves correctly. But when the comparison is false, our current code gives sensible answers only if the other op can't be NAN. If it can be NAN, whenever it is NAN, the comparison is always false regardless of the other value, so the other value needs to be VARYING. Now, foperator_unordered_lt::op1_range etc. had code to deal with that for op?.known_nan (), but as the testcase shows, it is enough if it may be a NAN at runtime to make it VARYING. So, the following patch replaces for all those BRS_FALSE cases of the normal non-equality comparisons if (opOTHER.known_isnan ()) r.set_varying (type); to do it also if maybe_isnan (). For the unordered or ... comparisons, it is similar for BRS_TRUE. Those comparisons are true whenever either operand is NAN, or if neither is NAN, the corresponding normal comparison. So, if those comparisons are true and other operand might be a NAN, we can't tell (VARYING), if it is false, currently handling is correct. 2023-04-04 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/109386 * range-op-float.cc (foperator_lt::op1_range, foperator_lt::op2_range, foperator_le::op1_range, foperator_le::op2_range, foperator_gt::op1_range, foperator_gt::op2_range, foperator_ge::op1_range, foperator_ge::op2_range): Make r varying for BRS_FALSE case even if the other op is maybe_isnan, not just known_isnan. (foperator_unordered_lt::op1_range, foperator_unordered_lt::op2_range, foperator_unordered_le::op1_range, foperator_unordered_le::op2_range, foperator_unordered_gt::op1_range, foperator_unordered_gt::op2_range, foperator_unordered_ge::op1_range, foperator_unordered_ge::op2_range): Make r varying for BRS_TRUE case even if the other op is maybe_isnan, not just known_isnan. * gcc.c-torture/execute/ieee/pr109386.c: New test.
2023-04-01range-op-float: Further foperator_{,not_}equal::fold_range fixJakub Jelinek1-0/+14
On Fri, Mar 31, 2023 at 12:45:10PM +0200, Jakub Jelinek via Gcc-patches wrote: > - there is a missing case (not handled in this patch) where both operands > are known to be zeros, but not singleton zeros This patch adds those cases. 2023-04-01 Jakub Jelinek <jakub@redhat.com> * range-op-float.cc (foperator_equal::fold_range): If at least one of the op ranges is not singleton and neither is NaN and all 4 bounds are zero, return [1, 1]. (foperator_not_equal::fold_range): In the same case return [0, 0].
2023-04-01range-op-float: Further comparison fixesJakub Jelinek1-46/+108
On Fri, Mar 31, 2023 at 09:57:54AM +0200, Jakub Jelinek via Gcc-patches wrote: > and so if maybe_isnan, they always return [0, 1]. Now, thinking about it, > this is unnecessary pessimization, for the case where the ... block > returns range_false (type) we actually could do it also if maybe_isnan (op1, > op2), because if one or both operands are NAN, the comparison will be false, > and if neither is NAN, the comparison will be also false. Will fix > incrementally today. Here it is. 1) the foperator_{,not_}equal::fold_range cases - we have correctly first a case handling known_isnan on either operand, return there range_false (type) - EQ, resp. range_true (type) - NE - next we handle the singleton cases, maybe_isnan + singleton isn't singleton, so these are ok - there is a missing case (not handled in this patch) where both operands are known to be zeros, but not singleton zeros - there is some !maybe_isnan (op1, op2) handling which tries to prove when the operands are certainly not equal and results in range_false (type) - EQ, resp. range_true (type) - NE - otherwise range_true_and_false (type) Now, I think (and this patch implements it) that the !maybe_isnan (op1, op2) check is unnecessary. If we prove that when ignoring maybe NANs, the ranges don't intersect and so the comparison is always false for EQ or always true for NE, if NANs can appear, it doesn't change anything on that either, for EQ if NAN appears, the result is false like what we proved for the finite ranges, for NE if NAN appears, the result is true like what we proved for the finite ranges 2) foperator_{lt,le,gt,ge}::fold_range cases - these have correctly known_isnan on either operand first and return there range_false (type) - then !maybe_isnan (op1, op2) condition guarded checks - finally range_true_and_false (type) - so do that for maybe_isnan (op1, op2) Here in the !maybe_isnan (op1, op2) guarded code we have some condition which results in range_true (type), another condition which results in range_false (type) and otherwise range_true_and_false (type). Now, the condition which results in range_false (type) can be IMHO done also for the maybe_isnan (op1, op2) cases, because it is [0, 0] if both operands are finite or [0, 0] if either operand is NAN. 3) finally, LTGT_EXPR wasn't handled at all. LTGT_EXPR is the inverse comparision to UNEQ_EXPR, I believe both raise exceptions only if either operand is sNaN, UNEQ_EXPR is true if both operands are either equal or either of the operands is NAN, while LTGT_EXPR is true if the operands compare either smaller or larger and is false if either of the operands is NAN. 2023-04-01 Jakub Jelinek <jakub@redhat.com> * range-op-float.cc (foperator_equal::fold_range): Perform the non-singleton handling regardless of maybe_isnan (op1, op2). (foperator_not_equal::fold_range): Likewise. (foperator_lt::fold_range, foperator_le::fold_range, foperator_gt::fold_range, foperator_ge::fold_range): Perform the real_* comparison check which results in range_false (type) even if maybe_isnan (op1, op2). Simplify. (foperator_ltgt): New class. (fop_ltgt): New variable. (floating_op_table::floating_op_table): Handle LTGT_EXPR using fop_ltgt. * gcc.dg/torture/inf-compare-1.c: Add dg-additional-options -fno-tree-dominator-opts -fno-tree-vrp. * gcc.dg/torture/inf-compare-1-float.c: Likewise. * gcc.dg/torture/inf-compare-2.c: Likewise. * gcc.dg/torture/inf-compare-2-float.c: Likewise.
2023-03-31range-op-float, value-range: Fix up handling of UN{LT,LE,GT,GE,EQ}_EXPR and ↵Jakub Jelinek1-5/+35
handle comparisons in get_tree_range [PR91645] When looking into PR91645, I've noticed we handle UN{LT,LE,GT,GE,EQ}_EXPR comparisons incorrectly. All those are unordered or ..., we correctly return [1, 1] if one or both operands are known NANs, and correctly ask the non-UN prefixed op to fold_range if neither operand may be NAN. But for the case where one or both operands may be NAN, we always return [0, 1]. The UN* fold_range tries to handle it by asking the non-UN prefixed fold_range and if it returns [1, 1] return that, if it returns [0, 0] or [0, 1] return [0, 1], which makes sense, because the maybe NAN means that it is the non-UN prefixed fold_range unioned with [1, 1] in case the maybe NAN is actually NAN at runtime. The problem is that the non-UN prefixed fold_range always returns [0, 1] because those fold_range implementations are like: if (op1.known_isnan () || op2.known_isnan ()) r = range_false (type); else if (!maybe_isnan (op1, op2)) { ... } else r = range_true_and_false (type); and so if maybe_isnan, they always return [0, 1]. Now, thinking about it, this is unnecessary pessimization, for the case where the ... block returns range_false (type) we actually could do it also if maybe_isnan (op1, op2), because if one or both operands are NAN, the comparison will be false, and if neither is NAN, the comparison will be also false. Will fix incrementally today. Anyway, the following patch fixes it by asking the non-UN prefixed fold_range on ranges with NAN cleared, which I think does the right thing in all cases. Another change in the patch is that range_query::get_tree_range always returned VARYING for comparisons, this patch allows to ask about those as well (they are very much like binary ops, except they take the important type from the types of the operands rather than result). Initially I've developed this patch together with changes to tree-call-cdce.cc, but those result in one regression and apparently aren't actually needed to fix this bug, the range-op-float.cc changes are enough. 2023-03-31 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/91645 * range-op-float.cc (foperator_unordered_lt::fold_range, foperator_unordered_le::fold_range, foperator_unordered_gt::fold_range, foperator_unordered_ge::fold_range, foperator_unordered_equal::fold_range): Call the ordered fold_range on ranges with cleared NaNs. * value-query.cc (range_query::get_tree_range): Handle also COMPARISON_CLASS_P trees. * gcc.target/i386/pr103559-1.c: New test. * gcc.target/i386/pr103559-2.c: New test. * gcc.target/i386/pr103559-3.c: New test. * gcc.target/i386/pr103559-4.c: New test.
2023-03-28range-op-float: Only flush_denormals_to_zero for +-*/ [PR109154]Jakub Jelinek1-0/+2
As discussed in the PR, flushing denormals to zero on every frange::set might be harmful for e.g. x < 0.0 comparisons, because we then on both sides use ranges that include zero [-Inf, -0.0] on the true side, and [-0.0, +Inf] NAN on the false side, rather than [-Inf, nextafter (-0.0, -Inf)] on the true side. The following patch does it only in range_operator_float::fold_range which is right now used for +-*/ (both normal and reverse ops of those). Though, I don't see any difference on the testcase in the PR, but not sure what I should be looking at and the reduced testcase there has undefined behavior. 2023-03-28 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/109154 * value-range.h (frange::flush_denormals_to_zero): Make it public rather than private. * value-range.cc (frange::set): Don't call flush_denormals_to_zero here. * range-op-float.cc (range_operator_float::fold_range): Call flush_denormals_to_zero.
2023-03-28range-op-float: Use get_nan_state in float_widen_lhs_rangeJakub Jelinek1-6/+1
On Wed, Mar 22, 2023 at 07:32:44AM +0100, Aldy Hernandez wrote: > * value-range.cc (frange::set): Add nan_state argument. > * value-range.h (class nan_state): New. > (frange::get_nan_state): New. The following patch makes use of those changes in float_widen_lhs_range. 2023-03-28 Jakub Jelinek <jakub@redhat.com> * range-op-float.cc (float_widen_lhs_range): Use pass get_nan_state as 4th argument to set to avoid clear_nan and union_ calls.
2023-03-23ranger: Ranger meets aspellJakub Jelinek1-6/+6
I've noticed a comment typo in tree-vrp.cc and decided to quickly skim aspell -c on the ranger sources (with quick I on everything that looked ok or roughly ok). But not being a native English speaker, I could get stuff wrong. 2023-03-23 Jakub Jelinek <jakub@redhat.com> * value-range.cc (irange::irange_union, irange::intersect): Fix comment spelling bugs. * gimple-range-trace.cc (range_tracer::do_header): Likewise. * gimple-range-trace.h: Likewise. * gimple-range-edge.cc: Likewise. (gimple_outgoing_range_stmt_p, gimple_outgoing_range::switch_edge_range, gimple_outgoing_range::edge_range_p): Likewise. * gimple-range.cc (gimple_ranger::prefill_stmt_dependencies, gimple_ranger::fold_stmt, gimple_ranger::register_transitive_infer, assume_query::assume_query, assume_query::calculate_phi): Likewise. * gimple-range-edge.h: Likewise. * value-range.h (Value_Range::set, Value_Range::lower_bound, Value_Range::upper_bound, frange::set_undefined): Likewise. * gimple-range-gori.h (range_def_chain::depend, gori_map::m_outgoing, gori_compute): Likewise. * gimple-range-fold.h (fold_using_range): Likewise. * gimple-range-path.cc (path_range_query::compute_ranges_in_phis): Likewise. * gimple-range-gori.cc (range_def_chain::in_chain_p, range_def_chain::dump, gori_map::calculate_gori, gori_compute::compute_operand_range_switch, gori_compute::logical_combine, gori_compute::refine_using_relation, gori_compute::compute_operand1_range, gori_compute::may_recompute_p): Likewise. * gimple-range.h: Likewise. (enable_ranger): Likewise. * range-op.h (empty_range_varying): Likewise. * value-query.h (value_query): Likewise. * gimple-range-cache.cc (block_range_cache::set_bb_range, block_range_cache::dump, ssa_global_cache::clear_global_range, temporal_cache::temporal_value, temporal_cache::current_p, ranger_cache::range_of_def, ranger_cache::propagate_updated_value, ranger_cache::range_from_dom, ranger_cache::register_inferred_value): Likewise. * gimple-range-fold.cc (fur_edge::get_phi_operand, fur_stmt::get_operand, gimple_range_adjustment, fold_using_range::range_of_phi, fold_using_range::relation_fold_and_or): Likewise. * value-range-storage.h (irange_storage_slot::MAX_INTS): Likewise. * value-query.cc (range_query::value_of_expr, range_query::value_on_edge, range_query::query_relation): Likewise. * tree-vrp.cc (remove_unreachable::remove_and_update_globals, intersect_range_with_nonzero_bits): Likewise. * gimple-range-infer.cc (gimple_infer_range::check_assume_func, exit_range): Likewise. * value-relation.h: Likewise. (equiv_oracle, relation_trio::relation_trio, value_relation, value_relation::value_relation, pe_min): Likewise. * range-op-float.cc (range_operator_float::rv_fold, frange_arithmetic, foperator_unordered_equal::op1_range, foperator_div::rv_fold): Likewise. * gimple-range-op.cc (cfn_clz::fold_range): Likewise. * value-relation.cc (equiv_oracle::query_relation, equiv_oracle::register_equiv, equiv_oracle::add_equiv_to_block, value_relation::apply_transitive, relation_chain_head::find_relation, dom_oracle::query_relation, dom_oracle::find_relation_block, dom_oracle::find_relation_dom, path_oracle::register_equiv): Likewise. * range-op.cc (range_operator::wi_fold_in_parts_equiv, create_possibly_reversed_range, adjust_op1_for_overflow, operator_mult::wi_fold, operator_exact_divide::op1_range, operator_cast::lhs_op1_relation, operator_cast::fold_pair, operator_cast::fold_range, operator_abs::wi_fold, range_op_cast_tests, range_op_lshift_tests): Likewise.
2023-03-10range-op-float: Extend lhs by 0.5ulp rather than 1ulp if not -frounding-math ↵Jakub Jelinek1-2/+18
[PR109008] This patch, incremental to the just posted one, improves the reverse operation ranges significantly by widening just by 0.5ulp in each direction rather than 1ulp. Again, REAL_VALUE_TYPE has both wider exponent range and wider mantissa precision (160 bits) than any supported type, this patch uses the latter property. The patch doesn't do it if -frounding-math, because then the rounding can be +-1ulp in each direction depending on the rounding mode which we don't know, or for IBM double double because that type is just weird and we can't trust in sane properties. I've performed testing of these 2 patches on 300000 random tests as with yesterday's patch, exact numbers are in the PR, but I see very significant improvement in the precision of the ranges while keeping it conservatively correct. 2023-03-10 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/109008 * range-op-float.cc (float_widen_lhs_range): If not -frounding-math and not IBM double double format, extend lhs range just by 0.5ulp rather than 1ulp in each direction.
2023-03-10range-op-float: Fix up -ffinite-math-only range extension and don't extend ↵Jakub Jelinek1-4/+34
into infinities [PR109008] The following patch does two things (both related to range extension around the boundaries). The first part (in the 2 real_isfinite blocks) is to make the ranges narrower when the old boundaries are minimum and/or maximum representable finite number. In that case frange_nextafter gives -Inf or +Inf, but then the resulting computed reverse range is very far from the actually needed range, usually extends up to infinity or could even result in NaNs. While infinities are really the next representable numbers in the corresponding mode, REAL_VALUE_TYPE is actually a type with wider range for exponent and 160 bit precision, so the patch instead uses nextafter number in a hypothetical floating point format with the same mantissa precision but wider range of exponents. This significantly improves the actual ranges of the reverse operations, while still making them conservatively correct. The second part is a fix for miscompilation of the new testcase below. For -ffinite-math-only, without this patch we extend the minimum and/or maximum representable finite number to -Inf or +Inf, with the patch to some number outside of the normal exponent range of the mode, but then we use set which canonicalizes it and turns the boundaries back to the minimum and/or maximum representable finite numbers, but because in say [__DBL_MAX__, __DBL_MAX__] = op1 + [__DBL_MAX__, __DBL_MAX__] op1 can be larger than 0, up to the largest number which rounds to even down back to __DBL_MAX__ and there are still no infinities involved, it needs to work even with -ffinite-math-only. So, we really need to widen the lhs range a little bit even in that case. The patch does that through temporarily clearing -ffinite-math-only, such that the value with infinities or the outside of bounds values passes the setting and verification (the VR_VARYING case is needed because we get ICEs otherwise, but when lhs is VR_VARYING in -ffast-math, i.e. minimum to maximum representable finite and both signs of NaN, then set does all we need, we don't need to or in a NaN range). We don't really later use the range in a way that would become a problem that it is wider than varying, we actually just perform maths on the two boundaries. As I said in the PR, this doesn't fix the !MODE_HAS_INFINITIES case, I believe we actually need to treat the boundary values as infinities in that case because they (probably) work like that, but it is unclear if it is just the reverse operation lhs widening that is a problem there, or whether it is a general problem. I have zero experience with floating points without infinities (PDP11, some ARM half type?, what else?). 2023-03-10 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/109008 * range-op-float.cc (float_widen_lhs_range): If lb is minimum representable finite number or ub is maximum representable finite number, instead of widening it to -inf or inf widen it to negative or positive 0x0.8p+(EMAX+1). Temporarily clear flag_finite_math_only when canonicalizing the widened range. * gcc.dg/pr109008.c: New test.
2023-03-09range-op-float: Fix up reverse binary operations [PR109008]Jakub Jelinek1-24/+57
The following testcase is reduced from miscompilation of scipy package. If we have say lhs = [1., 1.] - [1., 1.] and want to compute the range of lhs from it, we correctly determine it is [0., 0.] (if computations are exact, we generally don't try to round them further in frange_arithmetic). In the testcase it is about a reverse operation, [1., 1.] = op1 + [1., 1.] and we want to compute range of op1 from that. Right now we just perform the inverse operation (there are some corner cases about NaN and infinities handling) and so arrive to range [0., 0.] as well, and because it is a singleton, optimize return eps; to return 0. That is incorrect though, for the reverse ops we need to take into account also rounding, the right exact range is [-0x1.0p-54, 0x1.0p-53] in this case when rounding to nearest, i.e. all numbers which added to 1. with round to nearest still produce 1. The problem isn't solely on singleton ranges, and isn't solely on results around zero. We basically need to consider also values where the result is up to 0.5ulp away from the lhs range boundaries in each direction. The following patch fixes it by extending the lhs range for the reverse operations by 1ulp in each direction. The PR contains a pseudo-random test generator I've used to generate 300000 tests of + and - and then used the same test with * and / instead of + and - together with a hack to print the discovered ranges by the patch in a form that another test could then verify the range is conservatively correct and how far it is from a minimal range. I believe the results are good enough for now, though plan to look incrementally into trying to do something better on the -XXX_MAX or XXX_MAX boundaries (where I think frange_nextafter will use -inf or +inf) and also try to increase the range just by 0.5ulp rather than 1ulp if !flag_rounding_math. But dunno if either of those will be doable and will pass the testing, so I think it is worth committing this fix first. 2023-03-09 Jakub Jelinek <jakub@redhat.com> Richard Biener <rguenther@suse.de> PR tree-optimization/109008 * range-op-float.cc (float_widen_lhs_range): New function. (foperator_plus::op1_range, foperator_minus::op1_range, foperator_minus::op2_range, foperator_mult::op1_range, foperator_div::op1_range, foperator_div::op2_range): Use it. * gcc.c-torture/execute/ieee/pr109008.c: New test.
2023-02-03range-ops: Handle undefined ranges in frange op[12]_range [PR108647]Aldy Hernandez1-0/+56
This patch gracefully handles undefined operand ranges for the floating point op[12]_range operators. This is very low risk, as we would have ICEd otherwise. We don't have a testcase that ICEs for floating point ranges, but it's only a matter of time. Besides, this dovetails nicely with the integer versions Jakub is testing. gcc/ChangeLog: PR tree-optimization/108647 * range-op-float.cc (foperator_lt::op1_range): Handle undefined ranges. (foperator_lt::op2_range): Same. (foperator_le::op1_range): Same. (foperator_le::op2_range): Same. (foperator_gt::op1_range): Same. (foperator_gt::op2_range): Same. (foperator_ge::op1_range): Same. (foperator_ge::op2_range): Same. (foperator_unordered_lt::op1_range): Same. (foperator_unordered_lt::op2_range): Same. (foperator_unordered_le::op1_range): Same. (foperator_unordered_le::op2_range): Same. (foperator_unordered_gt::op1_range): Same. (foperator_unordered_gt::op2_range): Same. (foperator_unordered_ge::op1_range): Same. (foperator_unordered_ge::op2_range): Same.
2023-01-26frange: Fix up foperator_{,not_}equal::fold_range for signed zeros [PR108540]Jakub Jelinek1-5/+35
The following testcases are miscompiled, because threader sees some SSA_NAME would have -0.0 value and when computing range of SSA_NAME == 0.0 foperator_equal::fold_range sees one operand has [-0.0, -0.0] singleton range, the other [0.0, 0.0], they aren't equal (frange operator== uses real_identical etc. rather than real comparisons) and so it thinks they compare unequal. With signed zeros -0.0 == 0.0 is true though, so we need to special case the both ranges singleton code. Similarly, if we see op1 range being say [-42.0, -0.0] and op2 range [0.0, 42.0], we'd check that the intersection of the two ranges is empty (that is correct) and fold the result of == between such operands to [0, 0] which is wrong, because -0.0 == 0.0, it needs to be [0, 1]. Similarly for foperator_not_equal::fold_range. 2023-01-26 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/108540 * range-op-float.cc (foperator_equal::fold_range): If both op1 and op2 are singletons, use range_true even if op1 != op2 when one range is [-0.0, -0.0] and another [0.0, 0.0]. Similarly, even if intersection of the ranges is empty and one has zero low bound and another zero high bound, use range_true_and_false rather than range_false. (foperator_not_equal::fold_range): If both op1 and op2 are singletons, use range_false even if op1 != op2 when one range is [-0.0, -0.0] and another [0.0, 0.0]. Similarly, even if intersection of the ranges is empty and one has zero low bound and another zero high bound, use range_true_and_false rather than range_true. * gcc.c-torture/execute/ieee/pr108540-1.c: New test. * gcc.c-torture/execute/ieee/pr108540-2.c: New test.
2023-01-15[PR107608] [range-ops] Avoid folding into INF when flag_trapping_math.Aldy Hernandez1-0/+21
As discussed in the PR, for trapping math, do not fold overflowing operations into +-INF as doing so could elide a trap. There is a minor adjustment to known_isinf() where it was mistakenly returning true for an [infinity U NAN], whereas it should only return true when the range is exclusively +INF or -INF. This is benign, as there were no users of known_isinf up to now. Tested on x86-64 Linux. I also ran the glibc testsuite (git sources) on x86-64 and this patch fixes: -FAIL: math/test-double-lgamma -FAIL: math/test-double-log1p -FAIL: math/test-float-lgamma -FAIL: math/test-float-log1p -FAIL: math/test-float128-catan -FAIL: math/test-float128-catanh -FAIL: math/test-float128-lgamma -FAIL: math/test-float128-log -FAIL: math/test-float128-log1p -FAIL: math/test-float128-y0 -FAIL: math/test-float128-y1 -FAIL: math/test-float32-lgamma -FAIL: math/test-float32-log1p -FAIL: math/test-float32x-lgamma -FAIL: math/test-float32x-log1p -FAIL: math/test-float64-lgamma -FAIL: math/test-float64-log1p -FAIL: math/test-float64x-lgamma -FAIL: math/test-ldouble-lgamma PR tree-optimization/107608 gcc/ChangeLog: * range-op-float.cc (range_operator_float::fold_range): Avoid folding into INF when flag_trapping_math. * value-range.h (frange::known_isinf): Return false for possible NANs.
2023-01-02Update copyright years.Jakub Jelinek1-1/+1
2022-12-08range-op-float: frange_arithmetic tweaks for MODE_COMPOSITE_PJakub Jelinek1-16/+46
As mentioned in PR107967, ibm-ldouble-format documents that +- has 1ulp accuracy, * 2ulps and / 3ulps. So, even if the result is exact, we need to widen the range a little bit. The following patch does that. I just wonder what it means for reverse division (the op1_range case), which we implement through multiplication, when division has 3ulps error and multiplication just 2ulps. In any case, this format is a mess and for non-default rounding modes can't be trusted at all, instead of +inf or something close to it it happily computes -inf. 2022-12-08 Jakub Jelinek <jakub@redhat.com> * range-op-float.cc (frange_nextafter): For MODE_COMPOSITE_P from denormal or zero, use real_nextafter on DFmode with conversions around it. (frange_arithmetic): For mode_composite, on top of rounding in the right direction accept extra 1ulp error for PLUS/MINUS_EXPR, extra 2ulps error for MULT_EXPR and extra 3ulps error for RDIV_EXPR.
2022-12-08range-op-float: Fix up frange_arithmetic [PR107967]Jakub Jelinek1-3/+36
The addition of PLUS/MINUS/MULT/RDIV_EXPR frange handlers causes miscompilation of some of the libm routines, resulting in lots of glibc test failures. A part of them is purely PR107608 fold-overflow-1.c etc. issues, say when the code does return -0.5 / 0.0; and expects division by zero to be emitted, but we propagate -Inf and avoid the operation. But there are also various tests where we end up with different computed value from the expected ones. All those cases are like: is: inf inf should be: 1.18973149535723176502e+4932 0xf.fffffffffffffff0p+16380 is: inf inf should be: 1.18973149535723176508575932662800701e+4932 0x1.ffffffffffffffffffffffffffffp+16383 is: inf inf should be: 1.7976931348623157e+308 0x1.fffffffffffffp+1023 is: inf inf should be: 3.40282346e+38 0x1.fffffep+127 and the corresponding source looks like: static const double huge = 1.0e+300; double whatever (...) { ... return huge * huge; ... } which for rounding to nearest or +inf should and does return +inf, but for rounding to -inf or 0 should instead return nextafter (inf, -inf); The rules IEEE754 has are that operations on +-Inf operands are exact and produce +-Inf (except for the invalid ones that produce NaN) regardless of rounding mode, while overflows: "a) roundTiesToEven and roundTiesToAway carry all overflows to ∞ with the sign of the intermediate result. b) roundTowardZero carries all overflows to the format’s largest finite number with the sign of the intermediate result. c) roundTowardNegative carries positive overflows to the format’s largest finite number, and carries negative overflows to −∞. d) roundTowardPositive carries negative overflows to the format’s most negative finite number, and carries positive overflows to +∞." The behavior around overflows to -Inf or nextafter (-inf, inf) was actually handled correctly, we'd construct [-INF, -MAX] ranges in those cases because !real_less (&value, &result) in that case - value is finite but larger in magnitude than what the format can represent (but GCC internal's format can), while result is -INF in that case. But for the overflows to +Inf or nextafter (inf, -inf) was handled incorrectly, it tested real_less (&result, &value) rather than !real_less (&result, &value), the former test is true when already the rounding value -> result rounded down and in that case we shouldn't round again, we should round down when it didn't. So, in theory this could be fixed just by adding one ! character, - if ((mode_composite || (real_isneg (&inf) ? real_less (&result, &value) + if ((mode_composite || (real_isneg (&inf) ? !real_less (&result, &value) : !real_less (&value, &result))) but the following patch goes further. The distance between nextafter (inf, -inf) and inf is large (infinite) and expressions like 1.0e+300 * 1.0e+300 always produce +inf in round to nearest mode by far, so I think having low bound of nextafter (inf, -inf) in that case is unnecessary. But if it isn't multiplication but say addition and we are inexact and very close to the boundary between rounding to nearest maximum representable vs. rounding to nearest +inf, still using [MAX, +INF] etc. ranges seems safer because we don't know exactly what we lost in the inexact computation. The following patch implements that. 2022-12-08 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/107967 * range-op-float.cc (frange_arithmetic): Fix a thinko - if inf is negative, use nextafter if !real_less (&result, &value) rather than if real_less (&result, &value). If result is +-INF while value is finite and -fno-rounding-math, don't do rounding if !inexact or if result is significantly above max representable value or below min representable value. * gcc.dg/pr107967-1.c: New test. * gcc.dg/pr107967-2.c: New test. * gcc.dg/pr107967-3.c: New test.
2022-12-06range-op-float: Improve binary reverse operationsJakub Jelinek1-4/+29
On Mon, Dec 05, 2022 at 02:29:36PM +0100, Aldy Hernandez wrote: > > So like this for multiplication op1/2_range if it passes bootstrap/regtest? > > For division I'll need to go to a drawing board... > > Sure, looks good to me. Ulrich just filed PR107972, so in the light of that PR the following patch attempts to do that differently. As for testcase, I've tried both attached testcases, but unfortunately it seems that in neither of the cases we actually figure out that res range is finite (or for last function non-zero ordered). So there is further work needed on that. 2022-12-06 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/107972 * range-op-float.cc (frange_drop_infs): New function. (float_binary_op_range_finish): Add DIV_OP2 argument. If DIV_OP2 is false and lhs is finite or if DIV_OP2 is true and lhs is non-zero and not NAN, r must be finite too. (foperator_div::op2_range): Pass true to DIV_OP2 of float_binary_op_range_finish.
2022-12-06range-op-float: Fix up ICE in lower_bound [PR107975]Jakub Jelinek1-0/+6
According to https://gcc.gnu.org/pipermail/gcc-regression/2022-December/077258.html my patch caused some ICEs, e.g. the following testcase ICEs. The problem is that lower_bound and upper_bound methods on a france assert that the range isn't VR_NAN or VR_UNDEFINED. All the op1_range/op2_range methods already return early if lhs.undefined_p, but the other cases (when lhs is VR_NAN or the other opN is VR_NAN or VR_UNDEFINED) aren't. float_binary_op_range_finish will DTRT for those cases already. 2022-12-06 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/107975 * range-op-float.cc (foperator_mult::op1_range, foperator_div::op1_range, foperator_div::op2_range): Just return float_binary_op_range_finish result if lhs is known NAN, or the other operand is known NAN or UNDEFINED. * gcc.dg/pr107975.c: New test.
2022-12-05range-op-float: Fix up multiplication and division reverse operation [PR107879]Jakub Jelinek1-8/+66
While for the normal cases it seems to be correct to implement reverse multiplication (op1_range/op2_range) through division with float_binary_op_range_finish, reverse division (op1_range) through multiplication with float_binary_op_range_finish or (op2_range) through division with float_binary_op_range_finish, as e.g. following testcase shows for the corner cases it is incorrect. Say on the testcase we are doing reverse multiplication, we have [-0., 0.] range (no NAN) on lhs and VARYING on op1 (or op2). We implement that through division, because x from lhs = x * op2 is x = lhs / op2 For the division, [-0., 0.] / VARYING is computed (IMHO correctly) as [-0., 0.] +-NAN, because 0 / anything but 0 or NAN is still 0 and 0 / 0 is NAN and ditto 0 / NAN. And then we just float_binary_op_range_finish, which figures out that because lhs can't be NAN, neither operand can be NAN. So, the end range is [-0., 0.]. But that is not correct for the reverse multiplication. When the result is 0, if op2 can be zero, then x can be anything (VARYING), to be precise anything but INF (unless result can be NAN), because anything * 0 is 0 (or NAN for INF). While if op2 must be non-zero, then x must be 0. Of course the sign logic (signbit(x) = signbit(lhs) ^ signbit(op2)) still holds, so it actually isn't full VARYING if both lhs and op2 have known sign bits. And going through other corner cases one by one shows other differences between what we compute for the corresponding forward operation and what we should compute for the reverse operations. The following patch is slightly conservative and includes INF (in case of result including 0 and not NAN) in the ranges or 0 in the ranges (in case of result including INF and not NAN). The latter is what happens anyway because we flush denormals to 0, and the former just not to deal with all the corner cases. So, the end test is that for reverse multiplication and division op2_range the cases we need to adjust to VARYING or VARYING positive or VARYING negative are if lhs and op? ranges both contain 0, or both contain some infinity, while for division op1_range the corner case is if lhs range contains 0 and op2 range contains INF or vice versa. Otherwise I believe ranges from the corresponding operation are ok, or could be slightly more conservative (e.g. for reverse multiplication, if op? range is singleton INF and lhs range doesn't include any INF, then x's range should be UNDEFINED or known NAN (depending on if lhs can be NAN), while the division computes [-0., 0.] +-NAN; or similarly if op? range is only 0 and lhs range doesn't include 0, division would compute +INF +-NAN, or -INF +-NAN, or (for lack of multipart franges -INF +INF +-NAN just VARYING +-NAN), while again it is UNDEFINED or known NAN. Oh, and I found by code inspection wrong condition for the division's known NAN result, due to thinko it would trigger not just when both operands are known to be 0 or both are known to be INF, but when either both are known to be 0, or at least one is known to be INF. 2022-12-05 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/107879 * range-op-float.cc (foperator_mult::op1_range): If both lhs and op2 ranges contain zero or both ranges contain some infinity, set r range to zero_to_inf_range depending on signbit_known_p. (foperator_div::op2_range): Similarly for lhs and op1 ranges. (foperator_div::op1_range): If lhs range contains zero and op2 range contains some infinity or vice versa, set r range to zero_to_inf_range depending on signbit_known_p. (foperator_div::rv_fold): Fix up condition for returning known NAN.
2022-11-17[PR tree-optimization/107732] [range-ops] Handle attempt to abs() negatives.Aldy Hernandez1-1/+1
The threader is creating a scenario where we are trying to solve: [NEGATIVES] = abs(x) While solving this we have an intermediate value of UNDEFINED because we have no positive numbers. But then we try to union the negative pair to the final result by querying the bounds. Since neither UNDEFINED nor NAN have bounds, they need to be specially handled. PR tree-optimization/107732 gcc/ChangeLog: * range-op-float.cc (foperator_abs::op1_range): Early exit when result is undefined. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr107732.c: New test.
2022-11-17[range-ops] Minor readability fix.Aldy Hernandez1-2/+4
gcc/ChangeLog: * range-op-float.cc (range_operator_float::fold_range): Make check for maybe_isnan more readable.
2022-11-16ragen-op-float: Fix up float_binary_op_range_finish [PR107668]Jakub Jelinek1-1/+2
The following testcase ICEs, because when !HONOR_NANS but HONOR_SIGNED_ZEROS, if we see lhs = op1 * op2; and know that lhs is [-0.0, 0.0] and op2 is [0.0, 0.0], the division of these two yields UNDEFINED and clear_nan () on it fails an assert. With HONOR_NANS it would actually result in a known NAN, but when NANs aren't honored, we clear the NAN bits. Now, for the above case we actually don't know anything about the op1 range (except that it isn't a NAN/INF because of !HONOR_NANS !HONOR_INFINITIES), so I think the best is just to return VARYING for the case we get UNDEFINED as well. If we want, the op[12]_range methods perhaps can handle the corner cases earlier separately, say for lhs [0.0, 0.0] and op2 [0.0, 0.0] when HONOR_SIGNED_ZEROS this would be just [0.0, MAX]. 2022-11-16 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/107668 * range-op-float.cc (float_binary_op_range_finish): Set VARYING also when r is UNDEFINED. * gcc.dg/ubsan/pr107668.c: New test.
2022-11-12[range-ops] Add ability to represent open intervals in frange.Aldy Hernandez1-4/+19
Currently we represent < and > with a closed interval. So < 3.0 is represented as [-INF, +3.0]. This means 3.0 is included in the range, and though not ideal, is conservatively correct. Jakub has found a couple cases where properly representing < and > would help optimizations and tests, and this patch allows representing open intervals with real_nextafter. There are a few caveats. First, we leave MODE_COMPOSITE_P types pessimistically as a closed interval. Second, for -ffinite-math-only, real_nextafter will saturate the maximum representable number into +INF. However, this will still do the right thing, as frange::set() will crop things appropriately. Finally, and most frustratingly, representing < and > -+0.0 is problematic because we flush denormals to zero. Let me explain... real_nextafter(+0.0, +INF) gives 0x0.8p-148 as expected, but setting a range to this value yields [+0.0, 0x0.8p-148] because of the flushing. On the other hand, real_nextafter(+0.0, -INF) (surprisingly) gives -0.0.8p-148, but setting a range to that value yields [-0.0x8p-148, -0.0]. I say surprising, because according to cppreference.com, std::nextafter(+0.0, -INF) should give -0.0. But that's neither here nor there because our flushing denormals to zero prevents us from even representing ranges involving small values around 0.0. We ultimately end up with ranges looking like this: > +0.0 => [+0.0, INF] > -0.0 => [+0.0, INF] < +0.0 => [-INF, -0.0] < -0.0 => [-INF, -0.0] I suppose this is no worse off that what we had before with closed intervals. One could even argue that we're better because we at least have the right sign now ;-). gcc/ChangeLog: * range-op-float.cc (build_lt): Adjust with frange_nextafter instead of default to a closed range. (build_gt): Same.
2022-11-12range-op: Implement op[12]_range operators for {PLUS,MINUS,MULT,RDIV}_EXPRJakub Jelinek1-0/+131
On Wed, Nov 09, 2022 at 04:43:56PM +0100, Aldy Hernandez wrote: > On Wed, Nov 9, 2022 at 3:58 PM Jakub Jelinek <jakub@redhat.com> wrote: > > > > On Wed, Nov 09, 2022 at 10:02:46AM +0100, Aldy Hernandez wrote: > > > We can implement the op[12]_range entries for plus and minus in terms > > > of each other. These are adapted from the integer versions. > > > > I think for NANs the op[12]_range shouldn't act this way. > > For the forward binary operations, we have the (maybe/known) NAN handling > > of one or both NAN operands resulting in VARYING sign (maybe/known) NAN > > result, that is the somehow the case for the reverse binary operations too, > > if result is (maybe/known) NAN and the other op is not NAN, op is > > VARYING sign (maybe/known) NAN, if other op is (maybe/known) NAN, > > then op is VARYING sign maybe NAN (always maybe, never known). > > But then for + we have the -INF + INF or vice versa into NAN, and that > > is something that shouldn't be considered. If result isn't NAN, then > > neither operand can be NAN, regardless of whether result can be > > +/- INF and the other op -/+ INF. > > Heh. I just ran into this while debugging the problem reported by Xi. > > We are solving NAN = op1 - VARYING, and trying to do it with op1 = NAN > + VARYING, which returns op1 = NAN (incorrectly). > > I suppose in the above case op1 should ideally be > [-INF,-INF][+INF,+INF]+-NAN, but since we can't represent that then > [-INF,+INF] +-NAN, which is actually VARYING. Do you agree? > > I'm reverting this patch as attached, while I sort this out. Here is a patch which reinstalls your change, add the fixups I've talked about and also hooks up reverse operators for MULT_EXPR/RDIV_EXPR. 2022-11-12 Aldy Hernandez <aldyh@redhat.com> Jakub Jelinek <jakub@redhat.com> * range-op-float.cc (float_binary_op_range_finish): New function. (foperator_plus::op1_range): New. (foperator_plus::op2_range): New. (foperator_minus::op1_range): New. (foperator_minus::op2_range): New. (foperator_mult::op1_range): New. (foperator_mult::op2_range): New. (foperator_div::op1_range): New. (foperator_div::op2_range): New. * gcc.c-torture/execute/ieee/inf-4.c: New test.
2022-11-12range-op: Cleanup floating point multiplication and division fold_range ↵Jakub Jelinek1-196/+157
[PR107569] Admittedly there are many similar spots with the foperator_div case (but also with significant differences), so perhaps if foperator_{mult,div} inherit from some derived class from range_operator_float and that class would define various smaller helper static? methods, like this discussed in the PR - contains_zero_p, singleton_nan_p, zero_p, that + bool must_have_signbit_zero = false; + bool must_have_signbit_nonzero = false; + if (real_isneg (&lh_lb) == real_isneg (&lh_ub) + && real_isneg (&rh_lb) == real_isneg (&rh_ub)) + { + if (real_isneg (&lh_lb) == real_isneg (&rh_ub)) + must_have_signbit_zero = true; + else + must_have_signbit_nonzero = true; + } returned as -1/0/1 int, and those set result (based on the above value) to [+INF, +INF], [-INF, -INF] or [-INF, +INF] or [+0, +0], [-0, -0] or [-0, +0] or [+0, +INF], [-INF, -0] or [-INF, +INF] and the + for (int i = 1; i < 4; ++i) + { + if (real_less (&cp[i], &cp[0]) + || (real_iszero (&cp[0]) && real_isnegzero (&cp[i]))) + std::swap (cp[i], cp[0]); + if (real_less (&cp[4], &cp[i + 4]) + || (real_isnegzero (&cp[4]) && real_iszero (&cp[i + 4]))) + std::swap (cp[i + 4], cp[4]); + } block, it could be smaller and more readable. 2022-11-12 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/107569 * range-op-float.cc (zero_p, contains_p, singleton_inf_p, signbit_known_p, zero_range, inf_range, zero_to_inf_range): New functions. (foperator_mult_div_base): New class. (foperator_mult, foperator_div): Derive from that and use protected static method from it as well as above new functions to simplify the code.
2022-11-12range-op: Implement floating point division fold_range [PR107569]Jakub Jelinek1-0/+178
Here is the floating point division fold_range implementation, as I wrote in the last mail, we could outline some of the common parts into static methods with descriptive names and share them between foperator_div and foperator_mult. Regressions are +FAIL: gcc.dg/pr95115.c execution test +FAIL: libphobos.phobos/std/math/hardware.d execution test +FAIL: libphobos.phobos_shared/std/math/hardware.d execution test The first test is we have: # RANGE [frange] double [] +-NAN _3 = Inf / Inf; if (_3 ord _3) goto <bb 3>; [INV] else goto <bb 4>; [INV] <bb 3> : abort (); <bb 4> : before evrp, the range is correct, Inf / Inf is known NAN of unknown sign. evrp correctly folds _3 ord _3 into false and the _3 = Inf / Inf; remains in the IL, but then comes dse1 and removes it as dead statement. So, I think yet another example of the PR107608 problems where DCE? removes dead statements which raise floating point exceptions. And -fno-delete-dead-exceptions doesn't help. 2022-11-12 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/107569 * range-op-float.cc (foperator_div): New class. (floating_op_table::floating_op_table): Use foperator_div for RDIV_EXPR.
2022-11-12range-op: Implement floating point multiplication fold_range [PR107569]Jakub Jelinek1-6/+185
The following patch implements frange multiplication, including the special case of x * x. The callers don't tell us that it is x * x, just that it is either z = x * x or if (x == y) z = x * y; For irange that makes no difference, but for frange it can mean x is -0.0 and y is 0.0 if they have the same range that includes both signed and unsigned zeros, so we need to assume result could be -0.0. The patch causes one regression: +FAIL: gcc.dg/fold-overflow-1.c scan-assembler-times 2139095040 2 but that is already tracked in PR107608 and affects not just the newly added multiplication, but addition and other floating point operations (and doesn't seem like a ranger bug but dce or whatever else). 2022-11-12 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/107569 PR tree-optimization/107591 * range-op.h (range_operator_float::rv_fold): Add relation_kind argument. * range-op-float.cc (range_operator_float::fold_range): Name last argument trio and pass trio.op1_op2 () as last argument to rv_fold. (range_operator_float::rv_fold): Add relation_kind argument. (foperator_plus::rv_fold, foperator_minus::rv_fold): Likewise. (foperator_mult): New class. (floating_op_table::floating_op_table): Use foperator_mult for MULT_EXPR.
2022-11-09Revert op[12]_range operators for PLUS_EXPR and MINUS_EXPR.Aldy Hernandez1-45/+0
Revert the patch below until issues are resolved: commit 4287e8168f89e90b3dff3a50f3ada40be53e0e01 Author: Aldy Hernandez <aldyh@redhat.com> Date: Wed Nov 9 01:00:57 2022 +0100 Implement op[12]_range operators for PLUS_EXPR and MINUS_EXPR. We can implement the op[12]_range entries for plus and minus in terms of each other. These are adapted from the integer versions. gcc/ChangeLog: * range-op-float.cc (class foperator_plus): Remove op[12]_range. (class foperator_minus): Same.
2022-11-09Fix up foperator_abs::op1_range [PR107569]Jakub Jelinek1-3/+4
foperator_abs::op1_range works except for the NaN handling, from: [frange] double [-Inf, 1.79769313486231570814527423731704356798070567525844996599e+308 (0x0.fffffffffffff8p+1024)] lhs it computes r [frange] double [-1.79769313486231570814527423731704356798070567525844996599e+308 (-0x0.fffffffffffff8p+1024), 1.79769313486231570814527423731704356798070567525844996599e+308 +(0x0.fffffffffffff8p+1024)] +-NAN which is correct except for the +-NAN part. For r before the final step it makes sure to add -NAN if there is +NAN in the lhs range, but the final r.union_ makes it unconditional +-NAN, because the frange ctor sets +-NAN. So, I think we need to clear it (or have some set variant which says not to set NAN). This patch fixes that, but isn't enough to fix the PR, something in the assumptions handling is still broken (and the PR has other parts). 2022-11-09 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/107569 * range-op-float.cc (foperator_abs::op1_range): Clear NaNs from the negatives frange before unioning it into r.