Skip to content

Commit a700298

Browse files
authored
[CanonicalizeFreezeInLoops] fix duplicate removal (#74716)
This PR fixes #74572 where the freeze instruction could be found twice by the pass CanonicalizeFreezeInLoops, and then the compiling may crash in second removal since the instruction has already gone.
1 parent fb981e6 commit a700298

File tree

2 files changed

+76
-16
lines changed

2 files changed

+76
-16
lines changed

llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@
2929
//===----------------------------------------------------------------------===//
3030

3131
#include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h"
32+
#include "llvm/ADT/DenseMapInfo.h"
3233
#include "llvm/ADT/STLExtras.h"
34+
#include "llvm/ADT/SetVector.h"
3335
#include "llvm/ADT/SmallSet.h"
34-
#include "llvm/ADT/SmallVector.h"
3536
#include "llvm/Analysis/IVDescriptors.h"
3637
#include "llvm/Analysis/LoopAnalysisManager.h"
3738
#include "llvm/Analysis/LoopInfo.h"
@@ -66,19 +67,6 @@ class CanonicalizeFreezeInLoopsImpl {
6667
ScalarEvolution &SE;
6768
DominatorTree &DT;
6869

69-
struct FrozenIndPHIInfo {
70-
// A freeze instruction that uses an induction phi
71-
FreezeInst *FI = nullptr;
72-
// The induction phi, step instruction, the operand idx of StepInst which is
73-
// a step value
74-
PHINode *PHI;
75-
BinaryOperator *StepInst;
76-
unsigned StepValIdx = 0;
77-
78-
FrozenIndPHIInfo(PHINode *PHI, BinaryOperator *StepInst)
79-
: PHI(PHI), StepInst(StepInst) {}
80-
};
81-
8270
// Can freeze instruction be pushed into operands of I?
8371
// In order to do this, I should not create a poison after I's flags are
8472
// stripped.
@@ -99,6 +87,46 @@ class CanonicalizeFreezeInLoopsImpl {
9987

10088
} // anonymous namespace
10189

90+
namespace llvm {
91+
92+
struct FrozenIndPHIInfo {
93+
// A freeze instruction that uses an induction phi
94+
FreezeInst *FI = nullptr;
95+
// The induction phi, step instruction, the operand idx of StepInst which is
96+
// a step value
97+
PHINode *PHI;
98+
BinaryOperator *StepInst;
99+
unsigned StepValIdx = 0;
100+
101+
FrozenIndPHIInfo(PHINode *PHI, BinaryOperator *StepInst)
102+
: PHI(PHI), StepInst(StepInst) {}
103+
104+
bool operator==(const FrozenIndPHIInfo &Other) { return FI == Other.FI; }
105+
};
106+
107+
template <> struct DenseMapInfo<FrozenIndPHIInfo> {
108+
static inline FrozenIndPHIInfo getEmptyKey() {
109+
return FrozenIndPHIInfo(DenseMapInfo<PHINode *>::getEmptyKey(),
110+
DenseMapInfo<BinaryOperator *>::getEmptyKey());
111+
}
112+
113+
static inline FrozenIndPHIInfo getTombstoneKey() {
114+
return FrozenIndPHIInfo(DenseMapInfo<PHINode *>::getTombstoneKey(),
115+
DenseMapInfo<BinaryOperator *>::getTombstoneKey());
116+
}
117+
118+
static unsigned getHashValue(const FrozenIndPHIInfo &Val) {
119+
return DenseMapInfo<FreezeInst *>::getHashValue(Val.FI);
120+
};
121+
122+
static bool isEqual(const FrozenIndPHIInfo &LHS,
123+
const FrozenIndPHIInfo &RHS) {
124+
return LHS.FI == RHS.FI;
125+
};
126+
};
127+
128+
} // end namespace llvm
129+
102130
// Given U = (value, user), replace value with freeze(value), and let
103131
// SCEV forget user. The inserted freeze is placed in the preheader.
104132
void CanonicalizeFreezeInLoopsImpl::InsertFreezeAndForgetFromSCEV(Use &U) {
@@ -126,7 +154,7 @@ bool CanonicalizeFreezeInLoopsImpl::run() {
126154
if (!L->isLoopSimplifyForm())
127155
return false;
128156

129-
SmallVector<FrozenIndPHIInfo, 4> Candidates;
157+
SmallSetVector<FrozenIndPHIInfo, 4> Candidates;
130158

131159
for (auto &PHI : L->getHeader()->phis()) {
132160
InductionDescriptor ID;
@@ -155,7 +183,7 @@ bool CanonicalizeFreezeInLoopsImpl::run() {
155183
if (auto *FI = dyn_cast<FreezeInst>(U)) {
156184
LLVM_DEBUG(dbgs() << "canonfr: found: " << *FI << "\n");
157185
Info.FI = FI;
158-
Candidates.push_back(Info);
186+
Candidates.insert(Info);
159187
}
160188
};
161189
for_each(PHI.users(), Visit);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2+
; RUN: opt < %s --passes=canon-freeze -S | FileCheck %s
3+
4+
define void @check_duplicate_removal(i32 %n) {
5+
; CHECK-LABEL: define void @check_duplicate_removal(
6+
; CHECK-SAME: i32 [[N:%.*]]) {
7+
; CHECK-NEXT: entry:
8+
; CHECK-NEXT: [[N_FROZEN:%.*]] = freeze i32 [[N]]
9+
; CHECK-NEXT: br label [[LOOP:%.*]]
10+
; CHECK: loop:
11+
; CHECK-NEXT: [[T1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[T3:%.*]], [[LOOP]] ]
12+
; CHECK-NEXT: [[T2:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[T3]], [[LOOP]] ]
13+
; CHECK-NEXT: [[T3]] = add i32 [[N_FROZEN]], [[T2]]
14+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[T2]], 0
15+
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
16+
; CHECK: exit:
17+
; CHECK-NEXT: ret void
18+
;
19+
entry:
20+
br label %loop
21+
22+
loop:
23+
%t1 = phi i32 [ 0, %entry], [%t3, %loop ]
24+
%t2 = phi i32 [ 0, %entry], [%t3, %loop ]
25+
%t3 = add i32 %n, %t2
26+
%.fr = freeze i32 %t3
27+
%cond = icmp eq i32 %t2, 0
28+
br i1 %cond, label %loop, label %exit
29+
30+
exit:
31+
ret void
32+
}

0 commit comments

Comments
 (0)