From 05be69f1e396139127a31aa6586348cdc5691093 Mon Sep 17 00:00:00 2001 From: Igor Laevsky Date: Thu, 19 Feb 2015 11:28:47 +0000 Subject: [PATCH] Implement invoke statepoint verification. Differential Revision: http://reviews.llvm.org/D7366 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229840 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/IR/Verifier.cpp | 58 +++++++++++++++++++++++++++++++------ test/Verifier/statepoint.ll | 34 ++++++++++++++++++++-- 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 865b187ad46..43a023ec7c0 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -1987,6 +1987,13 @@ void Verifier::visitInvokeInst(InvokeInst &II) { 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); } @@ -2486,7 +2493,8 @@ void Verifier::visitInstruction(Instruction &I) { 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!", @@ -2901,14 +2909,46 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { 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 (ExtractValueInst *ExtractValue = + dyn_cast(CI.getArgOperand(0))) { + Assert1(isa(ExtractValue->getAggregateOperand()), + "gc relocate on unwind path incorrectly linked to the statepoint", + &CI); + + const BasicBlock *invokeBB = + ExtractValue->getParent()->getUniquePredecessor(); + + // Landingpad relocates should have only one predecessor with invoke + // statepoint terminator + Assert1(invokeBB, + "safepoints should have unique landingpads", + ExtractValue->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 + auto Token = CI.getArgOperand(0); + Assert2(isa(Token) && isStatepoint(cast(Token)), + "gc relocate is incorrectly tied to the statepoint", + &CI, Token); + } + + // Verify rest of the relocate arguments + + GCRelocateOperands ops(&CI); + ImmutableCallSite StatepointCS(ops.statepoint()); // Both the base and derived must be piped through the safepoint Value* Base = CI.getArgOperand(1); diff --git a/test/Verifier/statepoint.ll b/test/Verifier/statepoint.ll index 0899bde7ca8..934230940bf 100644 --- a/test/Verifier/statepoint.ll +++ b/test/Verifier/statepoint.ll @@ -7,7 +7,7 @@ declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ... 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 @@ entry: ; 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 @@ -51,3 +51,33 @@ equal: ; 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 +} + -- 2.34.1