]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
vect: Don't set excess bits in unform masks
authorAndrew Stubbs <ams@codesourcery.com>
Fri, 20 Oct 2023 15:26:51 +0000 (16:26 +0100)
committerAndrew Stubbs <ams@codesourcery.com>
Fri, 10 Nov 2023 11:54:59 +0000 (11:54 +0000)
AVX ignores any excess bits in the mask (at least for vector sizes >=8), but
AMD GCN magically uses a larger vector than was intended (the smaller sizes are
"fake"), leading to wrong-code.

This patch fixes amdgcn execution failures in gcc.dg/vect/pr81740-1.c,
gfortran.dg/c-interop/contiguous-1.f90,
gfortran.dg/c-interop/ff-descriptor-7.f90, and others.

gcc/ChangeLog:

* expr.cc (store_constructor): Add "and" operation to uniform mask
generation.

gcc/expr.cc

index ed4dbb13d8936d6097e0e5279a10e034dd3a6157..3e2a678710d689ad71ee48fa145fe725bccb64d9 100644 (file)
@@ -7470,7 +7470,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
            break;
          }
        /* Use sign-extension for uniform boolean vectors with
-          integer modes.  */
+          integer modes.  Effectively "vec_duplicate" for bitmasks.  */
        if (!TREE_SIDE_EFFECTS (exp)
            && VECTOR_BOOLEAN_TYPE_P (type)
            && SCALAR_INT_MODE_P (mode)
@@ -7479,7 +7479,19 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
          {
            rtx op0 = force_reg (TYPE_MODE (TREE_TYPE (elt)),
                                 expand_normal (elt));
-           convert_move (target, op0, 0);
+           rtx tmp = gen_reg_rtx (mode);
+           convert_move (tmp, op0, 0);
+
+           /* Ensure no excess bits are set.
+              GCN needs this for nunits < 64.
+              x86 needs this for nunits < 8.  */
+           auto nunits = TYPE_VECTOR_SUBPARTS (type).to_constant ();
+           if (maybe_ne (GET_MODE_PRECISION (mode), nunits))
+             tmp = expand_binop (mode, and_optab, tmp,
+                                 GEN_INT ((1 << nunits) - 1), target,
+                                 true, OPTAB_DIRECT);
+           if (tmp != target)
+             emit_move_insn (target, tmp);
            break;
          }