https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87600
--- Comment #3 from Segher Boessenkool <segher at gcc dot gnu.org> --- Here is an example for aarch64: === long f(long x) { register long a asm("x0"); asm("bla %0 %1" : "+&r"(a) : "r"(x)); return a; } === The first asm operand is a local register variable set to x0, so this one should end up in x0. But "x" is passed in x0 as function argument, and then combined into the asm, making both asm operands hard register 0. And then LRA has the job of making things work (operand 0 is earlyclobber so not both args can be hard reg 0), and LRA picks the wrong solution: bla x1 x0 Not letting combine combine the register moves that copy from the function argument registers into pseudos fixes this. But it costs 1%-5% of code size on all targets (most are about 2%): most targets can usefully combine register moves into other instructions, for example many targets have operations that set a flags register as side effect. I'm going to try to disallow combining the hard reg -> pseudo moves, because that should help with the register alloc problems (it also gives better register alloc!), but at the same time introducing an extra copy (from pseudo to a new pseudo). In theory this should be the best of both worlds.