The comment above expand_vector_broadcast() states a precondition that
the mode of op must be the element mode of vmode.  But when
expand_binop() called expand_vector_broadcast() to broadcast the shift
amount, it only truncated the shift amount if it's too wide, but no
action is performed if the shift amount is too narrow.

        PR middle-end/124250
        PR target/123807

gcc/
        * optabs.cc (expand_vector_broadcast): Add a checking assert to
        verify the precondition about the input modes.
        (expand_binop): Extend the shift amount if it's narrower than
        the element of the shifted vector.

gcc/testsuite/

        * gcc.c-torture/compile/pr124250.c: New test.
---

Bootstrapped and regtested on x86_64-linux-gnu and
loongarch64-linux-gnu.  Ok for trunk?

 gcc/optabs.cc                                 | 34 +++++++++++++------
 .../gcc.c-torture/compile/pr124250.c          |  8 +++++
 2 files changed, 31 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr124250.c

diff --git a/gcc/optabs.cc b/gcc/optabs.cc
index e813cf9b215..249413c7576 100644
--- a/gcc/optabs.cc
+++ b/gcc/optabs.cc
@@ -428,9 +428,9 @@ force_expand_binop (machine_mode mode, optab binoptab,
   return true;
 }
 
-/* Create a new vector value in VMODE with all elements set to OP.  The
-   mode of OP must be the element mode of VMODE.  If OP is a constant,
-   then the return value will be a constant.  */
+/* Create a new vector value in VMODE with all elements set to OP.  If OP
+   is not a constant, the mode of it must be the element mode of VMODE.
+   If OP is a constant, then the return value will be a constant.  */
 
 rtx
 expand_vector_broadcast (machine_mode vmode, rtx op)
@@ -439,6 +439,8 @@ expand_vector_broadcast (machine_mode vmode, rtx op)
   rtvec vec;
 
   gcc_checking_assert (VECTOR_MODE_P (vmode));
+  gcc_checking_assert (CONST_INT_P (op)
+                      || GET_MODE_INNER (vmode) == GET_MODE (op));
 
   if (valid_for_const_vector_p (vmode, op))
     return gen_const_vec_duplicate (vmode, op);
@@ -1629,15 +1631,25 @@ expand_binop (machine_mode mode, optab binoptab, rtx 
op0, rtx op1,
       if (otheroptab
          && (icode = optab_handler (otheroptab, mode)) != CODE_FOR_nothing)
        {
-         /* The scalar may have been extended to be too wide.  Truncate
-            it back to the proper size to fit in the broadcast vector.  */
+         /* The scalar may be wider or narrower than the vector element.
+            Truncate or extend it to the proper size to fit in the
+            broadcast vector.  */
          scalar_mode inner_mode = GET_MODE_INNER (mode);
-         if (!CONST_INT_P (op1)
-             && (GET_MODE_BITSIZE (as_a <scalar_int_mode> (GET_MODE (op1)))
-                 > GET_MODE_BITSIZE (inner_mode)))
-           op1 = force_reg (inner_mode,
-                            simplify_gen_unary (TRUNCATE, inner_mode, op1,
-                                                GET_MODE (op1)));
+         if (!CONST_INT_P (op1))
+           {
+             auto mode1 = as_a <scalar_int_mode> (GET_MODE (op1));
+             int size1 = GET_MODE_BITSIZE (mode1);
+             int inner_size = GET_MODE_BITSIZE (inner_mode);
+
+             if (size1 != inner_size)
+               {
+                 auto unary = size1 > inner_size ? TRUNCATE : ZERO_EXTEND;
+                 op1 = force_reg (inner_mode,
+                                  simplify_gen_unary (unary, inner_mode,
+                                                      op1, mode1));
+               }
+           }
+
          rtx vop1 = expand_vector_broadcast (mode, op1);
          if (vop1)
            {
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr124250.c 
b/gcc/testsuite/gcc.c-torture/compile/pr124250.c
new file mode 100644
index 00000000000..1435091dc0b
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr124250.c
@@ -0,0 +1,8 @@
+typedef long long v2i64 __attribute__ ((vector_size (16), aligned (16)));
+v2i64 a, b;
+
+void
+test (int l)
+{
+  a = b >> (-l);
+}
-- 
2.53.0

Reply via email to