Index: lib/CodeGen/SelectionDAG/StatepointLowering.cpp =================================================================== --- lib/CodeGen/SelectionDAG/StatepointLowering.cpp +++ lib/CodeGen/SelectionDAG/StatepointLowering.cpp @@ -522,7 +522,16 @@ // The vm state arguments are lowered in an opaque manner. We do not know // what type of values are contained within. for (const Value *V : SI.DeoptState) { - SDValue Incoming = Builder.getValue(V); + SDValue Incoming; + // If this is a function argument at a static frame index, generate it as + // the frame index. + if (const Argument *Arg = dyn_cast(V)) { + int FI = Builder.FuncInfo.getArgumentFrameIndex(Arg); + if (FI != INT_MAX) + Incoming = Builder.DAG.getFrameIndex(FI, Builder.getFrameIndexTy()); + } + if (!Incoming.getNode()) + Incoming = Builder.getValue(V); const bool LiveInValue = LiveInDeopt && !isGCValue(V); lowerIncomingStatepointValue(Incoming, LiveInValue, Ops, Builder); } Index: test/CodeGen/X86/statepoint-stackmap-format.ll =================================================================== --- test/CodeGen/X86/statepoint-stackmap-format.ll +++ test/CodeGen/X86/statepoint-stackmap-format.ll @@ -96,9 +96,33 @@ ret i32 %ld } +; Test that function arguments at fixed stack offset +; can be directly encoded in the stack map, without +; spilling. +%struct = type { i64, i64, i64 } + +declare void @use(%struct*) + +define void @test_fixed_arg(%struct* byval %x) gc "statepoint-example" { +; CHECK-LABEL: test_fixed_arg +; CHECK: pushq %rax +; CHECK: leaq 16(%rsp), %rdi +; Should not spill fixed stack address. +; CHECK-NOT: movq %rdi, (%rsp) +; CHECK: callq use +; CHECK: popq %rax +; CHECK: retq +entry: + br label %bb + +bb: ; preds = %entry + %statepoint_token = call token (i64, i32, void (%struct*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidp0s_structsf(i64 0, i32 0, void (%struct*)* @use, i32 1, i32 0, %struct* %x, i32 0, i32 1, %struct* %x) + ret void +} declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...) declare token @llvm.experimental.gc.statepoint.p0f_isVoidi64i64i64i64i64i64i64i64f(i64, i32, void (i64, i64, i64, i64, i64, i64, i64, i64)*, i32, i32, ...) +declare token @llvm.experimental.gc.statepoint.p0f_isVoidp0s_structsf(i64, i32, void (%struct*)*, i32, i32, ...) declare i1 @llvm.experimental.gc.result.i1(token) declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32) #3 @@ -109,11 +133,11 @@ ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .short 0 ; Num Functions -; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 5 ; Num LargeConstants ; CHECK-NEXT: .long 0 ; Num Callsites -; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 5 ; Functions and stack size ; CHECK-NEXT: .quad test @@ -128,6 +152,9 @@ ; CHECK-NEXT: .quad test_spadj ; CHECK-NEXT: .quad 8 ; CHECK-NEXT: .quad 1 +; CHECK-NEXT: .quad test_fixed_arg +; CHECK-NEXT: .quad 8 +; CHECK-NEXT: .quad 1 ; ; test @@ -421,3 +448,59 @@ ; CHECK: .short 0 ; CHECK: .short 0 ; CHECK: .p2align 3 + +; +; test_fixed_arg + +; Statepoint ID +; CHECK-NEXT: .quad 0 + +; Instruction Offset +; CHECK-NEXT: .long .Ltmp4-test_fixed_arg + +; Reserved: +; CHECK: .short 0 + +; NumLocations: +; CHECK: .short 4 + +; StkMapRecord[0]: +; SmallConstant(0): +; CHECK: .byte 4 +; CHECK-NEXT: .byte 0 +; CHECK: .short 8 +; CHECK: .short 0 +; CHECK-NEXT: .short 0 +; CHECK: .long 0 + +; StkMapRecord[1]: +; SmallConstant(0): +; CHECK: .byte 4 +; CHECK-NEXT: .byte 0 +; CHECK: .short 8 +; CHECK: .short 0 +; CHECK-NEXT: .short 0 +; CHECK: .long 0 + +; StkMapRecord[2]: +; SmallConstant(1): +; CHECK: .byte 4 +; CHECK-NEXT: .byte 0 +; CHECK: .short 8 +; CHECK: .short 0 +; CHECK-NEXT: .short 0 +; CHECK: .long 1 + +; StkMapRecord[3]: +; Direct RSP+16 +; CHECK: .byte 2 +; CHECK-NEXT: .byte 0 +; CHECK: .short 8 +; CHECK: .short 7 +; CHECK-NEXT: .short 0 +; CHECK: .long 16 + +; No padding or LiveOuts +; CHECK: .short 0 +; CHECK: .short 0 +; CHECK: .p2align 3