llvm.org GIT mirror llvm / 21f9a71
[RewriteStatepoints] Fix stale parse points Summary: RewriteStatepointsForGC collects parse points for further processing. During the collection if a callsite is found in an unreachable block (DominatorTree::isReachableFromEntry()) then all unreachable blocks are removed by removeUnreachableBlocks(). Some of the removed blocks could have been reachable according to DominatorTree::isReachableFromEntry(). In this case the collected parse points became stale and resulted in a crash when accessed. The fix is to unconditionally canonicalize the IR to removeUnreachableBlocks and then collect the parse points. The added test crashes with the old version and passes with this patch. Patch by Yevgeny Rouban! Reviewed by: Anna Differential Revision: https://reviews.llvm.org/D43929 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@326748 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Neilson 1 year, 6 months ago
4 changed file(s) with 71 addition(s) and 28 deletion(s). Raw diff Collapse all Expand all
25282528 return false;
25292529 };
25302530
2531
2532 // Delete any unreachable statepoints so that we don't have unrewritten
2533 // statepoints surviving this pass. This makes testing easier and the
2534 // resulting IR less confusing to human readers.
2535 DeferredDominance DD(DT);
2536 bool MadeChange = removeUnreachableBlocks(F, nullptr, &DD);
2537 DD.flush();
2538
25312539 // Gather all the statepoints which need rewritten. Be careful to only
25322540 // consider those in reachable code since we need to ask dominance queries
25332541 // when rewriting. We'll delete the unreachable ones in a moment.
25342542 SmallVector ParsePointNeeded;
2535 bool HasUnreachableStatepoint = false;
25362543 for (Instruction &I : instructions(F)) {
25372544 // TODO: only the ones with the flag set!
25382545 if (NeedsRewrite(I)) {
2539 if (DT.isReachableFromEntry(I.getParent()))
2540 ParsePointNeeded.push_back(CallSite(&I));
2541 else
2542 HasUnreachableStatepoint = true;
2543 }
2544 }
2545
2546 bool MadeChange = false;
2547
2548 // Delete any unreachable statepoints so that we don't have unrewritten
2549 // statepoints surviving this pass. This makes testing easier and the
2550 // resulting IR less confusing to human readers. Rather than be fancy, we
2551 // just reuse a utility function which removes the unreachable blocks.
2552 if (HasUnreachableStatepoint)
2553 MadeChange |= removeUnreachableBlocks(F);
2546 // NOTE removeUnreachableBlocks() is stronger than
2547 // DominatorTree::isReachableFromEntry(). In other words
2548 // removeUnreachableBlocks can remove some blocks for which
2549 // isReachableFromEntry() returns true.
2550 assert(DT.isReachableFromEntry(I.getParent()) &&
2551 "no unreachable blocks expected");
2552 ParsePointNeeded.push_back(CallSite(&I));
2553 }
2554 }
25542555
25552556 // Return early if no work to do.
25562557 if (ParsePointNeeded.empty())
102102 ret void
103103 }
104104
105 declare void @goo(i64)
106
107 declare i32 @moo(i64 addrspace(1)*)
108
105109 ; Make sure a use in a statepoint gets properly relocated at a previous one.
106110 ; This is basically just making sure that statepoints aren't accidentally
107111 ; treated specially.
112116 ; CHECK-NEXT: bitcast
113117 ; CHECK-NEXT: gc.statepoint
114118 entry:
115 call void undef(i64 undef) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]
116 %0 = call i32 undef(i64 addrspace(1)* %obj) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]
117 ret void
118 }
119 call void @goo(i64 undef) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]
120 %0 = call i32 @moo(i64 addrspace(1)* %obj) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0) ]
121 ret void
122 }
123
124 declare i8 addrspace(1)* @boo()
119125
120126 ; Check specifically for the case where the result of a statepoint needs to
121127 ; be relocated itself
126132 ; CHECK: gc.statepoint
127133 ; CHECK: [[RELOCATED:%[^ ]+]] = call {{.*}}gc.relocate
128134 ; CHECK: @use(i8 addrspace(1)* [[RELOCATED]])
129 %1 = call i8 addrspace(1)* undef() [ "deopt"() ]
130 %2 = call i8 addrspace(1)* undef() [ "deopt"() ]
135 %1 = call i8 addrspace(1)* @boo() [ "deopt"() ]
136 %2 = call i8 addrspace(1)* @boo() [ "deopt"() ]
131137 call void (...) @use(i8 addrspace(1)* %1)
132 unreachable
138 ret void
133139 }
134140
135141 ; Test updating a phi where not all inputs are live to begin with
136142 define void @test5(i8 addrspace(1)* %arg) gc "statepoint-example" {
137143 ; CHECK-LABEL: test5
138144 entry:
139 %0 = call i8 addrspace(1)* undef() [ "deopt"() ]
145 %0 = call i8 addrspace(1)* @boo() [ "deopt"() ]
140146 switch i32 undef, label %kill [
141147 i32 10, label %merge
142148 i32 13, label %merge
153159 ; CHECK-DAG: [ %arg.relocated, %entry ]
154160 %test = phi i8 addrspace(1)* [ null, %kill ], [ %arg, %entry ], [ %arg, %entry ]
155161 call void (...) @use(i8 addrspace(1)* %test)
156 unreachable
162 ret void
157163 }
158164
159165 ; Check to make sure we handle values live over an entry statepoint
0 ; RUN: opt -S -rewrite-statepoints-for-gc < %s | FileCheck %s
1 ; RUN: opt -S -passes=rewrite-statepoints-for-gc < %s | FileCheck %s
2 ;
3 ; Regression test:
4 ; After the rewritable callsite collection if any callsite was found
5 ; in a block that was reported unreachable by DominanceTree then
6 ; removeUnreachableBlocks() was called. But it is stronger than
7 ; DominatorTree::isReachableFromEntry(), i.e. removeUnreachableBlocks
8 ; can remove some blocks for which isReachableFromEntry() returns true.
9 ; This resulted in stale pointers to the collected but removed
10 ; callsites. Such stale pointers caused crash when accessed.
11 declare void @f(i8 addrspace(1)* %obj)
12
13 define void @test(i8 addrspace(1)* %arg) gc "statepoint-example" {
14 ; CHECK-LABEL: test(
15 ; CHECK-NEXT: @f
16 call void @f(i8 addrspace(1)* %arg) #1
17 br i1 true, label %not_zero, label %zero
18
19 not_zero:
20 ret void
21
22 ; This block is reachable but removed by removeUnreachableBlocks()
23 zero:
24 ; CHECK-NOT: @f
25 call void @f(i8 addrspace(1)* %arg) #1
26 ret void
27
28 unreach:
29 call void @f(i8 addrspace(1)* %arg) #1
30 ret void
31 }
32
33 attributes #1 = { norecurse noimplicitfloat }
66 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:1"
77 target triple = "x86_64-unknown-linux-gnu"
88
9 declare i8 addrspace(1)* @foo()
10
911 ; Function Attrs: uwtable
10 define void @test() gc "statepoint-example" {
12 define i32 @test() gc "statepoint-example" {
1113 ; CHECK-LABEL: @test
1214 entry:
1315 ; CHECK-LABEL: entry
2022 ; CHECK: load atomic
2123 %bc = bitcast <8 x i8 addrspace(1)*> undef to <8 x i32 addrspace(1)*>
2224 %ptr= extractelement <8 x i32 addrspace(1)*> %bc, i32 7
23 %0 = call i8 addrspace(1)* undef() [ "deopt"() ]
25 %0 = call i8 addrspace(1)* @foo() [ "deopt"() ]
2426 %1 = load atomic i32, i32 addrspace(1)* %ptr unordered, align 4
25 unreachable
27 ret i32 %1
2628 }