1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes='rewrite-statepoints-for-gc,verify<safepoint-ir>' -S | FileCheck %s 3 4declare void @use_obj(ptr addrspace(1)) "gc-leaf-function" 5declare void @do_safepoint() 6 7 8; Profitable test 9define i32 @test_remat(ptr addrspace(1) %base, i1 %cond) gc "statepoint-example" { 10; CHECK-LABEL: @test_remat( 11; CHECK-NEXT: entry: 12; CHECK-NEXT: [[DERIVED:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE:%.*]], i32 16 13; 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]]) ] 14; CHECK-NEXT: [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) 15; CHECK-NEXT: br i1 [[COND:%.*]], label [[HERE:%.*]], label [[THERE:%.*]] 16; CHECK: here: 17; 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]]) ] 18; CHECK-NEXT: [[BASE_RELOCATED2:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN1]], i32 0, i32 0) 19; CHECK-NEXT: br label [[MERGE:%.*]] 20; CHECK: there: 21; 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]]) ] 22; CHECK-NEXT: [[BASE_RELOCATED4:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN3]], i32 0, i32 0) 23; CHECK-NEXT: br label [[MERGE]] 24; CHECK: merge: 25; CHECK-NEXT: [[DOT0:%.*]] = phi ptr addrspace(1) [ [[BASE_RELOCATED2]], [[HERE]] ], [ [[BASE_RELOCATED4]], [[THERE]] ] 26; CHECK-NEXT: [[DERIVED_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[DOT0]], i32 16 27; CHECK-NEXT: [[RET:%.*]] = load i32, ptr addrspace(1) [[DERIVED_REMAT]], align 4 28; CHECK-NEXT: ret i32 [[RET]] 29; 30entry: 31 %derived = getelementptr i32, ptr addrspace(1) %base, i32 16 32 call void @do_safepoint() [ "deopt"() ] 33 br i1 %cond, label %here, label %there 34 35here: 36 call void @do_safepoint() [ "deopt"() ] 37 br label %merge 38 39there: 40 call void @do_safepoint() [ "deopt"() ] 41 br label %merge 42 43merge: 44 %ret = load i32, ptr addrspace(1) %derived 45 ret i32 %ret 46} 47 48; Unprofitable test 49define i32 @test_many_uses(ptr addrspace(1) %base, i1 %cond) gc "statepoint-example" { 50; CHECK-LABEL: @test_many_uses( 51; CHECK-NEXT: entry: 52; CHECK-NEXT: [[DERIVED:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE:%.*]], i32 16 53; 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]]) ] 54; CHECK-NEXT: [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) 55; CHECK-NEXT: [[DERIVED_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED]], i32 16 56; CHECK-NEXT: br i1 [[COND:%.*]], label [[HERE:%.*]], label [[THERE:%.*]] 57; CHECK: here: 58; 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]]) ] 59; CHECK-NEXT: [[BASE_RELOCATED4:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN3]], i32 0, i32 0) 60; CHECK-NEXT: [[DERIVED_REMAT1:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED4]], i32 16 61; CHECK-NEXT: call void @use_obj(ptr addrspace(1) [[DERIVED_REMAT1]]) 62; CHECK-NEXT: br label [[MERGE:%.*]] 63; CHECK: there: 64; CHECK-NEXT: call void @use_obj(ptr addrspace(1) [[DERIVED_REMAT]]) 65; 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]]) ] 66; CHECK-NEXT: [[BASE_RELOCATED6:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN5]], i32 0, i32 0) 67; CHECK-NEXT: [[DERIVED_REMAT2:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED6]], i32 16 68; CHECK-NEXT: br label [[MERGE]] 69; CHECK: merge: 70; CHECK-NEXT: [[DOT0:%.*]] = phi ptr addrspace(1) [ [[DERIVED_REMAT1]], [[HERE]] ], [ [[DERIVED_REMAT2]], [[THERE]] ] 71; CHECK-NEXT: call void @use_obj(ptr addrspace(1) [[DOT0]]) 72; CHECK-NEXT: [[RET:%.*]] = load i32, ptr addrspace(1) [[DOT0]], align 4 73; CHECK-NEXT: ret i32 [[RET]] 74; 75entry: 76 %derived = getelementptr i32, ptr addrspace(1) %base, i32 16 77 call void @do_safepoint() [ "deopt" () ] 78 br i1 %cond, label %here, label %there 79 80here: 81 call void @do_safepoint() [ "deopt"() ] 82 call void @use_obj(ptr addrspace(1) %derived) 83 br label %merge 84 85there: 86 call void @use_obj(ptr addrspace(1) %derived) 87 call void @do_safepoint() [ "deopt"() ] 88 br label %merge 89 90merge: 91 call void @use_obj(ptr addrspace(1) %derived) 92 %ret = load i32, ptr addrspace(1) %derived 93 ret i32 %ret 94} 95 96; Remat before phi - not implemented 97define i32 @test_phi(ptr addrspace(1) %base, i1 %cond) gc "statepoint-example" { 98; CHECK-LABEL: @test_phi( 99; CHECK-NEXT: entry: 100; CHECK-NEXT: [[DERIVED1:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE:%.*]], i32 16 101; CHECK-NEXT: [[DERIVED2:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE]], i32 32 102; 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]]) ] 103; CHECK-NEXT: [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) 104; CHECK-NEXT: [[DERIVED2_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED]], i32 32 105; CHECK-NEXT: [[DERIVED1_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED]], i32 16 106; CHECK-NEXT: br i1 [[COND:%.*]], label [[HERE:%.*]], label [[THERE:%.*]] 107; CHECK: here: 108; CHECK-NEXT: br label [[MERGE:%.*]] 109; CHECK: there: 110; CHECK-NEXT: br label [[MERGE]] 111; CHECK: merge: 112; CHECK-NEXT: [[PHI1:%.*]] = phi ptr addrspace(1) [ [[DERIVED1_REMAT]], [[HERE]] ], [ [[DERIVED2_REMAT]], [[THERE]] ] 113; CHECK-NEXT: [[RET:%.*]] = load i32, ptr addrspace(1) [[PHI1]], align 4 114; CHECK-NEXT: ret i32 [[RET]] 115; 116entry: 117 %derived1 = getelementptr i32, ptr addrspace(1) %base, i32 16 118 %derived2 = getelementptr i32, ptr addrspace(1) %base, i32 32 119 call void @do_safepoint() [ "deopt"() ] 120 br i1 %cond, label %here, label %there 121 122here: 123 br label %merge 124 125there: 126 br label %merge 127 128merge: 129 %phi1 = phi ptr addrspace(1) [ %derived1, %here ], [ %derived2, %there ] 130 %ret = load i32, ptr addrspace(1) %phi1 131 ret i32 %ret 132} 133 134; Several uses per block 135; TODO: We could rematerialize once per block for several uses if there is not statepoint between 136define i32 @test_same_block_with_statepoint(ptr addrspace(1) %base, i1 %cond) gc "statepoint-example" { 137; CHECK-LABEL: @test_same_block_with_statepoint( 138; CHECK-NEXT: entry: 139; CHECK-NEXT: [[DERIVED:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE:%.*]], i32 16 140; 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]]) ] 141; CHECK-NEXT: [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) 142; CHECK-NEXT: br i1 [[COND:%.*]], label [[HERE:%.*]], label [[THERE:%.*]] 143; CHECK: here: 144; CHECK-NEXT: [[DERIVED_REMAT3:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED]], i32 16 145; CHECK-NEXT: call void @use_obj(ptr addrspace(1) [[DERIVED_REMAT3]]) 146; 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]]) ] 147; CHECK-NEXT: [[BASE_RELOCATED5:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN4]], i32 0, i32 0) 148; CHECK-NEXT: [[DERIVED_REMAT2:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED5]], i32 16 149; CHECK-NEXT: call void @use_obj(ptr addrspace(1) [[DERIVED_REMAT2]]) 150; CHECK-NEXT: [[DERIVED_REMAT1:%.*]] = getelementptr i32, ptr addrspace(1) [[BASE_RELOCATED5]], i32 16 151; CHECK-NEXT: [[DUMMY:%.*]] = load i32, ptr addrspace(1) [[DERIVED_REMAT1]], align 4 152; 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]]) ] 153; CHECK-NEXT: [[BASE_RELOCATED7:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN6]], i32 0, i32 0) 154; CHECK-NEXT: br label [[MERGE:%.*]] 155; CHECK: there: 156; 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]]) ] 157; CHECK-NEXT: [[BASE_RELOCATED9:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN8]], i32 0, i32 0) 158; CHECK-NEXT: br label [[MERGE]] 159; CHECK: merge: 160; CHECK-NEXT: [[DOT0:%.*]] = phi ptr addrspace(1) [ [[BASE_RELOCATED7]], [[HERE]] ], [ [[BASE_RELOCATED9]], [[THERE]] ] 161; CHECK-NEXT: [[DERIVED_REMAT:%.*]] = getelementptr i32, ptr addrspace(1) [[DOT0]], i32 16 162; CHECK-NEXT: [[RET:%.*]] = load i32, ptr addrspace(1) [[DERIVED_REMAT]], align 4 163; CHECK-NEXT: ret i32 [[RET]] 164; 165entry: 166 %derived = getelementptr i32, ptr addrspace(1) %base, i32 16 167 call void @do_safepoint() [ "deopt" () ] 168 br i1 %cond, label %here, label %there 169 170here: 171 call void @use_obj(ptr addrspace(1) %derived) 172 call void @do_safepoint() [ "deopt"() ] 173 call void @use_obj(ptr addrspace(1) %derived) 174 %dummy = load i32, ptr addrspace(1) %derived 175 call void @do_safepoint() [ "deopt" () ] 176 br label %merge 177 178there: 179 call void @do_safepoint() [ "deopt"() ] 180 br label %merge 181 182merge: 183 %ret = load i32, ptr addrspace(1) %derived 184 ret i32 %ret 185} 186 187; Test long chain with sub-chain rematerialized 188; TODO: If we rematerialized longer chain first (%v4), then shorter on (%v0) would become dead 189define void @test_chain(ptr addrspace(1) %base, i1 %cond1) gc "statepoint-example" { 190; CHECK-LABEL: @test_chain( 191; CHECK-NEXT: entry: 192; CHECK-NEXT: [[V0:%.*]] = getelementptr i8, ptr addrspace(1) [[BASE:%.*]], i64 16 193; 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]]) ] 194; CHECK-NEXT: [[BASE_RELOCATED:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN]], i32 0, i32 0) 195; CHECK-NEXT: br i1 [[COND1:%.*]], label [[BLOCK3:%.*]], label [[COMMON_RET:%.*]] 196; CHECK: block3: 197; CHECK-NEXT: [[V0_REMAT:%.*]] = getelementptr i8, ptr addrspace(1) [[BASE_RELOCATED]], i64 16 198; CHECK-NEXT: [[V4:%.*]] = getelementptr i8, ptr addrspace(1) [[V0_REMAT]], i64 70 199; 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]]) ] 200; CHECK-NEXT: [[BASE_RELOCATED2:%.*]] = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token [[STATEPOINT_TOKEN1]], i32 0, i32 0) 201; CHECK-NEXT: [[V0_REMAT_REMAT:%.*]] = getelementptr i8, ptr addrspace(1) [[BASE_RELOCATED2]], i64 16 202; CHECK-NEXT: [[V4_REMAT:%.*]] = getelementptr i8, ptr addrspace(1) [[V0_REMAT_REMAT]], i64 70 203; CHECK-NEXT: [[V5:%.*]] = load atomic i8, ptr addrspace(1) [[V4_REMAT]] unordered, align 2 204; CHECK-NEXT: br label [[COMMON_RET]] 205; CHECK: common.ret: 206; CHECK-NEXT: ret void 207; 208entry: 209 %v0 = getelementptr i8, ptr addrspace(1) %base, i64 16 210 call void @do_safepoint() [ "deopt"(ptr addrspace(1) %base) ] 211 br i1 %cond1, label %block3, label %common.ret 212 213block3: 214 %v4 = getelementptr i8, ptr addrspace(1) %v0, i64 70 215 call void @do_safepoint() [ "deopt"(ptr addrspace(1) %base) ] 216 %v5 = load atomic i8, ptr addrspace(1) %v4 unordered, align 2 217 br label %common.ret 218 219common.ret: 220 ret void 221} 222