// heap. This is basically just here to help catch errors during statepoint
// insertion. TODO: This should actually be in the Verifier, but we can't get
// to the GCStrategy from there (yet).
- if (Builder.GFI) {
- GCStrategy &S = Builder.GFI->getStrategy();
- for (const Value *V : Bases) {
- auto Opt = S.isGCManagedPointer(V);
- if (Opt.hasValue()) {
- assert(Opt.getValue() &&
- "non gc managed base pointer found in statepoint");
- }
+ GCStrategy &S = Builder.GFI->getStrategy();
+ for (const Value *V : Bases) {
+ auto Opt = S.isGCManagedPointer(V);
+ if (Opt.hasValue()) {
+ assert(Opt.getValue() &&
+ "non gc managed base pointer found in statepoint");
}
- for (const Value *V : Ptrs) {
- auto Opt = S.isGCManagedPointer(V);
- if (Opt.hasValue()) {
- assert(Opt.getValue() &&
- "non gc managed derived pointer found in statepoint");
- }
+ }
+ for (const Value *V : Ptrs) {
+ auto Opt = S.isGCManagedPointer(V);
+ if (Opt.hasValue()) {
+ assert(Opt.getValue() &&
+ "non gc managed derived pointer found in statepoint");
}
- for (const Value *V : Relocations) {
- auto Opt = S.isGCManagedPointer(V);
- if (Opt.hasValue()) {
- assert(Opt.getValue() && "non gc managed pointer relocated");
- }
+ }
+ for (const Value *V : Relocations) {
+ auto Opt = S.isGCManagedPointer(V);
+ if (Opt.hasValue()) {
+ assert(Opt.getValue() && "non gc managed pointer relocated");
}
}
#endif
// TODO: This if should become an assert. For now, we allow the GCStrategy
// to be optional for backwards compatibility. This will only last a short
// period (i.e. a couple of weeks).
- if (GFI) {
- assert(GFI->getStrategy().useStatepoints() &&
- "GCStrategy does not expect to encounter statepoints");
- }
+ assert(GFI->getStrategy().useStatepoints() &&
+ "GCStrategy does not expect to encounter statepoints");
#endif
// Lower statepoint vmstate and gcstate arguments
case Intrinsic::experimental_gc_statepoint:
Assert(!CI.isInlineAsm(),
"gc.statepoint support for inline assembly unimplemented", &CI);
+ Assert(CI.getParent()->getParent()->hasGC(),
+ "Enclosing function does not use GC.", &CI);
VerifyStatepoint(ImmutableCallSite(&CI));
break;
case Intrinsic::experimental_gc_result_float:
case Intrinsic::experimental_gc_result_ptr:
case Intrinsic::experimental_gc_result: {
+ Assert(CI.getParent()->getParent()->hasGC(),
+ "Enclosing function does not use GC.", &CI);
// Are we tied to a statepoint properly?
CallSite StatepointCS(CI.getArgOperand(0));
const Function *StatepointFn =
@globalstr = global [6 x i8] c"hello\00"
-define void @test(i32 addrspace(1)* dereferenceable(8) %dparam) {
+define void @test(i32 addrspace(1)* dereferenceable(8) %dparam) gc "statepoint-example" {
; CHECK: The following are dereferenceable:
; CHECK: %globalptr
; CHECK: %alloca
; will serve the purpose.
; function and integer
-define i32* @test_iAny(i32* %v) {
+define i32* @test_iAny(i32* %v) gc "statepoint-example" {
%tok = call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0, i32* %v)
%v-new = call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 4, i32 4)
ret i32* %v-new
}
; float
-define float* @test_fAny(float* %v) {
+define float* @test_fAny(float* %v) gc "statepoint-example" {
%tok = call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0, float* %v)
%v-new = call float* @llvm.experimental.gc.relocate.p0f32(i32 %tok, i32 4, i32 4)
ret float* %v-new
}
; array of integers
-define [3 x i32]* @test_aAny([3 x i32]* %v) {
+define [3 x i32]* @test_aAny([3 x i32]* %v) gc "statepoint-example" {
%tok = call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0, [3 x i32]* %v)
%v-new = call [3 x i32]* @llvm.experimental.gc.relocate.p0a3i32(i32 %tok, i32 4, i32 4)
ret [3 x i32]* %v-new
}
; vector of integers
-define <3 x i32>* @test_vAny(<3 x i32>* %v) {
+define <3 x i32>* @test_vAny(<3 x i32>* %v) gc "statepoint-example" {
%tok = call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0, <3 x i32>* %v)
%v-new = call <3 x i32>* @llvm.experimental.gc.relocate.p0v3i32(i32 %tok, i32 4, i32 4)
ret <3 x i32>* %v-new
%struct.test = type { i32, i1 }
; struct
-define %struct.test* @test_struct(%struct.test* %v) {
+define %struct.test* @test_struct(%struct.test* %v) gc "statepoint-example" {
%tok = call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0, %struct.test* %v)
%v-new = call %struct.test* @llvm.experimental.gc.relocate.p0struct.test(i32 %tok, i32 4, i32 4)
ret %struct.test* %v-new
declare i32 @"personality_function"()
-define i64 addrspace(1)* @test_result(i64 addrspace(1)* %obj, i64 addrspace(1)* %obj1) {
+define i64 addrspace(1)* @test_result(i64 addrspace(1)* %obj,
+ i64 addrspace(1)* %obj1)
+ gc "statepoint-example" {
entry:
; CHECK: .Ltmp{{[0-9]+}}:
; CHECK: callq some_other_call
; of GC arguments differ, niave lowering code would insert loads and
; stores to rearrange items on the stack. We need to make sure (for
; performance) that this doesn't happen.
-define i32 @back_to_back_calls(i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c) #1 {
+define i32 @back_to_back_calls(i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c) #1 gc "statepoint-example" {
; CHECK-LABEL: back_to_back_calls
; The exact stores don't matter, but there need to be three stack slots created
; CHECK: movq %rdx, 16(%rsp)
; This test simply checks that minor changes in vm state don't prevent slots
; being reused for gc values.
-define i32 @reserve_first(i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c) #1 {
+define i32 @reserve_first(i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c) #1 gc "statepoint-example" {
; CHECK-LABEL: reserve_first
; The exact stores don't matter, but there need to be three stack slots created
; CHECK: movq %rdx, 16(%rsp)
declare zeroext i1 @return_i1()
-define i32 @test_sor_basic(i32* %base) {
+define i32 @test_sor_basic(i32* %base) gc "statepoint-example" {
; CHECK: getelementptr i32, i32* %base, i32 15
; CHECK: getelementptr i32, i32* %base-new, i32 15
entry:
ret i32 %ret
}
-define i32 @test_sor_two_derived(i32* %base) {
+define i32 @test_sor_two_derived(i32* %base) gc "statepoint-example" {
; CHECK: getelementptr i32, i32* %base, i32 15
; CHECK: getelementptr i32, i32* %base, i32 12
; CHECK: getelementptr i32, i32* %base-new, i32 15
ret i32 %ret
}
-define i32 @test_sor_ooo(i32* %base) {
+define i32 @test_sor_ooo(i32* %base) gc "statepoint-example" {
; CHECK: getelementptr i32, i32* %base, i32 15
; CHECK: getelementptr i32, i32* %base-new, i32 15
entry:
ret i32 %ret
}
-define i32 @test_sor_gep_smallint([3 x i32]* %base) {
+define i32 @test_sor_gep_smallint([3 x i32]* %base) gc "statepoint-example" {
; CHECK: getelementptr [3 x i32], [3 x i32]* %base, i32 0, i32 2
; CHECK: getelementptr [3 x i32], [3 x i32]* %base-new, i32 0, i32 2
entry:
ret i32 %ret
}
-define i32 @test_sor_gep_largeint([3 x i32]* %base) {
+define i32 @test_sor_gep_largeint([3 x i32]* %base) gc "statepoint-example" {
; CHECK: getelementptr [3 x i32], [3 x i32]* %base, i32 0, i32 21
; CHECK-NOT: getelementptr [3 x i32], [3 x i32]* %base-new, i32 0, i32 21
entry:
ret i32 %ret
}
-define i32 @test_sor_noop(i32* %base) {
+define i32 @test_sor_noop(i32* %base) gc "statepoint-example" {
; CHECK: getelementptr i32, i32* %base, i32 15
; CHECK: call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 4, i32 5)
; CHECK: call i32* @llvm.experimental.gc.relocate.p0i32(i32 %tok, i32 4, i32 6)
declare i32 @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()*, i32, i32, ...)
declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32, i32, i32)
-define i32 addrspace(1)* @deref(i32 addrspace(1)* dereferenceable(8) %dparam) {
+define i32 addrspace(1)* @deref(i32 addrspace(1)* dereferenceable(8) %dparam) gc "statepoint-example" {
; Checks that a dereferenceabler pointer
; CHECK-LABEL: @deref
; CHECK: call dereferenceable(8)
%tok = tail call i32 (i1 ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_i1f(i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 addrspace(1)* %dparam)
%relocate = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %tok, i32 4, i32 4)
ret i32 addrspace(1)* %relocate
-}
\ No newline at end of file
+}
declare void @func()
-define i1 @test_negative(i32 addrspace(1)* %p) {
+define i1 @test_negative(i32 addrspace(1)* %p) gc "statepoint-example" {
entry:
%safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* %p)
%pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4)
; CHECK: ret i1 %cmp
}
-define i1 @test_nonnull(i32 addrspace(1)* nonnull %p) {
+define i1 @test_nonnull(i32 addrspace(1)* nonnull %p) gc "statepoint-example" {
entry:
%safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* %p)
%pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4)
; CHECK: ret i1 false
}
-define i1 @test_null() {
+define i1 @test_null() gc "statepoint-example" {
entry:
%safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* null)
%pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4)
; CHECK: ret i1 true
}
-define i1 @test_undef() {
+define i1 @test_undef() gc "statepoint-example" {
entry:
%safepoint_token = tail call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @func, i32 0, i32 0, i32 0, i32 addrspace(1)* undef)
%pnew = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(i32 %safepoint_token, i32 4, i32 4)
}
; When run over a function which doesn't opt in, should do nothing!
-define i8 addrspace(1)* @test5(i8 addrspace(1)* %obj) {
+define i8 addrspace(1)* @test5(i8 addrspace(1)* %obj) gc "ocaml" {
; CHECK-LABEL: @test5
; CHECK-LABEL: entry:
; CHECK-NEXT: gc.statepoint