xref: /llvm-project/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp (revision 6b62a9135a28bd001263e5a9db08d4cff1123126)
1d9a4a244SJuneyoung Lee //==- CanonicalizeFreezeInLoops - Canonicalize freezes in a loop-*- C++ -*-===//
2d9a4a244SJuneyoung Lee //
3d9a4a244SJuneyoung Lee // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d9a4a244SJuneyoung Lee // See https://llvm.org/LICENSE.txt for license information.
5d9a4a244SJuneyoung Lee // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d9a4a244SJuneyoung Lee //
7d9a4a244SJuneyoung Lee //===----------------------------------------------------------------------===//
8d9a4a244SJuneyoung Lee //
9d9a4a244SJuneyoung Lee // This pass canonicalizes freeze instructions in a loop by pushing them out to
10d9a4a244SJuneyoung Lee // the preheader.
11d9a4a244SJuneyoung Lee //
12d9a4a244SJuneyoung Lee //   loop:
13d9a4a244SJuneyoung Lee //     i = phi init, i.next
14d9a4a244SJuneyoung Lee //     i.next = add nsw i, 1
15d9a4a244SJuneyoung Lee //     i.next.fr = freeze i.next // push this out of this loop
16d9a4a244SJuneyoung Lee //     use(i.next.fr)
17d9a4a244SJuneyoung Lee //     br i1 (i.next <= N), loop, exit
18d9a4a244SJuneyoung Lee //   =>
19d9a4a244SJuneyoung Lee //     init.fr = freeze init
20d9a4a244SJuneyoung Lee //   loop:
21d9a4a244SJuneyoung Lee //     i = phi init.fr, i.next
22d9a4a244SJuneyoung Lee //     i.next = add i, 1         // nsw is dropped here
23d9a4a244SJuneyoung Lee //     use(i.next)
24d9a4a244SJuneyoung Lee //     br i1 (i.next <= N), loop, exit
25d9a4a244SJuneyoung Lee //
26d9a4a244SJuneyoung Lee // Removing freezes from these chains help scalar evolution successfully analyze
27d9a4a244SJuneyoung Lee // expressions.
28d9a4a244SJuneyoung Lee //
29d9a4a244SJuneyoung Lee //===----------------------------------------------------------------------===//
30d9a4a244SJuneyoung Lee 
31d9a4a244SJuneyoung Lee #include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h"
32a700298bSWei Tao #include "llvm/ADT/DenseMapInfo.h"
33d9a4a244SJuneyoung Lee #include "llvm/ADT/STLExtras.h"
34a700298bSWei Tao #include "llvm/ADT/SetVector.h"
3522b0f7baSKazu Hirata #include "llvm/ADT/SmallSet.h"
365b0d1f04SBenjamin Kramer #include "llvm/Analysis/IVDescriptors.h"
37d9a4a244SJuneyoung Lee #include "llvm/Analysis/LoopAnalysisManager.h"
38d9a4a244SJuneyoung Lee #include "llvm/Analysis/LoopInfo.h"
39d9a4a244SJuneyoung Lee #include "llvm/Analysis/LoopPass.h"
405006e551SSimon Pilgrim #include "llvm/Analysis/ScalarEvolution.h"
41d9a4a244SJuneyoung Lee #include "llvm/Analysis/ValueTracking.h"
425006e551SSimon Pilgrim #include "llvm/IR/Dominators.h"
43d9a4a244SJuneyoung Lee #include "llvm/InitializePasses.h"
44d9a4a244SJuneyoung Lee #include "llvm/Pass.h"
45d9a4a244SJuneyoung Lee #include "llvm/Support/Debug.h"
46d9a4a244SJuneyoung Lee #include "llvm/Transforms/Utils.h"
47d9a4a244SJuneyoung Lee 
48d9a4a244SJuneyoung Lee using namespace llvm;
49d9a4a244SJuneyoung Lee 
50d9a4a244SJuneyoung Lee #define DEBUG_TYPE "canon-freeze"
51d9a4a244SJuneyoung Lee 
52d9a4a244SJuneyoung Lee namespace {
53d9a4a244SJuneyoung Lee 
54d9a4a244SJuneyoung Lee class CanonicalizeFreezeInLoops : public LoopPass {
55d9a4a244SJuneyoung Lee public:
56d9a4a244SJuneyoung Lee   static char ID;
57d9a4a244SJuneyoung Lee 
58d9a4a244SJuneyoung Lee   CanonicalizeFreezeInLoops();
59d9a4a244SJuneyoung Lee 
60d9a4a244SJuneyoung Lee private:
61d9a4a244SJuneyoung Lee   bool runOnLoop(Loop *L, LPPassManager &LPM) override;
62d9a4a244SJuneyoung Lee   void getAnalysisUsage(AnalysisUsage &AU) const override;
63d9a4a244SJuneyoung Lee };
64d9a4a244SJuneyoung Lee 
65d9a4a244SJuneyoung Lee class CanonicalizeFreezeInLoopsImpl {
66d9a4a244SJuneyoung Lee   Loop *L;
67d9a4a244SJuneyoung Lee   ScalarEvolution &SE;
68d9a4a244SJuneyoung Lee   DominatorTree &DT;
69d9a4a244SJuneyoung Lee 
70d9a4a244SJuneyoung Lee   // Can freeze instruction be pushed into operands of I?
71d9a4a244SJuneyoung Lee   // In order to do this, I should not create a poison after I's flags are
72d9a4a244SJuneyoung Lee   // stripped.
canHandleInst(const Instruction * I)73d9a4a244SJuneyoung Lee   bool canHandleInst(const Instruction *I) {
74d9a4a244SJuneyoung Lee     auto Opc = I->getOpcode();
75d9a4a244SJuneyoung Lee     // If add/sub/mul, drop nsw/nuw flags.
76d9a4a244SJuneyoung Lee     return Opc == Instruction::Add || Opc == Instruction::Sub ||
77d9a4a244SJuneyoung Lee            Opc == Instruction::Mul;
78d9a4a244SJuneyoung Lee   }
79d9a4a244SJuneyoung Lee 
80d9a4a244SJuneyoung Lee   void InsertFreezeAndForgetFromSCEV(Use &U);
81d9a4a244SJuneyoung Lee 
82d9a4a244SJuneyoung Lee public:
CanonicalizeFreezeInLoopsImpl(Loop * L,ScalarEvolution & SE,DominatorTree & DT)83d9a4a244SJuneyoung Lee   CanonicalizeFreezeInLoopsImpl(Loop *L, ScalarEvolution &SE, DominatorTree &DT)
84d9a4a244SJuneyoung Lee       : L(L), SE(SE), DT(DT) {}
85d9a4a244SJuneyoung Lee   bool run();
86d9a4a244SJuneyoung Lee };
87d9a4a244SJuneyoung Lee 
88d9a4a244SJuneyoung Lee } // anonymous namespace
89d9a4a244SJuneyoung Lee 
90a700298bSWei Tao namespace llvm {
91a700298bSWei Tao 
92a700298bSWei Tao struct FrozenIndPHIInfo {
93a700298bSWei Tao   // A freeze instruction that uses an induction phi
94a700298bSWei Tao   FreezeInst *FI = nullptr;
95a700298bSWei Tao   // The induction phi, step instruction, the operand idx of StepInst which is
96a700298bSWei Tao   // a step value
97a700298bSWei Tao   PHINode *PHI;
98a700298bSWei Tao   BinaryOperator *StepInst;
99a700298bSWei Tao   unsigned StepValIdx = 0;
100a700298bSWei Tao 
FrozenIndPHIInfollvm::FrozenIndPHIInfo101a700298bSWei Tao   FrozenIndPHIInfo(PHINode *PHI, BinaryOperator *StepInst)
102a700298bSWei Tao       : PHI(PHI), StepInst(StepInst) {}
103a700298bSWei Tao 
operator ==llvm::FrozenIndPHIInfo104a700298bSWei Tao   bool operator==(const FrozenIndPHIInfo &Other) { return FI == Other.FI; }
105a700298bSWei Tao };
106a700298bSWei Tao 
107a700298bSWei Tao template <> struct DenseMapInfo<FrozenIndPHIInfo> {
getEmptyKeyllvm::DenseMapInfo108a700298bSWei Tao   static inline FrozenIndPHIInfo getEmptyKey() {
109a700298bSWei Tao     return FrozenIndPHIInfo(DenseMapInfo<PHINode *>::getEmptyKey(),
110a700298bSWei Tao                             DenseMapInfo<BinaryOperator *>::getEmptyKey());
111a700298bSWei Tao   }
112a700298bSWei Tao 
getTombstoneKeyllvm::DenseMapInfo113a700298bSWei Tao   static inline FrozenIndPHIInfo getTombstoneKey() {
114a700298bSWei Tao     return FrozenIndPHIInfo(DenseMapInfo<PHINode *>::getTombstoneKey(),
115a700298bSWei Tao                             DenseMapInfo<BinaryOperator *>::getTombstoneKey());
116a700298bSWei Tao   }
117a700298bSWei Tao 
getHashValuellvm::DenseMapInfo118a700298bSWei Tao   static unsigned getHashValue(const FrozenIndPHIInfo &Val) {
119a700298bSWei Tao     return DenseMapInfo<FreezeInst *>::getHashValue(Val.FI);
120a700298bSWei Tao   };
121a700298bSWei Tao 
isEqualllvm::DenseMapInfo122a700298bSWei Tao   static bool isEqual(const FrozenIndPHIInfo &LHS,
123a700298bSWei Tao                       const FrozenIndPHIInfo &RHS) {
124a700298bSWei Tao     return LHS.FI == RHS.FI;
125a700298bSWei Tao   };
126a700298bSWei Tao };
127a700298bSWei Tao 
128a700298bSWei Tao } // end namespace llvm
129a700298bSWei Tao 
130d9a4a244SJuneyoung Lee // Given U = (value, user), replace value with freeze(value), and let
131d9a4a244SJuneyoung Lee // SCEV forget user. The inserted freeze is placed in the preheader.
InsertFreezeAndForgetFromSCEV(Use & U)132d9a4a244SJuneyoung Lee void CanonicalizeFreezeInLoopsImpl::InsertFreezeAndForgetFromSCEV(Use &U) {
133d9a4a244SJuneyoung Lee   auto *PH = L->getLoopPreheader();
134d9a4a244SJuneyoung Lee 
135d9a4a244SJuneyoung Lee   auto *UserI = cast<Instruction>(U.getUser());
136d9a4a244SJuneyoung Lee   auto *ValueToFr = U.get();
137d9a4a244SJuneyoung Lee   assert(L->contains(UserI->getParent()) &&
138d9a4a244SJuneyoung Lee          "Should not process an instruction that isn't inside the loop");
1399b3c2a72SJuneyoung Lee   if (isGuaranteedNotToBeUndefOrPoison(ValueToFr, nullptr, UserI, &DT))
140d9a4a244SJuneyoung Lee     return;
141d9a4a244SJuneyoung Lee 
142d9a4a244SJuneyoung Lee   LLVM_DEBUG(dbgs() << "canonfr: inserting freeze:\n");
143d9a4a244SJuneyoung Lee   LLVM_DEBUG(dbgs() << "\tUser: " << *U.getUser() << "\n");
144d9a4a244SJuneyoung Lee   LLVM_DEBUG(dbgs() << "\tOperand: " << *U.get() << "\n");
145d9a4a244SJuneyoung Lee 
146d9a4a244SJuneyoung Lee   U.set(new FreezeInst(ValueToFr, ValueToFr->getName() + ".frozen",
147*6b62a913SJeremy Morse                        PH->getTerminator()->getIterator()));
148d9a4a244SJuneyoung Lee 
149d9a4a244SJuneyoung Lee   SE.forgetValue(UserI);
150d9a4a244SJuneyoung Lee }
151d9a4a244SJuneyoung Lee 
run()152d9a4a244SJuneyoung Lee bool CanonicalizeFreezeInLoopsImpl::run() {
153d9a4a244SJuneyoung Lee   // The loop should be in LoopSimplify form.
154d9a4a244SJuneyoung Lee   if (!L->isLoopSimplifyForm())
155d9a4a244SJuneyoung Lee     return false;
156d9a4a244SJuneyoung Lee 
157a700298bSWei Tao   SmallSetVector<FrozenIndPHIInfo, 4> Candidates;
158d9a4a244SJuneyoung Lee 
159d9a4a244SJuneyoung Lee   for (auto &PHI : L->getHeader()->phis()) {
160d9a4a244SJuneyoung Lee     InductionDescriptor ID;
161d9a4a244SJuneyoung Lee     if (!InductionDescriptor::isInductionPHI(&PHI, L, &SE, ID))
162d9a4a244SJuneyoung Lee       continue;
163d9a4a244SJuneyoung Lee 
164d9a4a244SJuneyoung Lee     LLVM_DEBUG(dbgs() << "canonfr: PHI: " << PHI << "\n");
165d9a4a244SJuneyoung Lee     FrozenIndPHIInfo Info(&PHI, ID.getInductionBinOp());
166d9a4a244SJuneyoung Lee     if (!Info.StepInst || !canHandleInst(Info.StepInst)) {
167d9a4a244SJuneyoung Lee       // The stepping instruction has unknown form.
168d9a4a244SJuneyoung Lee       // Ignore this PHI.
169d9a4a244SJuneyoung Lee       continue;
170d9a4a244SJuneyoung Lee     }
171d9a4a244SJuneyoung Lee 
172d9a4a244SJuneyoung Lee     Info.StepValIdx = Info.StepInst->getOperand(0) == &PHI;
173d9a4a244SJuneyoung Lee     Value *StepV = Info.StepInst->getOperand(Info.StepValIdx);
174d9a4a244SJuneyoung Lee     if (auto *StepI = dyn_cast<Instruction>(StepV)) {
175d9a4a244SJuneyoung Lee       if (L->contains(StepI->getParent())) {
176d9a4a244SJuneyoung Lee         // The step value is inside the loop. Freezing step value will introduce
177d9a4a244SJuneyoung Lee         // another freeze into the loop, so skip this PHI.
178d9a4a244SJuneyoung Lee         continue;
179d9a4a244SJuneyoung Lee       }
180d9a4a244SJuneyoung Lee     }
181d9a4a244SJuneyoung Lee 
182d9a4a244SJuneyoung Lee     auto Visit = [&](User *U) {
183d9a4a244SJuneyoung Lee       if (auto *FI = dyn_cast<FreezeInst>(U)) {
184d9a4a244SJuneyoung Lee         LLVM_DEBUG(dbgs() << "canonfr: found: " << *FI << "\n");
185d9a4a244SJuneyoung Lee         Info.FI = FI;
186a700298bSWei Tao         Candidates.insert(Info);
187d9a4a244SJuneyoung Lee       }
188d9a4a244SJuneyoung Lee     };
189d9a4a244SJuneyoung Lee     for_each(PHI.users(), Visit);
190d9a4a244SJuneyoung Lee     for_each(Info.StepInst->users(), Visit);
191d9a4a244SJuneyoung Lee   }
192d9a4a244SJuneyoung Lee 
193d9a4a244SJuneyoung Lee   if (Candidates.empty())
194d9a4a244SJuneyoung Lee     return false;
195d9a4a244SJuneyoung Lee 
196d9a4a244SJuneyoung Lee   SmallSet<PHINode *, 8> ProcessedPHIs;
197d9a4a244SJuneyoung Lee   for (const auto &Info : Candidates) {
198d9a4a244SJuneyoung Lee     PHINode *PHI = Info.PHI;
199d9a4a244SJuneyoung Lee     if (!ProcessedPHIs.insert(Info.PHI).second)
200d9a4a244SJuneyoung Lee       continue;
201d9a4a244SJuneyoung Lee 
202d9a4a244SJuneyoung Lee     BinaryOperator *StepI = Info.StepInst;
203d9a4a244SJuneyoung Lee     assert(StepI && "Step instruction should have been found");
204d9a4a244SJuneyoung Lee 
205d9a4a244SJuneyoung Lee     // Drop flags from the step instruction.
2069b3c2a72SJuneyoung Lee     if (!isGuaranteedNotToBeUndefOrPoison(StepI, nullptr, StepI, &DT)) {
207d9a4a244SJuneyoung Lee       LLVM_DEBUG(dbgs() << "canonfr: drop flags: " << *StepI << "\n");
208d9a4a244SJuneyoung Lee       StepI->dropPoisonGeneratingFlags();
209d9a4a244SJuneyoung Lee       SE.forgetValue(StepI);
210d9a4a244SJuneyoung Lee     }
211d9a4a244SJuneyoung Lee 
212d9a4a244SJuneyoung Lee     InsertFreezeAndForgetFromSCEV(StepI->getOperandUse(Info.StepValIdx));
213d9a4a244SJuneyoung Lee 
214d9a4a244SJuneyoung Lee     unsigned OperandIdx =
215d9a4a244SJuneyoung Lee         PHI->getOperandNumForIncomingValue(PHI->getIncomingValue(0) == StepI);
216d9a4a244SJuneyoung Lee     InsertFreezeAndForgetFromSCEV(PHI->getOperandUse(OperandIdx));
217d9a4a244SJuneyoung Lee   }
218d9a4a244SJuneyoung Lee 
219d9a4a244SJuneyoung Lee   // Finally, remove the old freeze instructions.
220d9a4a244SJuneyoung Lee   for (const auto &Item : Candidates) {
221d9a4a244SJuneyoung Lee     auto *FI = Item.FI;
222d9a4a244SJuneyoung Lee     LLVM_DEBUG(dbgs() << "canonfr: removing " << *FI << "\n");
223d9a4a244SJuneyoung Lee     SE.forgetValue(FI);
224d9a4a244SJuneyoung Lee     FI->replaceAllUsesWith(FI->getOperand(0));
225d9a4a244SJuneyoung Lee     FI->eraseFromParent();
226d9a4a244SJuneyoung Lee   }
227d9a4a244SJuneyoung Lee 
228d9a4a244SJuneyoung Lee   return true;
229d9a4a244SJuneyoung Lee }
230d9a4a244SJuneyoung Lee 
CanonicalizeFreezeInLoops()231d9a4a244SJuneyoung Lee CanonicalizeFreezeInLoops::CanonicalizeFreezeInLoops() : LoopPass(ID) {
232d9a4a244SJuneyoung Lee   initializeCanonicalizeFreezeInLoopsPass(*PassRegistry::getPassRegistry());
233d9a4a244SJuneyoung Lee }
234d9a4a244SJuneyoung Lee 
getAnalysisUsage(AnalysisUsage & AU) const235d9a4a244SJuneyoung Lee void CanonicalizeFreezeInLoops::getAnalysisUsage(AnalysisUsage &AU) const {
236d9a4a244SJuneyoung Lee   AU.addPreservedID(LoopSimplifyID);
237d9a4a244SJuneyoung Lee   AU.addRequired<LoopInfoWrapperPass>();
238d9a4a244SJuneyoung Lee   AU.addPreserved<LoopInfoWrapperPass>();
239d9a4a244SJuneyoung Lee   AU.addRequiredID(LoopSimplifyID);
240d9a4a244SJuneyoung Lee   AU.addRequired<ScalarEvolutionWrapperPass>();
241d9a4a244SJuneyoung Lee   AU.addPreserved<ScalarEvolutionWrapperPass>();
242d9a4a244SJuneyoung Lee   AU.addRequired<DominatorTreeWrapperPass>();
243d9a4a244SJuneyoung Lee   AU.addPreserved<DominatorTreeWrapperPass>();
244d9a4a244SJuneyoung Lee }
245d9a4a244SJuneyoung Lee 
runOnLoop(Loop * L,LPPassManager &)246d9a4a244SJuneyoung Lee bool CanonicalizeFreezeInLoops::runOnLoop(Loop *L, LPPassManager &) {
247d9a4a244SJuneyoung Lee   if (skipLoop(L))
248d9a4a244SJuneyoung Lee     return false;
249d9a4a244SJuneyoung Lee 
250d9a4a244SJuneyoung Lee   auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
251d9a4a244SJuneyoung Lee   auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
252d9a4a244SJuneyoung Lee   return CanonicalizeFreezeInLoopsImpl(L, SE, DT).run();
253d9a4a244SJuneyoung Lee }
254d9a4a244SJuneyoung Lee 
255d9a4a244SJuneyoung Lee PreservedAnalyses
run(Loop & L,LoopAnalysisManager & AM,LoopStandardAnalysisResults & AR,LPMUpdater & U)256d9a4a244SJuneyoung Lee CanonicalizeFreezeInLoopsPass::run(Loop &L, LoopAnalysisManager &AM,
257d9a4a244SJuneyoung Lee                                    LoopStandardAnalysisResults &AR,
258d9a4a244SJuneyoung Lee                                    LPMUpdater &U) {
259d9a4a244SJuneyoung Lee   if (!CanonicalizeFreezeInLoopsImpl(&L, AR.SE, AR.DT).run())
260d9a4a244SJuneyoung Lee     return PreservedAnalyses::all();
261d9a4a244SJuneyoung Lee 
262d9a4a244SJuneyoung Lee   return getLoopPassPreservedAnalyses();
263d9a4a244SJuneyoung Lee }
264d9a4a244SJuneyoung Lee 
265d9a4a244SJuneyoung Lee INITIALIZE_PASS_BEGIN(CanonicalizeFreezeInLoops, "canon-freeze",
266d9a4a244SJuneyoung Lee                       "Canonicalize Freeze Instructions in Loops", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)267d9a4a244SJuneyoung Lee INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
268d9a4a244SJuneyoung Lee INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
269d9a4a244SJuneyoung Lee INITIALIZE_PASS_DEPENDENCY(LoopSimplify)
270d9a4a244SJuneyoung Lee INITIALIZE_PASS_END(CanonicalizeFreezeInLoops, "canon-freeze",
271d9a4a244SJuneyoung Lee                     "Canonicalize Freeze Instructions in Loops", false, false)
272d9a4a244SJuneyoung Lee 
273d9a4a244SJuneyoung Lee Pass *llvm::createCanonicalizeFreezeInLoopsPass() {
274d9a4a244SJuneyoung Lee   return new CanonicalizeFreezeInLoops();
275d9a4a244SJuneyoung Lee }
276d9a4a244SJuneyoung Lee 
277d9a4a244SJuneyoung Lee char CanonicalizeFreezeInLoops::ID = 0;
278