https://gcc.gnu.org/g:32e917d19d943af990bc46ad2cc70ed45a963127

commit r15-11025-g32e917d19d943af990bc46ad2cc70ed45a963127
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 19c0977adf1f..a35794167bcf 100644
--- a/gcc/tree-ssa-dse.cc
+++ b/gcc/tree-ssa-dse.cc
@@ -423,8 +423,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;

Reply via email to