In AArch64, ISel create Copy instructions to move function parameters to virtual registers in the entry block. If the parameters are live across a function call, then RA would allocate CSRs for such Copys in the entry.
We should be able to sink such Copy instructions if there is no use in the entry block, but MachineSink (before RA) cannot sink such Copys because SreReg is an allocatable PhyReg. After RA, there is no pass which try to sink such Copy instruction, so shrink-wrapping pass often miss opportunity because the first def of CSR is in the entry block.
This change try to encourage more shrink-wrapping by sinking Copys of which DestReg is CSR from the entry to successors if there there is no use in the entry.
In the IR below, one of the parameter (%paramAcrossCall) live across a function call, but it's only used in %BB0. Currently, in AArch64, we create a "COPY %X19, %W0 " in the entry for this parameter, which prevent this function from being shrink-wrapped. Since this COPY in the entry block is not used in the entry, we can sink it to %BB0, then this function will be shrink-wrapped.
define i32 @shrinkwrapme(i32 %paramAcrossCall, i32 %paramNotAcrossCall) { entry: %cmp5 = icmp sgt i32 %paramNotAcrossCall, 0 br i1 %cmp5, label %BB0, label %Exit BB0: %call = call i32 @fun() %add = add i32 %call, %paramAcrossCall ret i32 %add Exit: ret i32 0 }
With this change I observed 10% more shrink-wrapping happened in spec2000/2006/2017.
For now, I perform this only in the entry block as a way to encourage shrink-wrapping, but we might be able to make this more general as a separate pass like Post-RA machine sink. Please let me know any thought.
I think a MIR test would show the use case of this patch much better here.