Skip to content

Commit a488438

Browse files
committed
[IR][JumpThreading] Fix infinite recursion on compare self-reference
In unreachable code, constant PHI nodes may appear and be replaced by their single value. As a result, instructions may become self-referencing. This commit adds checks to avoid going into infinite recursion when handling self-referencing compare instructions in `evaluateOnPredecessorEdge()`.
1 parent 9fe2146 commit a488438

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

llvm/lib/Transforms/Scalar/JumpThreading.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,11 +1519,15 @@ Constant *JumpThreadingPass::evaluateOnPredecessorEdge(BasicBlock *BB,
15191519
}
15201520

15211521
// If we have a CmpInst, try to fold it for each incoming edge into PredBB.
1522+
// Note that during the execution of the pass, phi nodes may become constant
1523+
// and may be removed, which can lead to self-referencing instructions in
1524+
// code that becomes unreachable. Consequently, we need to handle those
1525+
// instructions in unreachable code and check before going into recursion.
15221526
if (CmpInst *CondCmp = dyn_cast<CmpInst>(V)) {
15231527
if (CondCmp->getParent() == BB) {
1524-
Constant *Op0 =
1528+
Constant *Op0 = CondCmp->getOperand(0) == CondCmp ? nullptr :
15251529
evaluateOnPredecessorEdge(BB, PredPredBB, CondCmp->getOperand(0), DL);
1526-
Constant *Op1 =
1530+
Constant *Op1 = CondCmp->getOperand(1) == CondCmp ? nullptr :
15271531
evaluateOnPredecessorEdge(BB, PredPredBB, CondCmp->getOperand(1), DL);
15281532
if (Op0 && Op1) {
15291533
return ConstantFoldCompareInstOperands(CondCmp->getPredicate(), Op0,

llvm/test/Transforms/JumpThreading/unreachable-loops.ll

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,63 @@ cleanup2343.loopexit4: ; preds = %cleanup1491
180180
unreachable
181181
}
182182

183+
; This segfaults due to recursion in %C4. Reason: %L6 is identified to be a
184+
; "partially redundant load" and is replaced by a PHI node. The PHI node is then
185+
; simplified to be constant and is removed. This leads to %L6 being replaced by
186+
; %C4, which makes %C4 invalid since it uses %L6.
187+
; The test case has been generated by the AMD Fuzzing project and simplified
188+
; manually and by llvm-reduce.
189+
190+
define i32 @constant_phi_leads_to_self_reference(ptr %ptr) {
191+
; CHECK-LABEL: @constant_phi_leads_to_self_reference(
192+
; CHECK-NEXT: [[A9:%.*]] = alloca i1, align 1
193+
; CHECK-NEXT: br label [[F6:%.*]]
194+
; CHECK: T3:
195+
; CHECK-NEXT: br label [[BB5:%.*]]
196+
; CHECK: BB5:
197+
; CHECK-NEXT: [[L10:%.*]] = load i1, ptr [[A9]], align 1
198+
; CHECK-NEXT: br i1 [[L10]], label [[BB6:%.*]], label [[F6]]
199+
; CHECK: BB6:
200+
; CHECK-NEXT: [[LGV3:%.*]] = load i1, ptr [[PTR:%.*]], align 1
201+
; CHECK-NEXT: [[C4:%.*]] = icmp sle i1 [[C4]], true
202+
; CHECK-NEXT: store i1 [[C4]], ptr [[PTR]], align 1
203+
; CHECK-NEXT: br i1 [[C4]], label [[F6]], label [[T3:%.*]]
204+
; CHECK: F6:
205+
; CHECK-NEXT: ret i32 0
206+
; CHECK: F7:
207+
; CHECK-NEXT: br label [[BB5]]
208+
;
209+
%A9 = alloca i1, align 1
210+
br i1 false, label %BB4, label %F6
211+
212+
BB4: ; preds = %0
213+
br i1 false, label %F6, label %F1
214+
215+
F1: ; preds = %BB4
216+
br i1 false, label %T4, label %T3
217+
218+
T3: ; preds = %T4, %BB6, %F1
219+
%L6 = load i1, ptr %ptr, align 1
220+
br label %BB5
221+
222+
BB5: ; preds = %F7, %T3
223+
%L10 = load i1, ptr %A9, align 1
224+
br i1 %L10, label %BB6, label %F6
225+
226+
BB6: ; preds = %BB5
227+
%LGV3 = load i1, ptr %ptr, align 1
228+
%C4 = icmp sle i1 %L6, true
229+
store i1 %C4, ptr %ptr, align 1
230+
br i1 %L6, label %F6, label %T3
231+
232+
T4: ; preds = %F1
233+
br label %T3
234+
235+
F6: ; preds = %BB6, %BB5, %BB4, %0
236+
ret i32 0
237+
238+
F7: ; No predecessors!
239+
br label %BB5
240+
}
241+
183242
!0 = !{!"branch_weights", i32 2146410443, i32 1073205}

0 commit comments

Comments
 (0)