Infinite compile in InstCombine
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
InstCombine causes an infinite compile after https://github.com/llvm/llvm-project/pull/154336. The issue seems to be an oscillation between a new freeze being created in foldOpIntoPhi and then later in pushFreezeToPreventPoisonFromPropagating the same freeze is removed. Following is a snippet from the debug output:
```
IC: Visiting: %.fr = freeze i32 %71
...
ADD DEFERRED: %68 = freeze i32 %67
ADD DEFERRED: %72 = phi i32
IC: Replacing %.fr = freeze i32 %73
with %72 = phi i32 [ 52, %42 ], [ %68, %43 ]
...
ADD: %.fr = phi i32 [ 52, %42 ], [ %68, %43 ]
ADD: %68 = freeze i32 %67
IC: Visiting: %68 = freeze i32 %67
...
IC: Replacing %68 = freeze i32 %67
with %67 = select i1 %65, i32 54, i32 %66
IC: ERASE %68 = freeze i32 %67
ADD DEFERRED: %.fr = phi i32 [ 52, %42 ], [ %67, %43 ]
...
IC: Visiting: %.fr1 = freeze i32 %.fr
...
IC: Replacing %.fr1 = freeze i32 %72
with %.fr = phi i32 [ 52, %42 ], [ %68, %43 ]
...
ADD: %68 = freeze i32 %67
IC: Visiting: %68 = freeze i32 %67
IC: Replacing %68 = freeze i32 %67
with %67 = select i1 %65, i32 54, i32 %66
IC: ERASE %68 = freeze i32 %67
```
This issue was found while running spec2000/crafty with Ofast and thin-lto (in the function InitializeRandomHash from evaluate.c during the lto step).
I have been trying to get a reduced test case but I haven't had much success there. I currently have the following patch for this which I will be uploading soon after some testing:
```
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index c4beacdd1268..3a44253f8ecb 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1980,6 +1980,12 @@ Instruction *InstCombinerImpl::foldOpIntoPhi(Instruction &I, PHINode *PN,
Value *InVal = PN->getIncomingValue(i);
BasicBlock *InBB = PN->getIncomingBlock(i);
+ // Avoid repeatedly sinking a freeze into a PHI only for some of the newly
+ // created incoming freezes to be trivially removable again. That pattern
+ // can cause oscillation between freeze(phi(...)) and phi(..., freeze(x), ...).
+ if (isa(&I) && isGuaranteedNotToBeUndefOrPoison(InVal))
+ return nullptr;
+
if (auto *NewVal = simplifyInstructionWithPHI(I, PN, InVal, InBB, DL, SQ)) {
NewPhiValues.push_back(NewVal);
continue;
@@ -5214,6 +5220,11 @@ InstCombinerImpl::pushFreezeToPreventPoisonFromPropagating(FreezeInst &OrigFI) {
if (!isa(V) || isa(V))
return false;
+ // Don't push through an existing freeze. Otherwise we can repeatedly
+ // create redundant freeze instructions during instcombine iterations.
+ if (isa(V))
+ return false;
+
// We can't push the freeze through an instruction which can itself create
// poison. If the only source of new poison is flags, we can simply
```
Contributor guide
Research direction
Start in llvm/lib/Transforms/InstCombine/InstructionCombining.cpp, focusing on foldOpIntoPhi and pushFreezeToPreventPoisonFromPropagating. Reproduce the issue with spec2000/crafty using Ofast and thin-LTO, then inspect the InstCombine debug output for the freeze oscillation. Done means the infinite compile no longer occurs and the affected compilation completes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100