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