|  | ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | 
|  | ; RUN: opt < %s -passes='rewrite-statepoints-for-gc,verify<safepoint-ir>' -S | FileCheck %s | 
|  |  | 
|  | declare void @use_obj(ptr addrspace(1)) "gc-leaf-function" | 
|  | declare void @do_safepoint() | 
|  |  | 
|  |  | 
|  | ; Profitable test | 
|  | define i32 @test_remat(ptr addrspace(1) %base, i1 %cond) gc "statepoint-example" { | 
|  | ; CHECK-LABEL: @test_remat( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[DERIVED:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE:%.*]], i32 16 | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    br i1 [[COND:%.*]], label [[HERE:%.*]], label [[THERE:%.*]] | 
|  | ; CHECK:       here: | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN1:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE_RELOCATED]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED2:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN1]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    br label [[MERGE:%.*]] | 
|  | ; CHECK:       there: | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN3:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE_RELOCATED]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED4:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN3]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    br label [[MERGE]] | 
|  | ; CHECK:       merge: | 
|  | ; CHECK-NEXT:    [[DOT0:%.*]] = phi ptr addrspace(1) [ [[BASE_RELOCATED2]], [[HERE]] ], [ [[BASE_RELOCATED4]], [[THERE]] ] | 
|  | ; CHECK-NEXT:    [[DERIVED_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[DOT0]], i32 16 | 
|  | ; CHECK-NEXT:    [[RET:%.*]] = load i32, ptr addrspace(1) [[DERIVED_REMAT]], align 4 | 
|  | ; CHECK-NEXT:    ret i32 [[RET]] | 
|  | ; | 
|  | entry: | 
|  | %derived = getelementptr i32, ptr addrspace(1) %base, i32 16 | 
|  | call void @do_safepoint() [ "deopt"() ] | 
|  | br i1 %cond, label %here, label %there | 
|  |  | 
|  | here: | 
|  | call void @do_safepoint() [ "deopt"() ] | 
|  | br label %merge | 
|  |  | 
|  | there: | 
|  | call void @do_safepoint() [ "deopt"() ] | 
|  | br label %merge | 
|  |  | 
|  | merge: | 
|  | %ret = load i32, ptr addrspace(1) %derived | 
|  | ret i32 %ret | 
|  | } | 
|  |  | 
|  | ; Unprofitable test | 
|  | define i32 @test_many_uses(ptr addrspace(1) %base, i1 %cond) gc "statepoint-example" { | 
|  | ; CHECK-LABEL: @test_many_uses( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[DERIVED:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE:%.*]], i32 16 | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    [[DERIVED_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED]], i32 16 | 
|  | ; CHECK-NEXT:    br i1 [[COND:%.*]], label [[HERE:%.*]], label [[THERE:%.*]] | 
|  | ; CHECK:       here: | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN3:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE_RELOCATED]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED4:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN3]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    [[DERIVED_REMAT1:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED4]], i32 16 | 
|  | ; CHECK-NEXT:    call void @use_obj(ptr addrspace(1) [[DERIVED_REMAT1]]) | 
|  | ; CHECK-NEXT:    br label [[MERGE:%.*]] | 
|  | ; CHECK:       there: | 
|  | ; CHECK-NEXT:    call void @use_obj(ptr addrspace(1) [[DERIVED_REMAT]]) | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN5:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE_RELOCATED]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED6:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN5]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    [[DERIVED_REMAT2:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED6]], i32 16 | 
|  | ; CHECK-NEXT:    br label [[MERGE]] | 
|  | ; CHECK:       merge: | 
|  | ; CHECK-NEXT:    [[DOT0:%.*]] = phi ptr addrspace(1) [ [[DERIVED_REMAT1]], [[HERE]] ], [ [[DERIVED_REMAT2]], [[THERE]] ] | 
|  | ; CHECK-NEXT:    call void @use_obj(ptr addrspace(1) [[DOT0]]) | 
|  | ; CHECK-NEXT:    [[RET:%.*]] = load i32, ptr addrspace(1) [[DOT0]], align 4 | 
|  | ; CHECK-NEXT:    ret i32 [[RET]] | 
|  | ; | 
|  | entry: | 
|  | %derived = getelementptr i32, ptr addrspace(1) %base, i32 16 | 
|  | call void @do_safepoint() [ "deopt" () ] | 
|  | br i1 %cond, label %here, label %there | 
|  |  | 
|  | here: | 
|  | call void @do_safepoint() [ "deopt"() ] | 
|  | call void @use_obj(ptr addrspace(1) %derived) | 
|  | br label %merge | 
|  |  | 
|  | there: | 
|  | call void @use_obj(ptr addrspace(1) %derived) | 
|  | call void @do_safepoint() [ "deopt"() ] | 
|  | br label %merge | 
|  |  | 
|  | merge: | 
|  | call void @use_obj(ptr addrspace(1) %derived) | 
|  | %ret = load i32, ptr addrspace(1) %derived | 
|  | ret i32 %ret | 
|  | } | 
|  |  | 
|  | ; Remat before phi - not implemented | 
|  | define i32 @test_phi(ptr addrspace(1) %base, i1 %cond) gc "statepoint-example" { | 
|  | ; CHECK-LABEL: @test_phi( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[DERIVED1:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE:%.*]], i32 16 | 
|  | ; CHECK-NEXT:    [[DERIVED2:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE]], i32 32 | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    [[DERIVED2_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED]], i32 32 | 
|  | ; CHECK-NEXT:    [[DERIVED1_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED]], i32 16 | 
|  | ; CHECK-NEXT:    br i1 [[COND:%.*]], label [[HERE:%.*]], label [[THERE:%.*]] | 
|  | ; CHECK:       here: | 
|  | ; CHECK-NEXT:    br label [[MERGE:%.*]] | 
|  | ; CHECK:       there: | 
|  | ; CHECK-NEXT:    br label [[MERGE]] | 
|  | ; CHECK:       merge: | 
|  | ; CHECK-NEXT:    [[PHI1:%.*]] = phi ptr addrspace(1) [ [[DERIVED1_REMAT]], [[HERE]] ], [ [[DERIVED2_REMAT]], [[THERE]] ] | 
|  | ; CHECK-NEXT:    [[RET:%.*]] = load i32, ptr addrspace(1) [[PHI1]], align 4 | 
|  | ; CHECK-NEXT:    ret i32 [[RET]] | 
|  | ; | 
|  | entry: | 
|  | %derived1 = getelementptr i32, ptr addrspace(1) %base, i32 16 | 
|  | %derived2 = getelementptr i32, ptr addrspace(1) %base, i32 32 | 
|  | call void @do_safepoint() [ "deopt"() ] | 
|  | br i1 %cond, label %here, label %there | 
|  |  | 
|  | here: | 
|  | br label %merge | 
|  |  | 
|  | there: | 
|  | br label %merge | 
|  |  | 
|  | merge: | 
|  | %phi1 = phi ptr addrspace(1) [ %derived1, %here ], [ %derived2, %there ] | 
|  | %ret = load i32, ptr addrspace(1) %phi1 | 
|  | ret i32 %ret | 
|  | } | 
|  |  | 
|  | ; Several uses per block | 
|  | ; TODO: We could rematerialize once per block for several uses if there is not statepoint between | 
|  | define i32 @test_same_block_with_statepoint(ptr addrspace(1) %base, i1 %cond) gc "statepoint-example" { | 
|  | ; CHECK-LABEL: @test_same_block_with_statepoint( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[DERIVED:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE:%.*]], i32 16 | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    br i1 [[COND:%.*]], label [[HERE:%.*]], label [[THERE:%.*]] | 
|  | ; CHECK:       here: | 
|  | ; CHECK-NEXT:    [[DERIVED_REMAT3:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED]], i32 16 | 
|  | ; CHECK-NEXT:    call void @use_obj(ptr addrspace(1) [[DERIVED_REMAT3]]) | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN4:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE_RELOCATED]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED5:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN4]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    [[DERIVED_REMAT2:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED5]], i32 16 | 
|  | ; CHECK-NEXT:    call void @use_obj(ptr addrspace(1) [[DERIVED_REMAT2]]) | 
|  | ; CHECK-NEXT:    [[DERIVED_REMAT1:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED5]], i32 16 | 
|  | ; CHECK-NEXT:    [[DUMMY:%.*]] = load i32, ptr addrspace(1) [[DERIVED_REMAT1]], align 4 | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN6:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE_RELOCATED5]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED7:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN6]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    br label [[MERGE:%.*]] | 
|  | ; CHECK:       there: | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN8:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) [[BASE_RELOCATED]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED9:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN8]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    br label [[MERGE]] | 
|  | ; CHECK:       merge: | 
|  | ; CHECK-NEXT:    [[DOT0:%.*]] = phi ptr addrspace(1) [ [[BASE_RELOCATED7]], [[HERE]] ], [ [[BASE_RELOCATED9]], [[THERE]] ] | 
|  | ; CHECK-NEXT:    [[DERIVED_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[DOT0]], i32 16 | 
|  | ; CHECK-NEXT:    [[RET:%.*]] = load i32, ptr addrspace(1) [[DERIVED_REMAT]], align 4 | 
|  | ; CHECK-NEXT:    ret i32 [[RET]] | 
|  | ; | 
|  | entry: | 
|  | %derived = getelementptr i32, ptr addrspace(1) %base, i32 16 | 
|  | call void @do_safepoint() [ "deopt" () ] | 
|  | br i1 %cond, label %here, label %there | 
|  |  | 
|  | here: | 
|  | call void @use_obj(ptr addrspace(1) %derived) | 
|  | call void @do_safepoint() [ "deopt"() ] | 
|  | call void @use_obj(ptr addrspace(1) %derived) | 
|  | %dummy = load i32, ptr addrspace(1) %derived | 
|  | call void @do_safepoint() [ "deopt" () ] | 
|  | br label %merge | 
|  |  | 
|  | there: | 
|  | call void @do_safepoint() [ "deopt"() ] | 
|  | br label %merge | 
|  |  | 
|  | merge: | 
|  | %ret = load i32, ptr addrspace(1) %derived | 
|  | ret i32 %ret | 
|  | } | 
|  |  | 
|  | ; Test long chain with sub-chain rematerialized | 
|  | ; TODO: If we rematerialized longer chain first (%v4), then shorter on (%v0) would become dead | 
|  | define void @test_chain(ptr addrspace(1) %base, i1 %cond1) gc "statepoint-example" { | 
|  | ; CHECK-LABEL: @test_chain( | 
|  | ; CHECK-NEXT:  entry: | 
|  | ; CHECK-NEXT:    [[V0:%.*]] = getelementptr i8, ptr addrspace(1) [[BASE:%.*]], i64 16 | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(ptr addrspace(1) [[BASE]]), "gc-live"(ptr addrspace(1) [[BASE]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    br i1 [[COND1:%.*]], label [[BLOCK3:%.*]], label [[COMMON_RET:%.*]] | 
|  | ; CHECK:       block3: | 
|  | ; CHECK-NEXT:    [[V0_REMAT:%.*]] = getelementptr i8, ptr addrspace(1) [[BASE_RELOCATED]], i64 16 | 
|  | ; CHECK-NEXT:    [[V4:%.*]] = getelementptr i8, ptr addrspace(1) [[V0_REMAT]], i64 70 | 
|  | ; CHECK-NEXT:    [[STATEPOINT_TOKEN1:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(ptr addrspace(1) [[BASE_RELOCATED]]), "gc-live"(ptr addrspace(1) [[BASE_RELOCATED]]) ] | 
|  | ; CHECK-NEXT:    [[BASE_RELOCATED2:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN1]], i32 0, i32 0) | 
|  | ; CHECK-NEXT:    [[V0_REMAT_REMAT:%.*]] = getelementptr i8, ptr addrspace(1) [[BASE_RELOCATED2]], i64 16 | 
|  | ; CHECK-NEXT:    [[V4_REMAT:%.*]] = getelementptr i8, ptr addrspace(1) [[V0_REMAT_REMAT]], i64 70 | 
|  | ; CHECK-NEXT:    [[V5:%.*]] = load atomic i8, ptr addrspace(1) [[V4_REMAT]] unordered, align 2 | 
|  | ; CHECK-NEXT:    br label [[COMMON_RET]] | 
|  | ; CHECK:       common.ret: | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | %v0 = getelementptr i8, ptr addrspace(1) %base, i64 16 | 
|  | call void @do_safepoint() [ "deopt"(ptr addrspace(1) %base) ] | 
|  | br i1 %cond1, label %block3, label %common.ret | 
|  |  | 
|  | block3: | 
|  | %v4 = getelementptr i8, ptr addrspace(1) %v0, i64 70 | 
|  | call void @do_safepoint() [ "deopt"(ptr addrspace(1) %base) ] | 
|  | %v5 = load atomic i8, ptr addrspace(1) %v4 unordered, align 2 | 
|  | br label %common.ret | 
|  |  | 
|  | common.ret: | 
|  | ret void | 
|  | } |