Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -2639,8 +2639,6 @@ "gc.statepoint callee must be of function pointer type", &CI, Target); FunctionType *TargetFuncType = cast(PT->getElementType()); - Assert1(!TargetFuncType->isVarArg(), - "gc.statepoint support for var arg functions not implemented", &CI); const Value *NumCallArgsV = CI.getArgOperand(1); Assert1(isa(NumCallArgsV), @@ -2650,8 +2648,18 @@ Assert1(NumCallArgs >= 0, "gc.statepoint number of arguments to underlying call " "must be positive", &CI); - Assert1(NumCallArgs == (int)TargetFuncType->getNumParams(), - "gc.statepoint mismatch in number of call args", &CI); + const int NumParams = (int)TargetFuncType->getNumParams(); + if (TargetFuncType->isVarArg()) { + Assert1(NumCallArgs >= NumParams, + "gc.statepoint mismatch in number of vararg call args", &CI); + + // TODO: Remove this limitation + Assert1(TargetFuncType->getReturnType()->isVoidTy(), + "gc.statepoint doesn't support wrapping non-void " + "vararg functions yet", &CI); + } else + Assert1(NumCallArgs == NumParams, + "gc.statepoint mismatch in number of call args", &CI); const Value *Unused = CI.getArgOperand(2); Assert1(isa(Unused) && @@ -2660,7 +2668,7 @@ // Verify that the types of the call parameter arguments match // the type of the wrapped callee. - for (int i = 0; i < NumCallArgs; i++) { + for (int i = 0; i < NumParams; i++) { Type *ParamType = TargetFuncType->getParamType(i); Type *ArgType = CI.getArgOperand(3+i)->getType(); Assert1(ArgType == ParamType, Index: llvm/trunk/test/CodeGen/X86/statepoint-call-lowering.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/statepoint-call-lowering.ll +++ llvm/trunk/test/CodeGen/X86/statepoint-call-lowering.ll @@ -9,6 +9,7 @@ declare zeroext i32 @return_i32() declare i32* @return_i32ptr() declare float @return_float() +declare void @varargf(i32, ...) define i1 @test_i1_return() gc "statepoint-example" { ; CHECK-LABEL: test_i1_return @@ -75,6 +76,17 @@ ret i1 %call2 } +define void @test_void_vararg() gc "statepoint-example" { +; CHECK-LABEL: test_void_vararg +; Check a statepoint wrapping a *void* returning vararg function works +; CHECK: callq varargf +entry: + %safepoint_token = tail call i32 (void (i32, ...)*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidi32varargf(void (i32, ...)* @varargf, i32 2, i32 0, i32 42, i32 43, i32 0) + ;; if we try to use the result from a statepoint wrapping a + ;; non-void-returning varargf, we will experience a crash. + ret void +} + declare i32 @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()*, i32, i32, ...) declare i1 @llvm.experimental.gc.result.int.i1(i32) @@ -87,4 +99,6 @@ declare i32 @llvm.experimental.gc.statepoint.p0f_f32f(float ()*, i32, i32, ...) declare float @llvm.experimental.gc.result.float.f32(i32) +declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidi32varargf(void (i32, ...)*, i32, i32, ...) + declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32, i32, i32)