I've been able to get it to do the right thing by changing the line
where it initially folds the source of the SET. That is line 4639 in
cse.c: /* Simplify and foldable subexpressions in SRC. Then get the
fully- simplified result, which may not necessarily be valid. */
src_folded = fold_rtx (src, insn);
In this instance SRC is: (plus:SI (mult:SI (sign_extend:SI (subreg:HI
(reg:SI 136) 0)) (sign_extend:SI (subreg:HI (reg:SI 138) 0))) (reg:SI
141))
and the resulting src_folded is: (plus:SI (mult:SI (reg:SI 136)
(reg:SI 138)) (reg:SI 141))
However, fold_rtx also modifies src itself, so after the call to
fold_rtx both src and src_folded contain the plus+mult form without
the extends. So further down in cse_insn where it does the cost
analysis of src, src_folded and other expressions it never considers
the original form of src. Changing that call to fold_rtx to not
modify its argument like so: src_folded = fold_rtx (src, 0); // An
argument of 0 means "make a copy of src before modifying"
fixes the testcase and allows CSE to properly select the cheaper
multiply-extend-add form and doesn't seem to regress codegen in any
way on SPEC2006 for arm. Archeology says this line has been that way
since forever, so does anyone know of the rationale for passing insn
to fold_rtx in that callsite?