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