https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117811
Andrew Pinski <pinskia at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Component|target |middle-end --- Comment #13 from Andrew Pinski <pinskia at gcc dot gnu.org> --- So this is a middle-end issue. So expand_binop does: ``` /* Record where to delete back to if we backtrack. */ last = get_last_insn (); ... 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. */ 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))); rtx vop1 = expand_vector_broadcast (mode, op1); if (vop1) { temp = expand_binop_directly (icode, mode, otheroptab, op0, vop1, target, unsignedp, methods, last); if (temp) return temp; } ``` But then inside expand_binop_directly, does: ``` /* If PAT is composed of more than one insn, try to add an appropriate REG_EQUAL note to it. If we can't because TEMP conflicts with an operand, call expand_binop again, this time without a target. */ if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && ! add_equal_note (pat, ops[0].value, optab_to_code (binoptab), ops[1].value, ops[2].value, mode0)) { delete_insns_since (last); return expand_binop (mode, binoptab, op0, op1, NULL_RTX, unsignedp, methods); } ``` And then the expand_vector_broadcast is lost because last points to right before the dup. But last here is wrong, it deletes too much. It should have been the last insn at the entry of expand_binop_directly instead of last argument.