findBasePointers(result.liveset, PointerToBase, &DT, DVCache, NewInsertedDefs);
if (PrintBasePointers) {
+ // Note: Need to print these in a stable order since this is checked in
+ // some tests.
errs() << "Base Pairs (w/o Relocation):\n";
+ SmallVector<Value*, 64> Temp;
+ Temp.reserve(PointerToBase.size());
for (auto Pair : PointerToBase) {
- errs() << " derived %" << Pair.first->getName() << " base %"
- << Pair.second->getName() << "\n";
+ Temp.push_back(Pair.first);
+ }
+ std::sort(Temp.begin(), Temp.end(), order_by_name);
+ for (Value *Ptr : Temp) {
+ Value *Base = PointerToBase[Ptr];
+ errs() << " derived %" << Ptr->getName() << " base %"
+ << Base->getName() << "\n";
}
}
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %merged_value base %base_phi
+
+declare void @site_for_call_safpeoint()
+
+define i64 addrspace(1)* @test(i64 addrspace(1)* %base_obj_x, i64 addrspace(1)* %base_obj_y, i1 %runtime_condition) gc "statepoint-example" {
+entry:
+ br i1 %runtime_condition, label %here, label %there
+
+here:
+ %x = getelementptr i64, i64 addrspace(1)* %base_obj_x, i32 1
+ br label %merge
+
+there:
+ %y = getelementptr i64, i64 addrspace(1)* %base_obj_y, i32 1
+ br label %merge
+
+merge:
+; CHECK-LABEL: merge:
+; CHECK: %base_phi = phi i64 addrspace(1)* [ %base_obj_x, %here ], [ %base_obj_y, %there ]
+ %merged_value = phi i64 addrspace(1)* [ %x, %here ], [ %y, %there ]
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @site_for_call_safpeoint, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ ret i64 addrspace(1)* %merged_value
+}
+
+declare void @foo()
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %next_x base %base_obj_x
+; CHECK: derived %next_y base %base_obj_y
+; CHECK: derived %next base %base_phi
+
+declare i1 @runtime_value()
+declare void @do_safepoint()
+
+define void @select_of_phi(i64 addrspace(1)* %base_obj_x, i64 addrspace(1)* %base_obj_y) gc "statepoint-example" {
+entry:
+ br label %loop
+
+loop:
+ %current_x = phi i64 addrspace(1)* [ %base_obj_x , %entry ], [ %next_x, %merge ]
+ %current_y = phi i64 addrspace(1)* [ %base_obj_y , %entry ], [ %next_y, %merge ]
+ %current = phi i64 addrspace(1)* [ null , %entry ], [ %next , %merge ]
+
+ %condition = call i1 @runtime_value()
+ %next_x = getelementptr i64, i64 addrspace(1)* %current_x, i32 1
+ %next_y = getelementptr i64, i64 addrspace(1)* %current_y, i32 1
+
+ br i1 %condition, label %true, label %false
+
+true:
+ br label %merge
+
+false:
+ br label %merge
+
+merge:
+ %next = phi i64 addrspace(1)* [ %next_x, %true ], [ %next_y, %false ]
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ br label %loop
+}
+
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %next base %base_obj
+
+declare void @do_safepoint()
+
+define void @test(i64 addrspace(1)* %base_obj) gc "statepoint-example" {
+entry:
+ %obj = getelementptr i64, i64 addrspace(1)* %base_obj, i32 1
+ br label %loop
+
+loop: ; preds = %loop, %entry
+; CHECK-LABEL: loop:
+; CHECK: phi i64 addrspace(1)*
+; CHECK-DAG: [ %base_obj.relocated, %loop ]
+; CHECK-DAG: [ %base_obj, %entry ]
+; CHECK: %current = phi i64 addrspace(1)*
+; CHECK-DAG: [ %obj, %entry ]
+; CHECK-DAG: [ %next.relocated, %loop ]
+ %current = phi i64 addrspace(1)* [ %obj, %entry ], [ %next, %loop ]
+ %next = getelementptr i64, i64 addrspace(1)* %current, i32 1
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ br label %loop
+}
+
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %merged_value base %base_obj
+
+
+define i64 addrspace(1)* @test(i64 addrspace(1)* %base_obj, i1 %runtime_condition) gc "statepoint-example" {
+entry:
+ br i1 %runtime_condition, label %merge, label %there
+
+there:
+ %derived_obj = getelementptr i64, i64 addrspace(1)* %base_obj, i32 1
+ br label %merge
+
+merge:
+ %merged_value = phi i64 addrspace(1)* [ %base_obj, %entry ], [ %derived_obj, %there ]
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ ret i64 addrspace(1)* %merged_value
+}
+
+declare void @foo()
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %next.i64 base %base_obj
+
+define void @test(i64 addrspace(1)* %base_obj) gc "statepoint-example" {
+entry:
+ %obj = getelementptr i64, i64 addrspace(1)* %base_obj, i32 1
+ br label %loop
+
+loop:
+ %current = phi i64 addrspace(1)* [ %obj, %entry ], [ %next.i64, %loop ]
+ %current.i32 = bitcast i64 addrspace(1)* %current to i32 addrspace(1)*
+ %next.i32 = getelementptr i32, i32 addrspace(1)* %current.i32, i32 1
+ %next.i64 = bitcast i32 addrspace(1)* %next.i32 to i64 addrspace(1)*
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ br label %loop
+}
+
+declare void @do_safepoint()
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+
+; CHECK: derived %obj_to_consume base %base_phi
+
+declare void @foo()
+declare i64 addrspace(1)* @generate_obj()
+declare void @consume_obj(i64 addrspace(1)*)
+
+define void @test(i32 %condition) gc "statepoint-example" {
+entry:
+ br label %loop
+
+loop:
+; CHECK: loop:
+; CHECK: %safepoint_token1 = call i32 (i64 addrspace(1)* ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_p1i64f(i64 addrspace(1)* ()* @generate_obj, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i3
+; CHECK-NEXT: %obj2 = call i64 addrspace(1)* @llvm.experimental.gc.result
+ %safepoint_token1 = call i32 (i64 addrspace(1)* ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_p1i64f(i64 addrspace(1)* ()* @generate_obj, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ %obj2 = call i64 addrspace(1)* @llvm.experimental.gc.result.p1i64(i32 %safepoint_token1)
+ switch i32 %condition, label %dest_a [
+ i32 0, label %dest_b
+ i32 1, label %dest_c
+ ]
+
+dest_a:
+ br label %merge
+
+dest_b:
+ br label %merge
+
+dest_c:
+ br label %merge
+
+merge:
+; CHECK: merge:
+; CHECK: %base_phi = phi i64 addrspace(1)* [ %obj2, %dest_a ], [ null, %dest_b ], [ null, %dest_c ]
+; CHECK: %obj_to_consume = phi i64 addrspace(1)* [ %obj2, %dest_a ], [ null, %dest_b ], [ null, %dest_c ]
+
+ %obj_to_consume = phi i64 addrspace(1)* [ %obj2, %dest_a ], [ null, %dest_b ], [ null, %dest_c ]
+ %safepoint_token3 = call i32 (void (i64 addrspace(1)*)*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidp1i64f(void (i64 addrspace(1)*)* @consume_obj, i32 1, i32 0, i64 addrspace(1)* %obj_to_consume, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ br label %merge.split
+
+merge.split: ; preds = %merge
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ br label %loop
+}
+
+
+; Function Attrs: nounwind
+declare i64 addrspace(1)* @llvm.experimental.gc.result.p1i64(i32) #0
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
+declare i32 @llvm.experimental.gc.statepoint.p0f_p1i64f(i64 addrspace(1)* ()*, i32, i32, ...)
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidp1i64f(void (i64 addrspace(1)*)*, i32, i32, ...)
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %merged_value base %base_phi
+
+declare void @foo()
+
+define i64 addrspace(1)* @test(i64 addrspace(1)* %base_obj_x, i64 addrspace(1)* %base_obj_y, i1 %runtime_condition) gc "statepoint-example" {
+entry:
+ br i1 %runtime_condition, label %here, label %there
+
+here:
+ br label %bump
+
+bump:
+ br label %merge
+
+there:
+ %y = getelementptr i64, i64 addrspace(1)* %base_obj_y, i32 1
+ br label %merge
+
+merge:
+; CHECK: merge:
+; CHECK: %base_phi = phi i64 addrspace(1)* [ %base_obj_x, %bump ], [ %base_obj_y, %there ]
+; CHECK-NEXT: %merged_value = phi i64 addrspace(1)* [ %base_obj_x, %bump ], [ %y, %there ]
+ %merged_value = phi i64 addrspace(1)* [ %base_obj_x, %bump ], [ %y, %there ]
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ ret i64 addrspace(1)* %merged_value
+}
+
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
+
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %merged_value base %base_phi
+
+declare void @site_for_call_safpeoint()
+
+define i64 addrspace(1)* @test(i64 addrspace(1)* %base_obj_x, i64 addrspace(1)* %base_obj_y, i1 %runtime_condition_x, i1 %runtime_condition_y) gc "statepoint-example" {
+entry:
+ br i1 %runtime_condition_x, label %here, label %there
+
+here:
+ br i1 %runtime_condition_y, label %bump_here_a, label %bump_here_b
+
+bump_here_a:
+ %x_a = getelementptr i64, i64 addrspace(1)* %base_obj_x, i32 1
+ br label %merge_here
+
+bump_here_b:
+ %x_b = getelementptr i64, i64 addrspace(1)* %base_obj_x, i32 2
+ br label %merge_here
+
+
+merge_here:
+ %x = phi i64 addrspace(1)* [ %x_a , %bump_here_a ], [ %x_b , %bump_here_b ]
+ br label %merge
+
+there:
+ %y = getelementptr i64, i64 addrspace(1)* %base_obj_y, i32 1
+ br label %merge
+
+merge:
+; CHECK: merge:
+; CHECK: %base_phi = phi i64 addrspace(1)* [ %base_obj_x, %merge_here ], [ %base_obj_y, %there ]
+; CHECK-NEXT: %merged_value = phi i64 addrspace(1)* [ %x, %merge_here ], [ %y, %there ]
+ %merged_value = phi i64 addrspace(1)* [ %x, %merge_here ], [ %y, %there ]
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @site_for_call_safpeoint, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ ret i64 addrspace(1)* %merged_value
+}
+
+declare void @do_safepoint()
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %merged_value base %base_phi
+
+declare void @site_for_call_safpeoint()
+
+define i64 addrspace(1)* @test(i64 addrspace(1)* %base_obj_x,
+ i64 addrspace(1)* %base_obj_y, i1 %runtime_condition_x,
+ i1 %runtime_condition_y) gc "statepoint-example" {
+entry:
+ br i1 %runtime_condition_x, label %here, label %there
+
+here:
+ br i1 %runtime_condition_y, label %bump_here_a, label %bump_here_b
+
+bump_here_a:
+ %x_a = getelementptr i64, i64 addrspace(1)* %base_obj_x, i32 1
+ br label %merge_here
+
+bump_here_b:
+ %x_b = getelementptr i64, i64 addrspace(1)* %base_obj_y, i32 2
+ br label %merge_here
+
+
+merge_here:
+; CHECK: merge_here:
+; CHECK-DAG: %base_phi
+; CHECK-DAG: phi i64 addrspace(1)*
+; CHECK-DAG: [ %base_obj_x, %bump_here_a ]
+; CHECK-DAG: [ %base_obj_y, %bump_here_b ]
+ %x = phi i64 addrspace(1)* [ %x_a , %bump_here_a ], [ %x_b , %bump_here_b ]
+ br label %merge
+
+there:
+ %y = getelementptr i64, i64 addrspace(1)* %base_obj_y, i32 1
+ br label %merge
+
+merge:
+; CHECK: merge:
+; CHECK-DAG: %base_phi1
+; CHECK-DAG: phi i64 addrspace(1)*
+; CHECK-DAG: %merge_here
+; CHECK-DAG: [ %base_obj_y, %there ]
+; CHECK: %merged_value = phi i64 addrspace(1)* [ %x, %merge_here ], [ %y, %there ]
+ %merged_value = phi i64 addrspace(1)* [ %x, %merge_here ], [ %y, %there ]
+
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @site_for_call_safpeoint, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ ret i64 addrspace(1)* %merged_value
+}
+
+declare void @do_safepoint()
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
+
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %next_element_ptr base %array_obj
+
+define i32 @null_in_array(i64 addrspace(1)* %array_obj) gc "statepoint-example" {
+entry:
+ %array_len_pointer.i64 = getelementptr i64, i64 addrspace(1)* %array_obj, i32 1
+ %array_len_pointer.i32 = bitcast i64 addrspace(1)* %array_len_pointer.i64 to i32 addrspace(1)*
+ %array_len = load i32, i32 addrspace(1)* %array_len_pointer.i32
+ %array_elems = bitcast i32 addrspace(1)* %array_len_pointer.i32 to i64 addrspace(1)* addrspace(1)*
+ br label %loop_check
+
+loop_check:
+ %index = phi i32 [ 0, %entry ], [ %next_index, %loop_back ]
+ %current_element_ptr = phi i64 addrspace(1)* addrspace(1)* [ %array_elems, %entry ], [ %next_element_ptr, %loop_back ]
+ %index_lt = icmp ult i32 %index, %array_len
+ br i1 %index_lt, label %check_for_null, label %not_found
+
+check_for_null:
+ %current_element = load i64 addrspace(1)*, i64 addrspace(1)* addrspace(1)* %current_element_ptr
+ %is_null = icmp eq i64 addrspace(1)* %current_element, null
+ br i1 %is_null, label %found, label %loop_back
+
+loop_back:
+ %next_element_ptr = getelementptr i64 addrspace(1)*, i64 addrspace(1)* addrspace(1)* %current_element_ptr, i32 1
+ %next_index = add i32 %index, 1
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ br label %loop_check
+
+not_found:
+ ret i32 -1
+
+found:
+ ret i32 %index
+}
+
+declare void @do_safepoint()
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -spp-print-base-pointers -S 2>&1 | FileCheck %s
+
+; CHECK: derived %next base %base_obj
+
+declare i1 @runtime_value()
+
+define void @maybe_GEP(i64 addrspace(1)* %base_obj) gc "statepoint-example" {
+entry:
+ br label %loop
+
+loop:
+ %current = phi i64 addrspace(1)* [ %base_obj, %entry ], [ %next, %loop ]
+ %condition = call i1 @runtime_value()
+ %maybe_next = getelementptr i64, i64 addrspace(1)* %current, i32 1
+ %next = select i1 %condition, i64 addrspace(1)* %maybe_next, i64 addrspace(1)* %current
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ br label %loop
+}
+
+declare void @do_safepoint()
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
--- /dev/null
+; RUN: opt %s -rewrite-statepoints-for-gc -S 2>&1 | FileCheck %s
+
+declare i64 addrspace(1)* @generate_obj()
+declare void @use_obj(i64 addrspace(1)*)
+
+; The rewriting needs to make %obj loop variant by inserting a phi
+; of the original value and it's relocation.
+define void @def_use_safepoint() gc "statepoint-example" {
+; CHECK-LABEL: def_use_safepoint
+entry:
+ %obj = call i64 addrspace(1)* @generate_obj()
+ br label %loop
+
+loop:
+; CHECK: phi i64 addrspace(1)*
+; CHECK-DAG: [ %obj.relocated, %loop ]
+; CHECK-DAG: [ %obj, %entry ]
+ call void @use_obj(i64 addrspace(1)* %obj)
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @do_safepoint, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ br label %loop
+}
+
+declare void @do_safepoint()
+
+declare void @parse_point(i64 addrspace(1)*)
+
+define i64 addrspace(1)* @test1(i32 %caller, i8 addrspace(1)* %a, i8 addrspace(1)* %b, i32 %unknown) gc "statepoint-example" {
+; CHECK-LABEL: test1
+ entry:
+ br i1 undef, label %left, label %right
+
+ left:
+ %a.cast = bitcast i8 addrspace(1)* %a to i64 addrspace(1)*
+; CHECK: left:
+; CHECK-NEXT: %a.cast = bitcast i8 addrspace(1)* %a to i64 addrspace(1)*
+; CHECK-NEXT: [[CAST_L:%.*]] = bitcast i8 addrspace(1)* %a to i64 addrspace(1)*
+
+; Our safepoint placement pass calls removeUnreachableBlocks, which does a bunch
+; of simplifications to branch instructions. This bug is visible only when
+; there are multiple branches into the same block from the same predecessor, and
+; the following ceremony is to make that artefact survive a call to
+; removeUnreachableBlocks. As an example, "br i1 undef, label %merge, label %merge"
+; will get simplified to "br label %merge" by removeUnreachableBlocks.
+ switch i32 %unknown, label %right [ i32 0, label %merge
+ i32 1, label %merge
+ i32 5, label %merge
+ i32 3, label %right ]
+
+ right:
+ %b.cast = bitcast i8 addrspace(1)* %b to i64 addrspace(1)*
+ br label %merge
+; CHECK: right:
+; CHECK-NEXT: %b.cast = bitcast i8 addrspace(1)* %b to i64 addrspace(1)*
+; CHECK-NEXT: [[CAST_R:%.*]] = bitcast i8 addrspace(1)* %b to i64 addrspace(1)*
+
+ merge:
+; CHECK: merge:
+; CHECK-NEXT: %base_phi = phi i64 addrspace(1)* [ [[CAST_L]], %left ], [ [[CAST_L]], %left ], [ [[CAST_L]], %left ], [ [[CAST_R]], %right ], !is_base_value !0
+ %value = phi i64 addrspace(1)* [ %a.cast, %left], [ %a.cast, %left], [ %a.cast, %left], [ %b.cast, %right]
+ %safepoint_token = call i32 (void (i64 addrspace(1)*)*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidp1i64f(void (i64 addrspace(1)*)* @parse_point, i32 1, i32 0, i64 addrspace(1)* %value, i32 5, i32 0, i32 0, i32 0, i32 0, i32 0)
+
+ ret i64 addrspace(1)* %value
+}
+
+;; The purpose of this test is to ensure that when two live values share a
+;; base defining value with inherent conflicts, we end up with a *single*
+;; base phi/select per such node. This is testing an optimization, not a
+;; fundemental correctness criteria
+define void @test2(i1 %cnd, i64 addrspace(1)* %base_obj, i64 addrspace(1)* %base_arg2) gc "statepoint-example" {
+; CHECK-LABEL: @test2
+entry:
+ %obj = getelementptr i64, i64 addrspace(1)* %base_obj, i32 1
+ br label %loop
+
+loop: ; preds = %loop, %entry
+; CHECK-LABEL: loop
+; CHECK: %base_phi = phi i64 addrspace(1)*
+; CHECK-DAG: [ %base_obj, %entry ]
+; CHECK-DAG: [ %base_select
+; CHECK-NOT: base_phi2
+; CHECK: next = select
+; CHECK: base_select
+; CHECK: extra2 = select
+; CHECK: base_select
+; CHECK: statepoint
+;; Both 'next' and 'extra2' are live across the backedge safepoint...
+ %current = phi i64 addrspace(1)* [ %obj, %entry ], [ %next, %loop ]
+ %extra = phi i64 addrspace(1)* [ %obj, %entry ], [ %extra2, %loop ]
+ %nexta = getelementptr i64, i64 addrspace(1)* %current, i32 1
+ %next = select i1 %cnd, i64 addrspace(1)* %nexta, i64 addrspace(1)* %base_arg2
+ %extra2 = select i1 %cnd, i64 addrspace(1)* %nexta, i64 addrspace(1)* %base_arg2
+ %safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @foo, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
+ br label %loop
+}
+
+declare void @foo()
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)
+declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidp1i64f(void (i64 addrspace(1)*)*, i32, i32, ...)