Skip to content

Commit d368128

Browse files
[GVN] do not repeat PRE on failure to split critical edge
Fixes an infinite loop encountered in GVN. GVN will delay PRE if it encounters critical edges, attempt to split them later via calls to SplitCriticalEdge(), then restart. The caller of GVN::splitCriticalEdges() assumed a return value of true meant that critical edges were split, that the IR had changed, and that PRE should be re-attempted, upon which we loop infinitely. This was exposed after D88438, by compiling the Linux kernel for s390, but the test case is reproducible on x86. Fixes: ClangBuiltLinux/linux#1261 Reviewed By: void Differential Revision: https://reviews.llvm.org/D94996
1 parent f5c7c03 commit d368128

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

llvm/lib/Transforms/Scalar/GVN.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2673,9 +2673,11 @@ BasicBlock *GVN::splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ) {
26732673
BasicBlock *BB = SplitCriticalEdge(
26742674
Pred, Succ,
26752675
CriticalEdgeSplittingOptions(DT, LI, MSSAU).unsetPreserveLoopSimplify());
2676-
if (MD)
2677-
MD->invalidateCachedPredecessors();
2678-
InvalidBlockRPONumbers = true;
2676+
if (BB) {
2677+
if (MD)
2678+
MD->invalidateCachedPredecessors();
2679+
InvalidBlockRPONumbers = true;
2680+
}
26792681
return BB;
26802682
}
26812683

@@ -2684,14 +2686,20 @@ BasicBlock *GVN::splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ) {
26842686
bool GVN::splitCriticalEdges() {
26852687
if (toSplit.empty())
26862688
return false;
2689+
2690+
bool Changed = false;
26872691
do {
26882692
std::pair<Instruction *, unsigned> Edge = toSplit.pop_back_val();
2689-
SplitCriticalEdge(Edge.first, Edge.second,
2690-
CriticalEdgeSplittingOptions(DT, LI, MSSAU));
2693+
Changed |= SplitCriticalEdge(Edge.first, Edge.second,
2694+
CriticalEdgeSplittingOptions(DT, LI, MSSAU)) !=
2695+
nullptr;
26912696
} while (!toSplit.empty());
2692-
if (MD) MD->invalidateCachedPredecessors();
2693-
InvalidBlockRPONumbers = true;
2694-
return true;
2697+
if (Changed) {
2698+
if (MD)
2699+
MD->invalidateCachedPredecessors();
2700+
InvalidBlockRPONumbers = true;
2701+
}
2702+
return Changed;
26952703
}
26962704

26972705
/// Executes one iteration of GVN
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
; RUN: opt -gvn -S -o - %s | FileCheck %s
2+
; RUN: opt -passes=gvn -S -o - %s | FileCheck %s
3+
4+
%struct.sk_buff = type opaque
5+
6+
@l2tp_recv_dequeue_session = external dso_local local_unnamed_addr global i32, align 4
7+
@l2tp_recv_dequeue_skb = external dso_local local_unnamed_addr global %struct.sk_buff*, align 8
8+
@l2tp_recv_dequeue_session_2 = external dso_local local_unnamed_addr global i32, align 4
9+
@l2tp_recv_dequeue_session_0 = external dso_local local_unnamed_addr global i32, align 4
10+
11+
declare void @llvm.assume(i1 noundef)
12+
13+
define dso_local void @l2tp_recv_dequeue() local_unnamed_addr {
14+
entry:
15+
%0 = load i32, i32* @l2tp_recv_dequeue_session, align 4
16+
%conv = sext i32 %0 to i64
17+
%1 = inttoptr i64 %conv to %struct.sk_buff*
18+
%2 = load i32, i32* @l2tp_recv_dequeue_session_2, align 4
19+
%tobool.not = icmp eq i32 %2, 0
20+
br label %for.cond
21+
22+
for.cond: ; preds = %if.end, %entry
23+
%storemerge = phi %struct.sk_buff* [ %1, %entry ], [ null, %if.end ]
24+
store %struct.sk_buff* %storemerge, %struct.sk_buff** @l2tp_recv_dequeue_skb, align 8
25+
br i1 %tobool.not, label %if.end, label %if.then
26+
27+
if.then: ; preds = %for.cond
28+
%ns = bitcast %struct.sk_buff* %storemerge to i32*
29+
%3 = load i32, i32* %ns, align 4
30+
store i32 %3, i32* @l2tp_recv_dequeue_session_0, align 4
31+
; Splitting the critical edge from if.then to if.end will fail, but should not
32+
; cause an infinite loop in GVN. If we can one day split edges of callbr
33+
; indirect targets, great!
34+
; CHECK: callbr void asm sideeffect "", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@l2tp_recv_dequeue, %if.end))
35+
; CHECK-NEXT: to label %asm.fallthrough.i [label %if.end]
36+
callbr void asm sideeffect "", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@l2tp_recv_dequeue, %if.end))
37+
to label %asm.fallthrough.i [label %if.end]
38+
39+
asm.fallthrough.i: ; preds = %if.then
40+
br label %if.end
41+
42+
if.end: ; preds = %asm.fallthrough.i, %if.then, %for.cond
43+
%ns1 = bitcast %struct.sk_buff* %storemerge to i32*
44+
%4 = load i32, i32* %ns1, align 4
45+
%tobool2.not = icmp eq i32 %4, 0
46+
tail call void @llvm.assume(i1 %tobool2.not)
47+
br label %for.cond
48+
}
49+

0 commit comments

Comments
 (0)