https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124250
--- Comment #6 from Xi Ruoyao <xry111 at gcc dot gnu.org> ---
I'm testing this:
diff --git a/gcc/optabs.cc b/gcc/optabs.cc
index e813cf9b215..0dbee1b53e5 100644
--- a/gcc/optabs.cc
+++ b/gcc/optabs.cc
@@ -439,6 +439,7 @@ expand_vector_broadcast (machine_mode vmode, rtx op)
rtvec vec;
gcc_checking_assert (VECTOR_MODE_P (vmode));
+ gcc_checking_assert (GET_MODE_INNER (vmode) == GET_MODE (op));
if (valid_for_const_vector_p (vmode, op))
return gen_const_vec_duplicate (vmode, op);
@@ -1629,15 +1630,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)
{