Hi!
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 does 2 things (both are enough to avoid the ICE).
One is to also punt if idx is clearly negative (doesn't fit into
poly_uint64 but fits into poly_int64).
And the second fix is 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.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Now that I look at the patch, I think the if (known_gt (idx_poly, nelts))
above is wrong as well, I think it should be
if (known_ge (idx_poly, nelts))
because vector set is out of bounds even when accessing nelts index.
If you agree, I can post an incremental patch.
2026-07-28 Jakub Jelinek <[email protected]>
PR target/126446
* gimple-isel.cc (gimple_expand_vec_set_extract_expr): Punt if
idx doesn't fit into poly_uint64 but fits into poly_int64.
* 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.
--- gcc/gimple-isel.cc.jj 2026-07-22 09:42:52.010559350 +0200
+++ gcc/gimple-isel.cc 2026-07-28 13:07:46.663422172 +0200
@@ -96,10 +96,11 @@ gimple_expand_vec_set_extract_expr (stru
return false;
tree op0 = TREE_OPERAND (ref, 0);
- if (TREE_CODE (op0) == VIEW_CONVERT_EXPR && DECL_P (TREE_OPERAND (op0, 0))
+ if (TREE_CODE (op0) == VIEW_CONVERT_EXPR
+ && DECL_P (TREE_OPERAND (op0, 0))
&& VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0)))
- && TYPE_MODE (TREE_TYPE (ref))
- == TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0)))))
+ && (TYPE_MODE (TREE_TYPE (ref))
+ == TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0))))))
{
tree pos = TREE_OPERAND (ref, 1);
@@ -114,6 +115,10 @@ gimple_expand_vec_set_extract_expr (stru
if (known_gt (idx_poly, nelts))
return false;
}
+ else if (tree_fits_poly_int64_p (idx))
+ // if idx doesn't fit into poly_uint64, but fits into poly_int64,
+ // it must be negative
+ return false;
machine_mode outermode = TYPE_MODE (TREE_TYPE (view_op0));
machine_mode extract_mode = TYPE_MODE (TREE_TYPE (ref));
--- gcc/config/i386/i386-expand.cc.jj 2026-07-24 11:52:32.590640836 +0200
+++ gcc/config/i386/i386-expand.cc 2026-07-28 13:04:52.711678590 +0200
@@ -19157,6 +19157,11 @@ ix86_expand_vector_set (bool mmx_ok, rtx
machine_mode mmode = VOIDmode;
rtx (*gen_blendm) (rtx, rtx, rtx, rtx);
+ if (elt < 0 || elt >= GET_MODE_NUNITS (mode))
+ {
+ emit_move_insn (target, target);
+ return;
+ }
if (TARGET_SSE4_1 && mode == V4SImode && val == const0_rtx)
{
emit_insn (gen_sse4_1_insertps_v4si_zero (target, target,
--- gcc/testsuite/gcc.target/i386/avx2-pr126446.c.jj 2026-07-28
13:15:10.373701905 +0200
+++ gcc/testsuite/gcc.target/i386/avx2-pr126446.c 2026-07-28
13:14:54.663904357 +0200
@@ -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];
+}
Jakub