https://gcc.gnu.org/g:dc9b5b53de1d2ce50e028495163931bb16673f80
commit r14-12496-gdc9b5b53de1d2ce50e028495163931bb16673f80 Author: Eric Botcazou <[email protected]> Date: Tue Mar 31 18:42:19 2026 +0200 Fix internal error on non-byte-sized reference in GIMPLE DSE This is a regression present on all the active branches and a sibling of: https://gcc.gnu.org/pipermail/gcc-patches/2024-February/646628.html during GIMPLE pass: dse +===========================GNAT BUG DETECTED==============================+ | 16.0.1 20260331 (experimental) [master r16-8354-gbf6989de817] GCC error:| | in exact_div, at poly-int.h:2179 | | Error detected around opt107.adb:26:11 | | Compiling opt107.adb At least one caller of compute_trims, namely maybe_trim_constructor_store, expects ref->size to be a multiple of a byte for trimming, and that is most probably the case for others in practice, from a cursory reading. Therefore the patch adds the same test on ref->size as the one added to ref->offset. gcc/ * tree-ssa-dse.cc (compute_trims): Bail out if ref->size is not byte aligned either. gcc/testsuite/ * gnat.dg/opt107.adb: New test. * gnat.dg/opt107_pkg.ads: New helper. Diff: --- gcc/testsuite/gnat.dg/opt107.adb | 27 ++++++ gcc/testsuite/gnat.dg/opt107_pkg.ads | 156 +++++++++++++++++++++++++++++++++++ gcc/tree-ssa-dse.cc | 6 +- 3 files changed, 187 insertions(+), 2 deletions(-) diff --git a/gcc/testsuite/gnat.dg/opt107.adb b/gcc/testsuite/gnat.dg/opt107.adb new file mode 100644 index 000000000000..438558530327 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt107.adb @@ -0,0 +1,27 @@ +-- { dg-do compile } +-- { dg-options "-O" } + +with Opt107_Pkg; use Opt107_Pkg; + +function Opt107 return Rec is + R : Rec; +begin + R.W1A := B_A_7; + R.W1B := 0; + R.W1C := C_A; + R.W1D := (Spare => 0, + D_A => 0, + D_B => 0, + D_C => 0, + D_D => 0); + R.W2B := (Spare => 0, + E_A => 0, + E_B => 0, + E_C => 0, + E_D => 0, + E_E => 0, + E_F => 0, + E_G => 0, + E_H => 0); + return R; +end; diff --git a/gcc/testsuite/gnat.dg/opt107_pkg.ads b/gcc/testsuite/gnat.dg/opt107_pkg.ads new file mode 100644 index 000000000000..9ac737ffa271 --- /dev/null +++ b/gcc/testsuite/gnat.dg/opt107_pkg.ads @@ -0,0 +1,156 @@ +with System; +with Unchecked_Conversion; + +package Opt107_Pkg is + + Word_Size : constant := 32; + type Word_Type is mod 2 ** Word_Size; + for Word_Type'Size use Word_Size; + + Word : constant := Word_Size / System.Storage_Unit; + + Halfword_Size : constant := Word_Size / 2; + + type Halfword_Type is range 0 .. 2 ** Halfword_Size - 1; + for Halfword_Type'Size use Halfword_Size; + + type One_Bit_Type is mod 2 ** 1; + for One_Bit_Type'Size use 1; + + type Four_Bit_Type is mod 2 ** 4; + for Four_Bit_Type'Size use 4; + + type Seven_Bit_Type is mod 2 ** 7; + for Seven_Bit_Type'Size use 7; + + type Eight_Bit_Type is mod 2 ** 8; + for Eight_Bit_Type'Size use 8; + + type Twelve_Bit_Type is mod 2 ** 12; + for Twelve_Bit_Type'Size use 12; + + type Thirty_One_Bit_Type is mod 2 ** 31; + for Thirty_One_Bit_Type'Size use 31; + + type W0_Type is record + A : Eight_Bit_Type; + B : Eight_Bit_Type; + C : Halfword_Type; + end record; + + for W0_Type use record + A at Word * 0 range 24 .. 31; + B at Word * 0 range 16 .. 23; + C at Word * 0 range 0 .. 15; + end record; + for W0_Type'Size use Word_Size; + + type A_Type is (A0, A1); + for A_Type use (A0 => 0, A1 => 1); + for A_Type'Size use 1; + + type B_Type is (B_A_1, + B_A_2, + B_A_3, + B_A_4, + B_A_5, + B_A_6, + B_A_7, + B_A_8, + B_B_1, + B_B_2, + B_B_3, + B_B_4, + B_B_5, + B_B_6, + B_B_7, + B_B_8); + + for B_Type use (B_A_1 => 8#00#, + B_A_2 => 8#01#, + B_A_3 => 8#02#, + B_A_4 => 8#03#, + B_A_5 => 8#04#, + B_A_6 => 8#05#, + B_A_7 => 8#06#, + B_A_8 => 8#07#, + B_B_1 => 8#10#, + B_B_2 => 8#11#, + B_B_3 => 8#12#, + B_B_4 => 8#13#, + B_B_5 => 8#14#, + B_B_6 => 8#15#, + B_B_7 => 8#16#, + B_B_8 => 8#17#); + for B_Type'Size use 8; + + type C_Type is (C_A, C_B); + for C_Type use (C_A => 0, C_B => 2); + for C_Type'Size use 4; + + type D_Type is record + Spare : Twelve_Bit_Type; + D_A : One_Bit_Type; + D_B : One_Bit_Type; + D_C : One_Bit_Type; + D_D : One_Bit_Type; + end record; + + for D_Type use record + Spare at 0 range 4 .. 15; + D_A at 0 range 3 .. 3; + D_B at 0 range 2 .. 2; + D_C at 0 range 1 .. 1; + D_D at 0 range 0 .. 0; + end record; + for D_Type'Size use Halfword_Size; + + type E_Type is record + Spare : Seven_Bit_Type; + E_A : One_Bit_Type; + E_B : One_Bit_Type; + E_C : One_Bit_Type; + E_D : One_Bit_Type; + E_E : One_Bit_Type; + E_F : One_Bit_Type; + E_G : One_Bit_Type; + E_H : One_Bit_Type; + end record; + + for E_Type use record + Spare at 0 range 8 .. 14; + E_A at 0 range 7 .. 7; + E_B at 0 range 6 .. 6; + E_C at 0 range 5 .. 5; + E_D at 0 range 4 .. 4; + E_E at 0 range 3 .. 3; + E_F at 0 range 2 .. 2; + E_G at 0 range 1 .. 1; + E_H at 0 range 0 .. 0; + end record; + for E_Type'Size use 15; + + type Rec is record + W0 : W0_Type; + W1A : B_Type; + W1B : Four_Bit_Type; + W1C : C_Type; + W1D : D_Type; + W2A : A_Type; + W2B : E_Type; + W2C : Halfword_Type; + end record; + + for Rec use record + W0 at Word * 0 range 0 .. 31; + W1A at Word * 1 range 24 .. 31; + W1B at Word * 1 range 20 .. 23; + W1C at Word * 1 range 16 .. 19; + W1D at Word * 1 range 0 .. 15; + W2A at Word * 2 range 31 .. 31; + W2B at Word * 2 range 16 .. 30; + W2C at Word * 2 range 0 .. 15; + end record; + for Rec'Size use 6 * Halfword_Size; + +end Opt107_Pkg; diff --git a/gcc/tree-ssa-dse.cc b/gcc/tree-ssa-dse.cc index b587df745077..e6ccc387a004 100644 --- a/gcc/tree-ssa-dse.cc +++ b/gcc/tree-ssa-dse.cc @@ -424,8 +424,10 @@ compute_trims (ao_ref *ref, sbitmap live, int *trim_head, int *trim_tail, the bitmap extends through ref->max_size, so we know that in the original bitmap bits 0 .. ref->max_size were true. But we need to check that this covers the bytes of REF exactly. */ - const unsigned int align = known_alignment (ref->offset); - if ((align > 0 && align < BITS_PER_UNIT) + const unsigned int offset_align = known_alignment (ref->offset); + const unsigned int size_align = known_alignment (ref->size); + if ((offset_align > 0 && offset_align < BITS_PER_UNIT) + || (size_align > 0 && size_align < BITS_PER_UNIT) || !known_eq (ref->size, ref->max_size)) return;
