YunQiang Su <s...@gcc.gnu.org> writes: > On TRULY_NOOP_TRUNCATION_MODES_P (DImode, SImode)) == true platforms, > if 31 or above bits is polluted by an bitops, we will need an > truncate. Let's emit one, and mark let's use the same hardreg > as in and out, the RTL may like: > > (insn 21 20 24 2 (set (subreg/s/u:SI (reg/v:DI 200 [ val ]) 0) > (truncate:SI (reg/v:DI 200 [ val ]))) "../xx.c":7:29 -1 > (nil)) > > We use /s/u flags to mark it as really needed, as in > combine_simplify_rtx, this insn may be considered as truncated, > so let's skip this combination. > > gcc/ChangeLog: > PR: 104914. > * combine.cc (try_combine): Skip combine with truncate if > dest is subreg and has /u/s flags on platforms > TRULY_NOOP_TRUNCATION_MODES_P (DImode, SImode)) == true. > * expr.cc (expand_assignment): Emit a truncate insn, if > 31+ bits is polluted for SImode. > > gcc/testsuite/ChangeLog: > PR: 104914. > * gcc.target/mips/pr104914.c: New testcase.
Sorry for not looking at this earlier. I've got a bit lost in the various threads, so apologies if this has been discussed already but I think the fix is: diff --git a/gcc/expr.cc b/gcc/expr.cc index 4f42c0ff487..9847eba19fe 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -6275,9 +6275,8 @@ expand_assignment (tree to, tree from, bool nontemporal) else { rtx to_rtx1 - = lowpart_subreg (subreg_unpromoted_mode (to_rtx), - SUBREG_REG (to_rtx), - subreg_promoted_mode (to_rtx)); + = convert_to_mode (subreg_unpromoted_mode (to_rtx), + SUBREG_REG (to_rtx), false); result = store_field (to_rtx1, bitsize, bitpos, bitregion_start, bitregion_end, mode1, from, get_alias_set (to), (completely untested apart from the test case). That should still produce a subreg on most targets, but generates the required trunc on MIPS. Thanks, Richard