Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -1930,6 +1930,7 @@ // Verify that the types of the call parameter arguments match // the type of the wrapped callee. + AttributeList Attrs = CS.getAttributes(); for (int i = 0; i < NumParams; i++) { Type *ParamType = TargetFuncType->getParamType(i); Type *ArgType = CS.getArgument(5 + i)->getType(); @@ -1937,6 +1938,12 @@ "gc.statepoint call argument does not match wrapped " "function type", &CI); + + if (TargetFuncType->isVarArg()) { + AttributeSet ArgAttrs = Attrs.getParamAttributes(5 + i); + Assert(!ArgAttrs.hasAttribute(Attribute::StructRet), + "Attribute 'sret' cannot be used for vararg call arguments!", &CI); + } } const int EndCallArgsInx = 4 + NumCallArgs; @@ -2814,8 +2821,13 @@ SawReturned = true; } - Assert(!ArgAttrs.hasAttribute(Attribute::StructRet), - "Attribute 'sret' cannot be used for vararg call arguments!", I); + // Statepoint intrinsic is vararg but the wrapped function may be not. + // Allow sret here and check the wrapped function in verifyStatepoint. + if (CS.getCalledFunction() == nullptr || + CS.getCalledFunction()->getIntrinsicID() != + Intrinsic::experimental_gc_statepoint) + Assert(!ArgAttrs.hasAttribute(Attribute::StructRet), + "Attribute 'sret' cannot be used for vararg call arguments!", I); if (ArgAttrs.hasAttribute(Attribute::InAlloca)) Assert(Idx == CS.arg_size() - 1, "inalloca isn't on the last argument!", Index: llvm/trunk/test/Verifier/statepoint.ll =================================================================== --- llvm/trunk/test/Verifier/statepoint.ll +++ llvm/trunk/test/Verifier/statepoint.ll @@ -4,6 +4,7 @@ declare i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32) declare i64 addrspace(1)* @llvm.experimental.gc.relocate.p1i64(token, i32, i32) declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...) +declare token @llvm.experimental.gc.statepoint.p0f_isVoidp0s_structsf(i64, i32, void (%struct*)*, i32, i32, ...) declare i32 @"personality_function"() ;; Basic usage @@ -79,3 +80,20 @@ %obj1.relocated1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %landing_pad, i32 12, i32 12) ret i8 addrspace(1)* %obj1.relocated1 } + +; Test for statepoint with sret attribute. +; This should be allowed as long as the wrapped function is not vararg. +%struct = type { i64, i64, i64 } + +declare void @fn_sret(%struct* sret) + +define void @test_sret() gc "statepoint-example" { + %x = alloca %struct + %statepoint_token = call token (i64, i32, void (%struct*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidp0s_structsf(i64 0, i32 0, void (%struct*)* @fn_sret, i32 1, i32 0, %struct* sret %x, i32 0, i32 0) + ret void + ; CHECK-LABEL: test_sret + ; CHECK: alloca + ; CHECK: statepoint + ; CHECK-SAME: sret + ; CHECK: ret +}