When FastISel hands over code selection to SelectionDAGISel, it should flush the local value map in order to avoid pushing local value instructions to the top of the basic block, which may cause unnecessary spills in the presence of calls.
Example:
struct X { int F(); }; void foo(); int main() { foo(); int (X::*mp)() = &X::F; // FastISel quits because of this store return 0; }
generates the following:
subq $32, %rsp xorl %eax, %eax <== local value instruction, spill occurs movl $0, -4(%rbp) movl %eax, -28(%rbp) # 4-byte Spill callq _Z3foov movq $0, -16(%rbp) movq $_ZN1X1FEv, -24(%rbp) movl -28(%rbp), %eax # 4-byte Reload addq $32, %rsp popq %rbp retq
with the proposed fix, the code is
subq $32, %rsp movl $0, -4(%rbp) callq _Z3foov movq $0, -16(%rbp) movq $_ZN1X1FEv, -24(%rbp) xorl %eax, %eax <=== local value instruction now after the call addq $32, %rsp popq %rbp retq
Two test cases needed adjustment:
- test/CodeGen/Mips/emergency-spill-slot-near-fp.ll
Returning %argc instead of 0 ensures that the test case needs to emergency-spill the %gpr scratch register. Otherwise the code gen improvement from the FastISel change would render it unnecessary, interfering with the goal of the test.
- test/DebugInfo/X86/vla.ll
The original case narrowly checked for %RDX and DW_OP_breg1. Make this a bit more flexible, otherwise different register assignments can lead to failures.