Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1859,6 +1859,13 @@ Assert1(II.getUnwindDest()->isLandingPad(), "The unwind destination does not have a landingpad instruction!",&II); + if (Function *F = II.getCalledFunction()) + // TODO: Ideally we should use visitIntrinsicFunction here. But it uses + // CallInst as an input parameter. It not woth updating this whole + // function only to support statepoint verification. + if (F->getIntrinsicID() == Intrinsic::experimental_gc_statepoint) + VerifyStatepoint(ImmutableCallSite(&II)); + visitTerminatorInst(II); } @@ -2358,7 +2365,8 @@ Assert1(!F->isIntrinsic() || isa(I) || F->getIntrinsicID() == Intrinsic::donothing || F->getIntrinsicID() == Intrinsic::experimental_patchpoint_void || - F->getIntrinsicID() == Intrinsic::experimental_patchpoint_i64, + F->getIntrinsicID() == Intrinsic::experimental_patchpoint_i64 || + F->getIntrinsicID() == Intrinsic::experimental_gc_statepoint, "Cannot invoke an intrinsinc other than" " donothing or patchpoint", &I); Assert1(F->getParent() == M, "Referencing function in another module!", @@ -2756,14 +2764,46 @@ break; } case Intrinsic::experimental_gc_relocate: { - // Are we tied to a statepoint properly? - CallSite StatepointCS(CI.getArgOperand(0)); - const Function *StatepointFn = - StatepointCS.getInstruction() ? StatepointCS.getCalledFunction() : nullptr; - Assert2(StatepointFn && StatepointFn->isDeclaration() && - StatepointFn->getIntrinsicID() == Intrinsic::experimental_gc_statepoint, - "gc.relocate operand #1 must be from a statepoint", - &CI, CI.getArgOperand(0)); + Assert1(CI.getNumArgOperands() == 3, "wrong number of arguments", &CI); + + // Check that this relocate is correctly tied to the statepoint + + // This is case for relocate on the unwinding path of an invoke statepoint + if (isa(CI.getArgOperand(0))) { + Assert1(isa( + cast( + CI.getArgOperand(0))->getAggregateOperand()), + "gc relocate on unwind path incorrectly linked to the statepoint", + &CI); + + const BasicBlock *invokeBB = + cast(CI.getArgOperand(0))->getParent()->getUniquePredecessor(); + + // Landingpad relocates should have only one predecessor with invoke + // statepoint terminator + Assert1(invokeBB, + "safepoints should have unique landingpads", + cast(CI.getArgOperand(0))->getParent()); + Assert1(invokeBB->getTerminator(), + "safepoint block should be well formed", + invokeBB); + Assert1(isStatepoint(invokeBB->getTerminator()), + "gc relocate should be linked to a statepoint", + invokeBB); + } + else { + // In all other cases relocate should be tied to the statepoint directly. + // This covers relocates on a normal return path of invoke statepoint and + // relocates of a call statepoint + Assert2(isStatepoint(cast(CI.getArgOperand(0))), + "gc relocate is incorrectly tied to the statepoint", + &CI, CI.getArgOperand(0)); + } + + // Verify rest of the relocate arguments + + GCRelocateOperands ops(&CI); + ImmutableCallSite StatepointCS = ImmutableCallSite(ops.statepoint()); // Both the base and derived must be piped through the safepoint Value* Base = CI.getArgOperand(1); Index: test/Verifier/statepoint.ll =================================================================== --- test/Verifier/statepoint.ll +++ test/Verifier/statepoint.ll @@ -7,7 +7,7 @@ declare i32 @"personality_function"() ;; Basic usage -define i64 addrspace(1)* @test1(i8 addrspace(1)* %arg) { +define i64 addrspace(1)* @test1(i8 addrspace(1)* %arg) gc "statepoint-example" { entry: %cast = bitcast i8 addrspace(1)* %arg to i64 addrspace(1)* %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* undef, i32 0, i32 0, i32 5, i32 0, i32 0, i32 0, i32 10, i32 0, i8 addrspace(1)* %arg, i64 addrspace(1)* %cast, i8 addrspace(1)* %arg, i8 addrspace(1)* %arg) @@ -29,7 +29,7 @@ ; 2) A value can be replaced by one which is known equal. This ; means a potentially derived pointer can be known base and that ; we can't check that derived pointer are never bases. -define void @test2(i8 addrspace(1)* %arg, i64 addrspace(1)* %arg2) { +define void @test2(i8 addrspace(1)* %arg, i64 addrspace(1)* %arg2) gc "statepoint-example" { entry: %cast = bitcast i8 addrspace(1)* %arg to i64 addrspace(1)* %c = icmp eq i64 addrspace(1)* %cast, %arg2 @@ -50,3 +50,33 @@ ; CHECK-NEXT: call ; CHECK-NEXT: ret voi } + +; Basic test for invoke statepoints +define i8 addrspace(1)* @test3(i8 addrspace(1)* %obj, i8 addrspace(1)* %obj1) gc "statepoint-example" { +; CHECK-LABEL: test3 +entry: + ; CHECK-LABEL: entry + ; CHECK: statepoint + %0 = invoke i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* undef, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0, i8 addrspace(1)* %obj, i8 addrspace(1)* %obj1) + to label %normal_dest unwind label %exceptional_return + +normal_dest: + ; CHECK-LABEL: normal_dest: + ; CHECK: gc.relocate + ; CHECK: gc.relocate + ; CHECK: ret + %obj.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %0, i32 9, i32 9) + %obj1.relocated = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %0, i32 10, i32 10) + ret i8 addrspace(1)* %obj.relocated + +exceptional_return: + ; CHECK-LABEL: exceptional_return + ; CHECK: gc.relocate + ; CHECK: gc.relocate + %landing_pad = landingpad { i8*, i32 } personality i32 ()* @"personality_function" + cleanup + %relocate_token = extractvalue { i8*, i32 } %landing_pad, 1 + %obj.relocated1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %relocate_token, i32 9, i32 9) + %obj1.relocated1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(i32 %relocate_token, i32 10, i32 10) + ret i8 addrspace(1)* %obj1.relocated1 +}