Hi gcc-patches mailing list,
Christopher Bazley via Sourceware Forge 
<[email protected]> has requested that the 
following forgejo pull request
be published on the mailing list.

Created on: 2026-06-12 15:12:52+00:00
Latest update: 2026-06-12 15:22:03+00:00
Changes: 2 changed files, 71 additions, 0 deletions
Head revision: chris.bazley/gcc ref pr125767 commit 
c692b66804a7441fd5cdcda4921035724fc8ec16
Base revision: gcc/gcc-TEST ref trunk commit 
c6133f911ea5ae4a4df59079c6299593fdec8afc r17-1517-gc6133f911ea5ae
Merge base: c6133f911ea5ae4a4df59079c6299593fdec8afc
Full diff url: https://forge.sourceware.org/gcc/gcc-TEST/pulls/176.diff
Discussion:  https://forge.sourceware.org/gcc/gcc-TEST/pulls/176
Requested Reviewers:

PR middle-end/125767

When the magnitude of the divisor is known to be bigger
than that of the dividend, the output quotient should be 1
when divisor and dividend have the same sign or -1
when they have opposite signs.

Previously, can_div_away_from_zero_p was overreliant on
can_div_trunc_p: if can_div_trunc_p returned a failure
indication then can_div_away_from_zero_p did likewise.

This matters because can_div_away_from_zero_p is commonly
used to answer questions such as "How many registers does
this value occupy?" If the register has a scalable vector
type, then the answer should be 1 if the number of bits
occupied by the value is known to be not greater than
the minimum number of bits in the vector type (as well as
if the number of bits occupied by the value is known to be
smaller). Previously, can_div_away_from_zero_p had to be
used with care to avoid wrongly concluding that a value of
type V16QI would not fit in a register of type VNx16QI.
That could cause selection of inefficient instruction
sequences or even an ICE in cases where V8QI in VNx16QI
behaved as expected.

Because polynomial division truncated toward zero can
fail to produce a constant quotient in cases where
polynomial division rounded away from zero can produce a
constant quotient, it is not sufficient for the
implementation of can_div_away_from_zero_p to simply adjust
the quotient produced by can_div_trunc_p.

can_div_trunc_p requires |b * Q| <= |a| whereas
can_div_away_from_zero_p requires |b * Q| >= |a|. The
latter can be proven in cases where the former cannot.
For example, when a = 16 + 0i and b = 16 + 16i, |b * Q|
cannot be smaller than |a| unless Q = 0, which would
violate a common requirement that |a - b * Q| < |b|
(because |a| >= 16 and |b| >= 16). In contrast, |b * Q|
is bigger than |a| if Q > 1 or i > 0. Crucially, it's
impossible to know the value of i at compile time, so
can_div_trunc_p must conservatively return false.

Another way of looking at it is:
Q = (16 + 0i) / (16 + 16i)
  = 16 / (16 + 16i)
  = 1 / (1 + i)

which is not "some constant Q" that these functions must
find in order to return true; however, we can be sure that
whatever the unknowable value of 1 / (1 + i) is, it lies
within the range 0 < Q <= 1. We cannot know whether that
answer should be truncated to zero, but we can know that
it should be rounded to one.

gcc/ChangeLog:

        * poly-int.h (can_div_away_from_zero_p):
        Exit early if |a| <= |b| instead of calling
        can_div_trunc_p and returning false if it
        returned false.

gcc/testsuite/ChangeLog:

        * gcc.dg/plugin/poly-int-tests.h: New test cases.


Changed files:
- M: gcc/poly-int.h
- M: gcc/testsuite/gcc.dg/plugin/poly-int-tests.h


Christopher Bazley (1):
  Handle divisor bigger than dividend in can_div_away_from_zero_p

 gcc/poly-int.h                               | 39 ++++++++++++++++++++
 gcc/testsuite/gcc.dg/plugin/poly-int-tests.h | 32 ++++++++++++++++
 2 files changed, 71 insertions(+)

-- 
2.54.0

Reply via email to