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
This commit is contained in:
Igor Laevsky 2015-02-19 11:28:47 +00:00
parent 589d13e8f5
commit 05be69f1e3
2 changed files with 81 additions and 11 deletions

View File

@ -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<CallInst>(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<ExtractValueInst>(CI.getArgOperand(0))) {
Assert1(isa<LandingPadInst>(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<Instruction>(Token) && isStatepoint(cast<Instruction>(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);

View File

@ -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
}