[gcc r13-10445] i386: Fix ICE on out of bounds vector elt access [PR126446]

Jakub Jelinek via Gcc-cvs <[email protected]> Sat, 1 Aug 2026 10:58:26 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:24d86ca3ffd089c0636949da6923d73dba9e0d37

commit r13-10445-g24d86ca3ffd089c0636949da6923d73dba9e0d37
Author: Jakub Jelinek <[email protected]>
Date:   Wed Jul 29 10:15:11 2026 +0200

    i386: Fix ICE on out of bounds vector elt access [PR126446]
    
    The following testcase ICEs on x86_64.
    The isel pass has a check for out of bounds constant index before
    optimizing into .VEC_SET, but it does it using
          // if index is a constant, then check the bounds
          poly_uint64 idx_poly;
          if (poly_int_tree_p (idx, &idx_poly))
            {
              poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (view_op0));
              if (known_gt (idx_poly, nelts))
                return false;
            }
    In the testcase below, idx is INTEGER_CST with long long type and
    negative value, that doesn't fit into poly_uint64, so we happily convert
    it into .VEC_SET.
    
    And another problem is that the x86 backend isn't trying to be careful
    and handle out of bounds elt gracefully (I think it could still in theory
    happen, if GIMPLE lets it through but e.g. something during expansion
    figures out the index is constant or whatever).
    
    The following patch fixes it in the backend to avoid triggering UB at compile
    time by doing HOST_WIDE_INT_1U << elt etc. when elt is negative or too
    large.  In order to avoid ICE, we need to emit something, so I emit
    a no-op move, out of bounds vector set shouldn't change anything in
    the target.
    
    gimple-isel.cc will be changed incrementally.
    
    2026-07-29  Jakub Jelinek  <[email protected]>
    
            PR target/126446
            * config/i386/i386-expand.cc (ix86_expand_vector_set): If elt is
            out of bounds, emit a no-op move.
    
            * gcc.target/i386/avx2-pr126446.c: New test.
    
    Reviewed-by: Uros Bizjak <[email protected]>
    (cherry picked from commit 1bc2fdc4f4cbe1b68237f49f211473c56d8a44a3)

Diff:
---
 gcc/config/i386/i386-expand.cc                |  5 +++++
 gcc/testsuite/gcc.target/i386/avx2-pr126446.c | 14 ++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 410cebd2f1f5..3392a99c6d4a 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -16724,6 +16724,11 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
   machine_mode mmode = VOIDmode;
   rtx (*gen_blendm) (rtx, rtx, rtx, rtx);
 
+  if (!IN_RANGE (elt, 0, GET_MODE_NUNITS (mode)))
+    {
+      emit_move_insn (target, target);
+      return;
+    }
   switch (mode)
     {
     case E_V2SImode:
diff --git a/gcc/testsuite/gcc.target/i386/avx2-pr126446.c b/gcc/testsuite/gcc.target/i386/avx2-pr126446.c
new file mode 100644
index 000000000000..4af8cfd283c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx2-pr126446.c
@@ -0,0 +1,14 @@
+/* PR target/126446 */
+/* { dg-do compile } */
+/* { dg-options "-O1 -mavx2" } */
+
+typedef signed char V __attribute__((vector_size (16)));
+
+signed char
+foo ()
+{
+  V b = {};
+  long long c = ~2878966870562407444LL;
+  b[c] = 1;
+  return b[0];
+}