Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions llvm/lib/Transforms/Scalar/JumpThreading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1519,12 +1519,20 @@ Constant *JumpThreadingPass::evaluateOnPredecessorEdge(BasicBlock *BB,
}

// If we have a CmpInst, try to fold it for each incoming edge into PredBB.
// Note that during the execution of the pass, phi nodes may become constant
// and may be removed, which can lead to self-referencing instructions in
// code that becomes unreachable. Consequently, we need to handle those
// instructions in unreachable code and check before going into recursion.
if (CmpInst *CondCmp = dyn_cast<CmpInst>(V)) {
if (CondCmp->getParent() == BB) {
Constant *Op0 =
evaluateOnPredecessorEdge(BB, PredPredBB, CondCmp->getOperand(0), DL);
Constant *Op1 =
evaluateOnPredecessorEdge(BB, PredPredBB, CondCmp->getOperand(1), DL);
Constant *Op0 = CondCmp->getOperand(0) == CondCmp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handles one specific kind of recursion, but there may be recursion across multiple instructions. It would be better to add a Visited set instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean directly in evaluateOnPredecessorEdge?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do something like this (see the commit I just pushed), I guess

Copy link
Contributor Author

@ro-i ro-i Mar 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(+ I guess this could/should be a private method)

? nullptr
: evaluateOnPredecessorEdge(
BB, PredPredBB, CondCmp->getOperand(0), DL);
Constant *Op1 = CondCmp->getOperand(1) == CondCmp
? nullptr
: evaluateOnPredecessorEdge(
BB, PredPredBB, CondCmp->getOperand(1), DL);
if (Op0 && Op1) {
return ConstantFoldCompareInstOperands(CondCmp->getPredicate(), Op0,
Op1, DL);
Expand Down
59 changes: 59 additions & 0 deletions llvm/test/Transforms/JumpThreading/unreachable-loops.ll
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,63 @@ cleanup2343.loopexit4: ; preds = %cleanup1491
unreachable
}

; This segfaults due to recursion in %C4. Reason: %L6 is identified to be a
; "partially redundant load" and is replaced by a PHI node. The PHI node is then
; simplified to be constant and is removed. This leads to %L6 being replaced by
; %C4, which makes %C4 invalid since it uses %L6.
; The test case has been generated by the AMD Fuzzing project and simplified
; manually and by llvm-reduce.

define i32 @constant_phi_leads_to_self_reference(ptr %ptr) {
; CHECK-LABEL: @constant_phi_leads_to_self_reference(
; CHECK-NEXT: [[A9:%.*]] = alloca i1, align 1
; CHECK-NEXT: br label [[F6:%.*]]
; CHECK: T3:
; CHECK-NEXT: br label [[BB5:%.*]]
; CHECK: BB5:
; CHECK-NEXT: [[L10:%.*]] = load i1, ptr [[A9]], align 1
; CHECK-NEXT: br i1 [[L10]], label [[BB6:%.*]], label [[F6]]
; CHECK: BB6:
; CHECK-NEXT: [[LGV3:%.*]] = load i1, ptr [[PTR:%.*]], align 1
; CHECK-NEXT: [[C4:%.*]] = icmp sle i1 [[C4]], true
; CHECK-NEXT: store i1 [[C4]], ptr [[PTR]], align 1
; CHECK-NEXT: br i1 [[C4]], label [[F6]], label [[T3:%.*]]
; CHECK: F6:
; CHECK-NEXT: ret i32 0
; CHECK: F7:
; CHECK-NEXT: br label [[BB5]]
;
%A9 = alloca i1, align 1
br i1 false, label %BB4, label %F6

BB4: ; preds = %0
br i1 false, label %F6, label %F1

F1: ; preds = %BB4
br i1 false, label %T4, label %T3

T3: ; preds = %T4, %BB6, %F1
%L6 = load i1, ptr %ptr, align 1
br label %BB5

BB5: ; preds = %F7, %T3
%L10 = load i1, ptr %A9, align 1
br i1 %L10, label %BB6, label %F6

BB6: ; preds = %BB5
%LGV3 = load i1, ptr %ptr, align 1
%C4 = icmp sle i1 %L6, true
store i1 %C4, ptr %ptr, align 1
br i1 %L6, label %F6, label %T3

T4: ; preds = %F1
br label %T3

F6: ; preds = %BB6, %BB5, %BB4, %0
ret i32 0

F7: ; No predecessors!
br label %BB5
}

!0 = !{!"branch_weights", i32 2146410443, i32 1073205}