[GC] improve testing around gc.relocate and fix a test

Patch by: Ramkumar Ramachandra <artagnon@gmail.com>

"This patch started out as an exploration of gc.relocate, and an attempt
to write a simple test in call-lowering. I then noticed that the
arguments of gc.relocate were not checked fully, so I went in and fixed
a few things. Finally, the most important outcome of this patch is that
my new error handling code caught a bug in a callsite in
stackmap-format."

Differential Revision: http://reviews.llvm.org/D6824

llvm-svn: 225412
This commit is contained in:
Philip Reames 2015-01-07 22:48:01 +00:00
parent 97fea8bb95
commit 76ebd15437
3 changed files with 51 additions and 14 deletions

View File

@ -2691,10 +2691,12 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
case Intrinsic::experimental_gc_result_ptr: {
// Are we tied to a statepoint properly?
CallSite StatepointCS(CI.getArgOperand(0));
const Function *StatepointFn = StatepointCS.getCalledFunction();
const Function *StatepointFn =
StatepointCS.getInstruction() ? StatepointCS.getCalledFunction() : nullptr;
Assert2(StatepointFn && StatepointFn->isDeclaration() &&
StatepointFn->getIntrinsicID() == Intrinsic::experimental_gc_statepoint,
"token must be from a statepoint", &CI, CI.getArgOperand(0));
"gc.result operand #1 must be from a statepoint",
&CI, CI.getArgOperand(0));
// Assert that result type matches wrapped callee.
const Value *Target = StatepointCS.getArgument(0);
@ -2710,32 +2712,53 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
// Are we tied to a statepoint properly?
CallSite StatepointCS(CI.getArgOperand(0));
const Function *StatepointFn =
StatepointCS.getInstruction() ? StatepointCS.getCalledFunction() : NULL;
StatepointCS.getInstruction() ? StatepointCS.getCalledFunction() : nullptr;
Assert2(StatepointFn && StatepointFn->isDeclaration() &&
StatepointFn->getIntrinsicID() == Intrinsic::experimental_gc_statepoint,
"token must be from a statepoint", &CI, CI.getArgOperand(0));
"gc.relocate operand #1 must be from a statepoint",
&CI, CI.getArgOperand(0));
// Both the base and derived must be piped through the safepoint
Value* Base = CI.getArgOperand(1);
Assert1( isa<ConstantInt>(Base), "must be integer offset", &CI);
Assert1(isa<ConstantInt>(Base),
"gc.relocate operand #2 must be integer offset", &CI);
Value* Derived = CI.getArgOperand(2);
Assert1( isa<ConstantInt>(Derived), "must be integer offset", &CI);
Assert1(isa<ConstantInt>(Derived),
"gc.relocate operand #3 must be integer offset", &CI);
const int BaseIndex = cast<ConstantInt>(Base)->getZExtValue();
const int DerivedIndex = cast<ConstantInt>(Derived)->getZExtValue();
// Check the bounds
Assert1(0 <= BaseIndex &&
BaseIndex < (int)StatepointCS.arg_size(),
"index out of bounds", &CI);
"gc.relocate: statepoint base index out of bounds", &CI);
Assert1(0 <= DerivedIndex &&
DerivedIndex < (int)StatepointCS.arg_size(),
"index out of bounds", &CI);
"gc.relocate: statepoint derived index out of bounds", &CI);
// Check that BaseIndex and DerivedIndex fall within the 'gc parameters'
// section of the statepoint's argument
const int NumCallArgs =
cast<ConstantInt>(StatepointCS.getArgument(1))->getZExtValue();
const int NumDeoptArgs =
cast<ConstantInt>(StatepointCS.getArgument(NumCallArgs + 3))->getZExtValue();
const int GCParamArgsStart = NumCallArgs + NumDeoptArgs + 4;
const int GCParamArgsEnd = StatepointCS.arg_size();
Assert1(GCParamArgsStart <= BaseIndex &&
BaseIndex < GCParamArgsEnd,
"gc.relocate: statepoint base index doesn't fall within the "
"'gc parameters' section of the statepoint call", &CI);
Assert1(GCParamArgsStart <= DerivedIndex &&
DerivedIndex < GCParamArgsEnd,
"gc.relocate: statepoint derived index doesn't fall within the "
"'gc parameters' section of the statepoint call", &CI);
// Assert that the result type matches the type of the relocated pointer
GCRelocateOperands Operands(&CI);
Assert1(Operands.derivedPtr()->getType() == CI.getType(),
"gc.relocate: relocating a pointer shouldn't change it's type",
"gc.relocate: relocating a pointer shouldn't change its type",
&CI);
break;
}

View File

@ -60,6 +60,21 @@ entry:
ret float %call1
}
define i1 @test_relocate(i32* %a) {
; CHECK-LABEL: test_relocate
; Check that an ununsed relocate has no code-generation impact
; CHECK: pushq %rax
; CHECK: callq return_i1
; CHECK-NEXT: .Ltmp13:
; CHECK-NEXT: popq %rdx
; CHECK-NEXT: retq
entry:
%safepoint_token = tail call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0, i32* %a)
%call1 = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %safepoint_token, i32 4, i32 4)
%call2 = call zeroext i1 @llvm.experimental.gc.result.int.i1(i32 %safepoint_token)
ret i1 %call2
}
declare i32 @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()*, i32, i32, ...)
declare i1 @llvm.experimental.gc.result.int.i1(i32)
@ -72,3 +87,4 @@ declare i32* @llvm.experimental.gc.result.ptr.p0i32(i32)
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.relocate.p0i32(i32, i32, i32)

View File

@ -21,12 +21,10 @@ define i1 @test(i32 addrspace(1)* %ptr) {
entry:
%metadata1 = alloca i32 addrspace(1)*, i32 2, align 8
store i32 addrspace(1)* null, i32 addrspace(1)** %metadata1
; NOTE: Currently NOT testing alloca lowering in the StackMap format. Its
; known to be broken.
%safepoint_token = tail call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 2, i32 addrspace(1)* %ptr, i32 addrspace(1)* null)
%safepoint_token = tail call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 2, i32 addrspace(1)* %ptr, i32 addrspace(1)* null, i32 addrspace(1)* %ptr, i32 addrspace(1)* null)
%call1 = call zeroext i1 @llvm.experimental.gc.result.int.i1(i32 %safepoint_token)
%a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4)
%b = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 5, i32 5)
%a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 6, i32 6)
%b = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 7, i32 7)
;
ret i1 %call1
}