Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1376,6 +1376,14 @@ TLI.getFrameIndexTy(DAG.getDataLayout())); } + // 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 = FuncInfo.getArgumentFrameIndex(Arg); + if (FI != INT_MAX) + return DAG.getFrameIndex(FI, TLI.getFrameIndexTy(DAG.getDataLayout())); + } + // If this is an instruction which fast-isel has deferred, select it now. if (const Instruction *Inst = dyn_cast(V)) { unsigned InReg = FuncInfo.InitializeRegForValue(Inst); Index: lib/CodeGen/SelectionDAG/StatepointLowering.cpp =================================================================== --- lib/CodeGen/SelectionDAG/StatepointLowering.cpp +++ lib/CodeGen/SelectionDAG/StatepointLowering.cpp @@ -522,7 +522,14 @@ // 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 the argument is a static frame index, use it without spilling. + if (isa(V) || + (isa(V) && + Builder.FuncInfo.getArgumentFrameIndex(cast(V)) != INT_MAX)) + Incoming = Builder.getNonRegisterValue(V); + else + Incoming = Builder.getValue(V); const bool LiveInValue = LiveInDeopt && !isGCValue(V); lowerIncomingStatepointValue(Incoming, LiveInValue, Ops, Builder); } Index: test/CodeGen/X86/statepoint-stack-usage.ll =================================================================== --- test/CodeGen/X86/statepoint-stack-usage.ll +++ test/CodeGen/X86/statepoint-stack-usage.ll @@ -133,4 +133,27 @@ declare i32 @"personality_function"() +; 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: leaq 16(%rsp), %rdi +; Should not spill fixed stack address. +; CHECK-NOT: movq %rdi, (%rsp) +; CHECK: callq +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_isVoidp0s_structsf(i64, i32, void (%struct*)*, i32, i32, ...) + attributes #1 = { uwtable }