https://gcc.gnu.org/g:0acb69bf9bb0db14b7e230fb5370257c530fb6e8

commit r17-3869-g0acb69bf9bb0db14b7e230fb5370257c530fb6e8
Author: Andrea Pinski <[email protected]>
Date:   Mon Aug 31 21:22:49 2026 -0700

    range-op: Fix some divisions [PR127092]
    
    This was an oversight of not knowing there are a few different
    integer divisions and how they will round.
    When `a < b` and for non-negative a and b, `a/b` will be 0 iff for
    truncate (TRUNC_DIV_EXPR), exact (EXACT_DIV_EXPR)
    and floor division (FLOOR_DIV_EXPR).
    Ceiling division (CEIL_DIV_EXPR) will be 1 for positive a and zero when a 
is 0.
    Rounding division (ROUND_DIV_EXPR) it is based on the how far a is from b.
    We can skip the ceiling division case since it is not used that much.
    And rounding division case is too hard to figure out here so that is skipped
    also.
    
    Bootstrapped and tested on x86_64-linux-gnu.
    
            PR tree-optimization/127092
    
    gcc/ChangeLog:
    
            * range-op.cc (operator_div::op1_op2_relation_effect): Only
            handle TRUNC_DIV_EXPR, EXACT_DIV_EXPR and FLOOR_DIV_EXPR
            for the `a < b` case.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/pr127092-1.f90: New test.
    
    Signed-off-by: Andrea Pinski <[email protected]>

Diff:
---
 gcc/range-op.cc                          |  9 ++++++++-
 gcc/testsuite/gfortran.dg/pr127092-1.f90 | 21 +++++++++++++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 76c52bf897ea..350548951f45 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2647,8 +2647,15 @@ operator_div::op1_op2_relation_effect (irange &lhs_range,
     /* op1/op2 = 0 if op1 < op2 and both op1 and op2
        are known positives.  */
     case VREL_LT:
+      // Exact, and truncate division will produce 0 for this case.
+      // Floor division will be treated similar to truncate div as rounding 
towards
+      //  to 0 is the same as rounding towards -inf for positive values.
+      if (m_code != EXACT_DIV_EXPR
+         && m_code != TRUNC_DIV_EXPR
+         && m_code != FLOOR_DIV_EXPR)
+       return false;
       if (!op1_range.nonnegative_p ()
-          || !op2_range.nonnegative_p ())
+         || !op2_range.nonnegative_p ())
        return false;
       rel_range.set_zero (type);
       break;
diff --git a/gcc/testsuite/gfortran.dg/pr127092-1.f90 
b/gcc/testsuite/gfortran.dg/pr127092-1.f90
new file mode 100644
index 000000000000..0602e88c5129
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr127092-1.f90
@@ -0,0 +1,21 @@
+! PR tree-optimization/127092
+! { dg-do run }
+
+
+program main
+  implicit none
+  if (transfer_count(3, 8) /= 1) error stop 1
+contains
+  integer function transfer_count(n, m)
+    integer, intent(in) :: n, m
+    character(len=n) :: source
+    character(len=m) :: mold(1)
+    if (len(source, kind=8) >= len(mold, kind=8)) then
+      transfer_count = -1
+      return
+    end if
+    source = ""
+    mold = ""
+    transfer_count = size(transfer(source, mold))
+  end function
+end program

Reply via email to