https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125984

--- Comment #7 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The releases/gcc-15 branch has been updated by Eric Botcazou
<[email protected]>:

https://gcc.gnu.org/g:54a701d1f8e55df52626b866719cd780bca06f2a

commit r15-11509-g54a701d1f8e55df52626b866719cd780bca06f2a
Author: Eric Botcazou <[email protected]>
Date:   Tue Aug 25 22:50:50 2026 +0200

    Fix optimization of up-level reference to array with negative low bound

    The problem is that the DSE pass incorrectly deletes a store to an up-level
    reference to an array with negative low bound:

    Deleted dead store: FRAME.19.s[0]{lb: 18446744073709551613 sz: 8} = 0.0;

    because IPA modref incorrectly flags it as dead for this call:

    ipa-modref: call stmt opt110.term (1, 0,
    2.37000000000000010658141036401502788066864013671875e+0,
    2.7932300000000000181898940354585647583007813e+3); [static-chain:
&FRAME.19]
    ipa-modref: call to Opt110.Term/3 does not use ref: FRAME.19.s[0]{lb:
    18446744073709551613 sz: 8} alias sets: 13->11

    The array at stake is declared with a negative low bound:

    N : constant := 3;

    S : array (-N..0) of REAL;

    The origin of the problem is visible when you compare the modref1 and
    modref2 dump files:

     - Analyzing load: CHAIN.20_21(D)->s[_7]{lb: 18446744073709551613 sz: 8}
     (can throw; marking side effects)    - Recording base_set=0 ref_set=0
     Static hain param offset:0 offset:960 size:64 max_size:256

    vs

     - Analyzing load: CHAIN.20_12(D)->s[_4]{lb: 18446744073709551613 sz: 8}
     (can throw; marking side effects)    - Recording base_set=0 ref_set=0
     Static chain param offset:0 offset:960 size:64 max_size:192

    The max_size has been incorrectly shrunk from 256 to 192 bits, the missing
    64 bits being the FRAME.19.s[0]{lb: 18446744073709551613 sz: 8} element.

    The problematic code is in get_ref_base_and_extent:

            if (TREE_CODE (index) == SSA_NAME
                && (low_bound = array_ref_low_bound (exp),
                    poly_int_tree_p (low_bound))
                && (unit_size = array_ref_element_size (exp),
                    TREE_CODE (unit_size) == INTEGER_CST)
                && query->range_of_expr (vr, index)
                && !vr.varying_p ()
                && !vr.undefined_p ())
              {
                wide_int min = vr.lower_bound ();
                wide_int max = vr.upper_bound ();
                poly_offset_int lbound = wi::to_poly_offset (low_bound);
                /* Try to constrain maxsize with range information. */

    It uses the range of the index expression to constrain the maxsize:

    [irange] sizetype [0, 0][18446744073709551613, +INF]

    but that's not correct in the general case, the correct range being instead
    the range of the difference between the low bound and the index expression,
    as implemented by the model computation in get_inner_reference:

    [irange] sizetype [0, 3]

    Of course this makes no difference for the C family of languages where the
    low bound is always 0.

    gcc/
            PR ada/125984
            * tree-dfa.cc (get_ref_base_and_extent) <ARRAY_REF>: Use the range
            of the difference between the index expression and the low bound,
            instead of that of the index expression itself, to constrain the
            maximum size of the access.

    gcc/testsuite/
            * gnat.dg/opt110.adb: New test.

Reply via email to