range-op: Fix some divisions [PR127092]
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_simplebootstrap_build--master-aarch64-bootstrap |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap |
success
|
Build passed
|
Commit Message
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 <andrew.pinski@oss.qualcomm.com>
---
gcc/range-op.cc | 9 ++++++++-
gcc/testsuite/gfortran.dg/pr127092-1.f90 | 21 +++++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gfortran.dg/pr127092-1.f90
Comments
On Tue, Sep 1, 2026 at 2:51 PM Andrea Pinski
<andrew.pinski@oss.qualcomm.com> wrote:
>
> 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.
OK.
> 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 <andrew.pinski@oss.qualcomm.com>
> ---
> gcc/range-op.cc | 9 ++++++++-
> gcc/testsuite/gfortran.dg/pr127092-1.f90 | 21 +++++++++++++++++++++
> 2 files changed, 29 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/gfortran.dg/pr127092-1.f90
>
> diff --git a/gcc/range-op.cc b/gcc/range-op.cc
> index 76c52bf897e..350548951f4 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 00000000000..0602e88c512
> --- /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
> --
> 2.43.0
>
@@ -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;
new file mode 100644
@@ -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