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.
