1; A collection of liveness test cases to ensure we're reporting the 2; correct live values at statepoints 3; RUN: opt -passes=rewrite-statepoints-for-gc -spp-rematerialization-threshold=0 -S < %s | FileCheck %s 4 5; Tests to make sure we consider %obj live in both the taken and untaken 6; predeccessor of merge. 7 8define ptr addrspace(1) @test1(i1 %cmp, ptr addrspace(1) %obj) gc "statepoint-example" { 9; CHECK-LABEL: @test1 10entry: 11 br i1 %cmp, label %taken, label %untaken 12 13taken: ; preds = %entry 14; CHECK-LABEL: taken: 15; CHECK-NEXT: gc.statepoint 16; CHECK-NEXT: %obj.relocated = call coldcc ptr addrspace(1) 17; CHECK-NEXT: br label %merge 18 call void @foo() [ "deopt"() ] 19 br label %merge 20 21untaken: ; preds = %entry 22; CHECK-LABEL: untaken: 23; CHECK-NEXT: gc.statepoint 24; CHECK-NEXT: %obj.relocated2 = call coldcc ptr addrspace(1) 25; CHECK-NEXT: br label %merge 26 call void @foo() [ "deopt"() ] 27 br label %merge 28 29merge: ; preds = %untaken, %taken 30; CHECK-LABEL: merge: 31; CHECK-NEXT: %.0 = phi ptr addrspace(1) [ %obj.relocated, %taken ], [ %obj.relocated2, %untaken ] 32; CHECK-NEXT: ret ptr addrspace(1) %.0 33; A local kill should not effect liveness in predecessor block 34 ret ptr addrspace(1) %obj 35} 36 37define ptr addrspace(1) @test2(i1 %cmp, ptr %loc) gc "statepoint-example" { 38; CHECK-LABEL: @test2 39entry: 40; CHECK-LABEL: entry: 41; CHECK-NEXT: gc.statepoint 42; CHECK-NEXT: br 43 call void @foo() [ "deopt"() ] 44 br i1 %cmp, label %taken, label %untaken 45 46taken: ; preds = %entry 47; CHECK-LABEL: taken: 48; CHECK-NEXT: %obj = load 49; CHECK-NEXT: gc.statepoint 50; CHECK-NEXT: gc.relocate 51; CHECK-NEXT: ret ptr addrspace(1) %obj.relocated 52; A local kill should effect values live from a successor phi. Also, we 53; should only propagate liveness from a phi to the appropriate predecessors. 54 %obj = load ptr addrspace(1), ptr %loc 55 call void @foo() [ "deopt"() ] 56 ret ptr addrspace(1) %obj 57 58untaken: ; preds = %entry 59 ret ptr addrspace(1) null 60} 61 62define ptr addrspace(1) @test3(i1 %cmp, ptr %loc) gc "statepoint-example" { 63; CHECK-LABEL: @test3 64entry: 65 br i1 %cmp, label %taken, label %untaken 66 67taken: ; preds = %entry 68; CHECK-LABEL: taken: 69; CHECK-NEXT: gc.statepoint 70; CHECK-NEXT: %obj = load 71; CHECK-NEXT: gc.statepoint 72; CHECK-NEXT: %obj.relocated = call coldcc ptr addrspace(1) 73; CHECK-NEXT: br label %merge 74 call void @foo() [ "deopt"() ] 75 %obj = load ptr addrspace(1), ptr %loc 76 call void @foo() [ "deopt"() ] 77 br label %merge 78 79untaken: ; preds = %entry 80; CHECK-LABEL: taken: 81; CHECK-NEXT: gc.statepoint 82; CHECK-NEXT: br label %merge 83; A base pointer must be live if it is needed at a later statepoint, 84; even if the base pointer is otherwise unused. 85 call void @foo() [ "deopt"() ] 86 br label %merge 87 88merge: ; preds = %untaken, %taken 89 %phi = phi ptr addrspace(1) [ %obj, %taken ], [ null, %untaken ] 90 ret ptr addrspace(1) %phi 91} 92 93define ptr addrspace(1) @test4(i1 %cmp, ptr addrspace(1) %obj) gc "statepoint-example" { 94; CHECK-LABEL: @test4 95entry: 96; CHECK-LABEL: entry: 97; CHECK-NEXT: %derived = getelementptr 98; CHECK-NEXT: gc.statepoint 99; CHECK-NEXT: %derived.relocated = 100; CHECK-NEXT: %obj.relocated = 101; CHECK-NEXT: gc.statepoint 102; CHECK-NEXT: %derived.relocated2 = 103 104; Note: It's legal to relocate obj again, but not strictly needed 105; CHECK-NEXT: %obj.relocated3 = 106; CHECK-NEXT: ret ptr addrspace(1) %derived.relocated2 107; 108; Make sure that a phi def visited during iteration is considered a kill. 109; Also, liveness after base pointer analysis can change based on new uses, 110; not just new defs. 111 %derived = getelementptr i64, ptr addrspace(1) %obj, i64 8 112 call void @foo() [ "deopt"() ] 113 call void @foo() [ "deopt"() ] 114 ret ptr addrspace(1) %derived 115} 116 117declare void @consume(...) readonly "gc-leaf-function" 118 119define ptr addrspace(1) @test5(i1 %cmp, ptr addrspace(1) %obj) gc "statepoint-example" { 120; CHECK-LABEL: @test5 121entry: 122 br i1 %cmp, label %taken, label %untaken 123 124taken: ; preds = %entry 125; CHECK-LABEL: taken: 126; CHECK-NEXT: gc.statepoint 127; CHECK-NEXT: %obj.relocated = call coldcc ptr addrspace(1) 128; CHECK-NEXT: br label %merge 129 call void @foo() [ "deopt"() ] 130 br label %merge 131 132untaken: ; preds = %entry 133; CHECK-LABEL: untaken: 134; CHECK-NEXT: br label %merge 135 br label %merge 136 137merge: ; preds = %untaken, %taken 138; CHECK-LABEL: merge: 139; CHECK-NEXT: %.0 = phi ptr addrspace(1) 140; CHECK-NEXT: %obj2a = phi 141; CHECK-NEXT: @consume 142; CHECK-NEXT: br label %final 143 %obj2a = phi ptr addrspace(1) [ %obj, %taken ], [ null, %untaken ] 144 call void (...) @consume(ptr addrspace(1) %obj2a) 145 br label %final 146 147final: ; preds = %merge 148; CHECK-LABEL: final: 149; CHECK-NEXT: @consume 150; CHECK-NEXT: ret ptr addrspace(1) %.0 151 call void (...) @consume(ptr addrspace(1) %obj2a) 152 ret ptr addrspace(1) %obj 153} 154 155declare void @foo() 156 157