xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //==- CanonicalizeFreezeInLoops - Canonicalize freezes in a loop-*- C++ -*-===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // This pass canonicalizes freeze instructions in a loop by pushing them out to
105ffd83dbSDimitry Andric // the preheader.
115ffd83dbSDimitry Andric //
125ffd83dbSDimitry Andric //   loop:
135ffd83dbSDimitry Andric //     i = phi init, i.next
145ffd83dbSDimitry Andric //     i.next = add nsw i, 1
155ffd83dbSDimitry Andric //     i.next.fr = freeze i.next // push this out of this loop
165ffd83dbSDimitry Andric //     use(i.next.fr)
175ffd83dbSDimitry Andric //     br i1 (i.next <= N), loop, exit
185ffd83dbSDimitry Andric //   =>
195ffd83dbSDimitry Andric //     init.fr = freeze init
205ffd83dbSDimitry Andric //   loop:
215ffd83dbSDimitry Andric //     i = phi init.fr, i.next
225ffd83dbSDimitry Andric //     i.next = add i, 1         // nsw is dropped here
235ffd83dbSDimitry Andric //     use(i.next)
245ffd83dbSDimitry Andric //     br i1 (i.next <= N), loop, exit
255ffd83dbSDimitry Andric //
265ffd83dbSDimitry Andric // Removing freezes from these chains help scalar evolution successfully analyze
275ffd83dbSDimitry Andric // expressions.
285ffd83dbSDimitry Andric //
295ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
305ffd83dbSDimitry Andric 
315ffd83dbSDimitry Andric #include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h"
32647cbc5dSDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
335ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
34647cbc5dSDimitry Andric #include "llvm/ADT/SetVector.h"
355f757f3fSDimitry Andric #include "llvm/ADT/SmallSet.h"
365ffd83dbSDimitry Andric #include "llvm/Analysis/IVDescriptors.h"
375ffd83dbSDimitry Andric #include "llvm/Analysis/LoopAnalysisManager.h"
385ffd83dbSDimitry Andric #include "llvm/Analysis/LoopInfo.h"
395ffd83dbSDimitry Andric #include "llvm/Analysis/LoopPass.h"
405ffd83dbSDimitry Andric #include "llvm/Analysis/ScalarEvolution.h"
415ffd83dbSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
425ffd83dbSDimitry Andric #include "llvm/IR/Dominators.h"
435ffd83dbSDimitry Andric #include "llvm/InitializePasses.h"
445ffd83dbSDimitry Andric #include "llvm/Pass.h"
455ffd83dbSDimitry Andric #include "llvm/Support/Debug.h"
465ffd83dbSDimitry Andric #include "llvm/Transforms/Utils.h"
475ffd83dbSDimitry Andric 
485ffd83dbSDimitry Andric using namespace llvm;
495ffd83dbSDimitry Andric 
505ffd83dbSDimitry Andric #define DEBUG_TYPE "canon-freeze"
515ffd83dbSDimitry Andric 
525ffd83dbSDimitry Andric namespace {
535ffd83dbSDimitry Andric 
545ffd83dbSDimitry Andric class CanonicalizeFreezeInLoops : public LoopPass {
555ffd83dbSDimitry Andric public:
565ffd83dbSDimitry Andric   static char ID;
575ffd83dbSDimitry Andric 
585ffd83dbSDimitry Andric   CanonicalizeFreezeInLoops();
595ffd83dbSDimitry Andric 
605ffd83dbSDimitry Andric private:
615ffd83dbSDimitry Andric   bool runOnLoop(Loop *L, LPPassManager &LPM) override;
625ffd83dbSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
635ffd83dbSDimitry Andric };
645ffd83dbSDimitry Andric 
655ffd83dbSDimitry Andric class CanonicalizeFreezeInLoopsImpl {
665ffd83dbSDimitry Andric   Loop *L;
675ffd83dbSDimitry Andric   ScalarEvolution &SE;
685ffd83dbSDimitry Andric   DominatorTree &DT;
695ffd83dbSDimitry Andric 
705ffd83dbSDimitry Andric   // Can freeze instruction be pushed into operands of I?
715ffd83dbSDimitry Andric   // In order to do this, I should not create a poison after I's flags are
725ffd83dbSDimitry Andric   // stripped.
canHandleInst(const Instruction * I)735ffd83dbSDimitry Andric   bool canHandleInst(const Instruction *I) {
745ffd83dbSDimitry Andric     auto Opc = I->getOpcode();
755ffd83dbSDimitry Andric     // If add/sub/mul, drop nsw/nuw flags.
765ffd83dbSDimitry Andric     return Opc == Instruction::Add || Opc == Instruction::Sub ||
775ffd83dbSDimitry Andric            Opc == Instruction::Mul;
785ffd83dbSDimitry Andric   }
795ffd83dbSDimitry Andric 
805ffd83dbSDimitry Andric   void InsertFreezeAndForgetFromSCEV(Use &U);
815ffd83dbSDimitry Andric 
825ffd83dbSDimitry Andric public:
CanonicalizeFreezeInLoopsImpl(Loop * L,ScalarEvolution & SE,DominatorTree & DT)835ffd83dbSDimitry Andric   CanonicalizeFreezeInLoopsImpl(Loop *L, ScalarEvolution &SE, DominatorTree &DT)
845ffd83dbSDimitry Andric       : L(L), SE(SE), DT(DT) {}
855ffd83dbSDimitry Andric   bool run();
865ffd83dbSDimitry Andric };
875ffd83dbSDimitry Andric 
885ffd83dbSDimitry Andric } // anonymous namespace
895ffd83dbSDimitry Andric 
90647cbc5dSDimitry Andric namespace llvm {
91647cbc5dSDimitry Andric 
92647cbc5dSDimitry Andric struct FrozenIndPHIInfo {
93647cbc5dSDimitry Andric   // A freeze instruction that uses an induction phi
94647cbc5dSDimitry Andric   FreezeInst *FI = nullptr;
95647cbc5dSDimitry Andric   // The induction phi, step instruction, the operand idx of StepInst which is
96647cbc5dSDimitry Andric   // a step value
97647cbc5dSDimitry Andric   PHINode *PHI;
98647cbc5dSDimitry Andric   BinaryOperator *StepInst;
99647cbc5dSDimitry Andric   unsigned StepValIdx = 0;
100647cbc5dSDimitry Andric 
FrozenIndPHIInfollvm::FrozenIndPHIInfo101647cbc5dSDimitry Andric   FrozenIndPHIInfo(PHINode *PHI, BinaryOperator *StepInst)
102647cbc5dSDimitry Andric       : PHI(PHI), StepInst(StepInst) {}
103647cbc5dSDimitry Andric 
operator ==llvm::FrozenIndPHIInfo104647cbc5dSDimitry Andric   bool operator==(const FrozenIndPHIInfo &Other) { return FI == Other.FI; }
105647cbc5dSDimitry Andric };
106647cbc5dSDimitry Andric 
107647cbc5dSDimitry Andric template <> struct DenseMapInfo<FrozenIndPHIInfo> {
getEmptyKeyllvm::DenseMapInfo108647cbc5dSDimitry Andric   static inline FrozenIndPHIInfo getEmptyKey() {
109647cbc5dSDimitry Andric     return FrozenIndPHIInfo(DenseMapInfo<PHINode *>::getEmptyKey(),
110647cbc5dSDimitry Andric                             DenseMapInfo<BinaryOperator *>::getEmptyKey());
111647cbc5dSDimitry Andric   }
112647cbc5dSDimitry Andric 
getTombstoneKeyllvm::DenseMapInfo113647cbc5dSDimitry Andric   static inline FrozenIndPHIInfo getTombstoneKey() {
114647cbc5dSDimitry Andric     return FrozenIndPHIInfo(DenseMapInfo<PHINode *>::getTombstoneKey(),
115647cbc5dSDimitry Andric                             DenseMapInfo<BinaryOperator *>::getTombstoneKey());
116647cbc5dSDimitry Andric   }
117647cbc5dSDimitry Andric 
getHashValuellvm::DenseMapInfo118647cbc5dSDimitry Andric   static unsigned getHashValue(const FrozenIndPHIInfo &Val) {
119647cbc5dSDimitry Andric     return DenseMapInfo<FreezeInst *>::getHashValue(Val.FI);
120647cbc5dSDimitry Andric   };
121647cbc5dSDimitry Andric 
isEqualllvm::DenseMapInfo122647cbc5dSDimitry Andric   static bool isEqual(const FrozenIndPHIInfo &LHS,
123647cbc5dSDimitry Andric                       const FrozenIndPHIInfo &RHS) {
124647cbc5dSDimitry Andric     return LHS.FI == RHS.FI;
125647cbc5dSDimitry Andric   };
126647cbc5dSDimitry Andric };
127647cbc5dSDimitry Andric 
128647cbc5dSDimitry Andric } // end namespace llvm
129647cbc5dSDimitry Andric 
1305ffd83dbSDimitry Andric // Given U = (value, user), replace value with freeze(value), and let
1315ffd83dbSDimitry Andric // SCEV forget user. The inserted freeze is placed in the preheader.
InsertFreezeAndForgetFromSCEV(Use & U)1325ffd83dbSDimitry Andric void CanonicalizeFreezeInLoopsImpl::InsertFreezeAndForgetFromSCEV(Use &U) {
1335ffd83dbSDimitry Andric   auto *PH = L->getLoopPreheader();
1345ffd83dbSDimitry Andric 
1355ffd83dbSDimitry Andric   auto *UserI = cast<Instruction>(U.getUser());
1365ffd83dbSDimitry Andric   auto *ValueToFr = U.get();
1375ffd83dbSDimitry Andric   assert(L->contains(UserI->getParent()) &&
1385ffd83dbSDimitry Andric          "Should not process an instruction that isn't inside the loop");
139e8d8bef9SDimitry Andric   if (isGuaranteedNotToBeUndefOrPoison(ValueToFr, nullptr, UserI, &DT))
1405ffd83dbSDimitry Andric     return;
1415ffd83dbSDimitry Andric 
1425ffd83dbSDimitry Andric   LLVM_DEBUG(dbgs() << "canonfr: inserting freeze:\n");
1435ffd83dbSDimitry Andric   LLVM_DEBUG(dbgs() << "\tUser: " << *U.getUser() << "\n");
1445ffd83dbSDimitry Andric   LLVM_DEBUG(dbgs() << "\tOperand: " << *U.get() << "\n");
1455ffd83dbSDimitry Andric 
1465ffd83dbSDimitry Andric   U.set(new FreezeInst(ValueToFr, ValueToFr->getName() + ".frozen",
147*0fca6ea1SDimitry Andric                        PH->getTerminator()->getIterator()));
1485ffd83dbSDimitry Andric 
1495ffd83dbSDimitry Andric   SE.forgetValue(UserI);
1505ffd83dbSDimitry Andric }
1515ffd83dbSDimitry Andric 
run()1525ffd83dbSDimitry Andric bool CanonicalizeFreezeInLoopsImpl::run() {
1535ffd83dbSDimitry Andric   // The loop should be in LoopSimplify form.
1545ffd83dbSDimitry Andric   if (!L->isLoopSimplifyForm())
1555ffd83dbSDimitry Andric     return false;
1565ffd83dbSDimitry Andric 
157647cbc5dSDimitry Andric   SmallSetVector<FrozenIndPHIInfo, 4> Candidates;
1585ffd83dbSDimitry Andric 
1595ffd83dbSDimitry Andric   for (auto &PHI : L->getHeader()->phis()) {
1605ffd83dbSDimitry Andric     InductionDescriptor ID;
1615ffd83dbSDimitry Andric     if (!InductionDescriptor::isInductionPHI(&PHI, L, &SE, ID))
1625ffd83dbSDimitry Andric       continue;
1635ffd83dbSDimitry Andric 
1645ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "canonfr: PHI: " << PHI << "\n");
1655ffd83dbSDimitry Andric     FrozenIndPHIInfo Info(&PHI, ID.getInductionBinOp());
1665ffd83dbSDimitry Andric     if (!Info.StepInst || !canHandleInst(Info.StepInst)) {
1675ffd83dbSDimitry Andric       // The stepping instruction has unknown form.
1685ffd83dbSDimitry Andric       // Ignore this PHI.
1695ffd83dbSDimitry Andric       continue;
1705ffd83dbSDimitry Andric     }
1715ffd83dbSDimitry Andric 
1725ffd83dbSDimitry Andric     Info.StepValIdx = Info.StepInst->getOperand(0) == &PHI;
1735ffd83dbSDimitry Andric     Value *StepV = Info.StepInst->getOperand(Info.StepValIdx);
1745ffd83dbSDimitry Andric     if (auto *StepI = dyn_cast<Instruction>(StepV)) {
1755ffd83dbSDimitry Andric       if (L->contains(StepI->getParent())) {
1765ffd83dbSDimitry Andric         // The step value is inside the loop. Freezing step value will introduce
1775ffd83dbSDimitry Andric         // another freeze into the loop, so skip this PHI.
1785ffd83dbSDimitry Andric         continue;
1795ffd83dbSDimitry Andric       }
1805ffd83dbSDimitry Andric     }
1815ffd83dbSDimitry Andric 
1825ffd83dbSDimitry Andric     auto Visit = [&](User *U) {
1835ffd83dbSDimitry Andric       if (auto *FI = dyn_cast<FreezeInst>(U)) {
1845ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "canonfr: found: " << *FI << "\n");
1855ffd83dbSDimitry Andric         Info.FI = FI;
186647cbc5dSDimitry Andric         Candidates.insert(Info);
1875ffd83dbSDimitry Andric       }
1885ffd83dbSDimitry Andric     };
1895ffd83dbSDimitry Andric     for_each(PHI.users(), Visit);
1905ffd83dbSDimitry Andric     for_each(Info.StepInst->users(), Visit);
1915ffd83dbSDimitry Andric   }
1925ffd83dbSDimitry Andric 
1935ffd83dbSDimitry Andric   if (Candidates.empty())
1945ffd83dbSDimitry Andric     return false;
1955ffd83dbSDimitry Andric 
1965ffd83dbSDimitry Andric   SmallSet<PHINode *, 8> ProcessedPHIs;
1975ffd83dbSDimitry Andric   for (const auto &Info : Candidates) {
1985ffd83dbSDimitry Andric     PHINode *PHI = Info.PHI;
1995ffd83dbSDimitry Andric     if (!ProcessedPHIs.insert(Info.PHI).second)
2005ffd83dbSDimitry Andric       continue;
2015ffd83dbSDimitry Andric 
2025ffd83dbSDimitry Andric     BinaryOperator *StepI = Info.StepInst;
2035ffd83dbSDimitry Andric     assert(StepI && "Step instruction should have been found");
2045ffd83dbSDimitry Andric 
2055ffd83dbSDimitry Andric     // Drop flags from the step instruction.
206e8d8bef9SDimitry Andric     if (!isGuaranteedNotToBeUndefOrPoison(StepI, nullptr, StepI, &DT)) {
2075ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "canonfr: drop flags: " << *StepI << "\n");
2085ffd83dbSDimitry Andric       StepI->dropPoisonGeneratingFlags();
2095ffd83dbSDimitry Andric       SE.forgetValue(StepI);
2105ffd83dbSDimitry Andric     }
2115ffd83dbSDimitry Andric 
2125ffd83dbSDimitry Andric     InsertFreezeAndForgetFromSCEV(StepI->getOperandUse(Info.StepValIdx));
2135ffd83dbSDimitry Andric 
2145ffd83dbSDimitry Andric     unsigned OperandIdx =
2155ffd83dbSDimitry Andric         PHI->getOperandNumForIncomingValue(PHI->getIncomingValue(0) == StepI);
2165ffd83dbSDimitry Andric     InsertFreezeAndForgetFromSCEV(PHI->getOperandUse(OperandIdx));
2175ffd83dbSDimitry Andric   }
2185ffd83dbSDimitry Andric 
2195ffd83dbSDimitry Andric   // Finally, remove the old freeze instructions.
2205ffd83dbSDimitry Andric   for (const auto &Item : Candidates) {
2215ffd83dbSDimitry Andric     auto *FI = Item.FI;
2225ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "canonfr: removing " << *FI << "\n");
2235ffd83dbSDimitry Andric     SE.forgetValue(FI);
2245ffd83dbSDimitry Andric     FI->replaceAllUsesWith(FI->getOperand(0));
2255ffd83dbSDimitry Andric     FI->eraseFromParent();
2265ffd83dbSDimitry Andric   }
2275ffd83dbSDimitry Andric 
2285ffd83dbSDimitry Andric   return true;
2295ffd83dbSDimitry Andric }
2305ffd83dbSDimitry Andric 
CanonicalizeFreezeInLoops()2315ffd83dbSDimitry Andric CanonicalizeFreezeInLoops::CanonicalizeFreezeInLoops() : LoopPass(ID) {
2325ffd83dbSDimitry Andric   initializeCanonicalizeFreezeInLoopsPass(*PassRegistry::getPassRegistry());
2335ffd83dbSDimitry Andric }
2345ffd83dbSDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const2355ffd83dbSDimitry Andric void CanonicalizeFreezeInLoops::getAnalysisUsage(AnalysisUsage &AU) const {
2365ffd83dbSDimitry Andric   AU.addPreservedID(LoopSimplifyID);
2375ffd83dbSDimitry Andric   AU.addRequired<LoopInfoWrapperPass>();
2385ffd83dbSDimitry Andric   AU.addPreserved<LoopInfoWrapperPass>();
2395ffd83dbSDimitry Andric   AU.addRequiredID(LoopSimplifyID);
2405ffd83dbSDimitry Andric   AU.addRequired<ScalarEvolutionWrapperPass>();
2415ffd83dbSDimitry Andric   AU.addPreserved<ScalarEvolutionWrapperPass>();
2425ffd83dbSDimitry Andric   AU.addRequired<DominatorTreeWrapperPass>();
2435ffd83dbSDimitry Andric   AU.addPreserved<DominatorTreeWrapperPass>();
2445ffd83dbSDimitry Andric }
2455ffd83dbSDimitry Andric 
runOnLoop(Loop * L,LPPassManager &)2465ffd83dbSDimitry Andric bool CanonicalizeFreezeInLoops::runOnLoop(Loop *L, LPPassManager &) {
2475ffd83dbSDimitry Andric   if (skipLoop(L))
2485ffd83dbSDimitry Andric     return false;
2495ffd83dbSDimitry Andric 
2505ffd83dbSDimitry Andric   auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
2515ffd83dbSDimitry Andric   auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
2525ffd83dbSDimitry Andric   return CanonicalizeFreezeInLoopsImpl(L, SE, DT).run();
2535ffd83dbSDimitry Andric }
2545ffd83dbSDimitry Andric 
2555ffd83dbSDimitry Andric PreservedAnalyses
run(Loop & L,LoopAnalysisManager & AM,LoopStandardAnalysisResults & AR,LPMUpdater & U)2565ffd83dbSDimitry Andric CanonicalizeFreezeInLoopsPass::run(Loop &L, LoopAnalysisManager &AM,
2575ffd83dbSDimitry Andric                                    LoopStandardAnalysisResults &AR,
2585ffd83dbSDimitry Andric                                    LPMUpdater &U) {
2595ffd83dbSDimitry Andric   if (!CanonicalizeFreezeInLoopsImpl(&L, AR.SE, AR.DT).run())
2605ffd83dbSDimitry Andric     return PreservedAnalyses::all();
2615ffd83dbSDimitry Andric 
2625ffd83dbSDimitry Andric   return getLoopPassPreservedAnalyses();
2635ffd83dbSDimitry Andric }
2645ffd83dbSDimitry Andric 
2655ffd83dbSDimitry Andric INITIALIZE_PASS_BEGIN(CanonicalizeFreezeInLoops, "canon-freeze",
2665ffd83dbSDimitry Andric                       "Canonicalize Freeze Instructions in Loops", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)2675ffd83dbSDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
2685ffd83dbSDimitry Andric INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
2695ffd83dbSDimitry Andric INITIALIZE_PASS_DEPENDENCY(LoopSimplify)
2705ffd83dbSDimitry Andric INITIALIZE_PASS_END(CanonicalizeFreezeInLoops, "canon-freeze",
2715ffd83dbSDimitry Andric                     "Canonicalize Freeze Instructions in Loops", false, false)
2725ffd83dbSDimitry Andric 
2735ffd83dbSDimitry Andric Pass *llvm::createCanonicalizeFreezeInLoopsPass() {
2745ffd83dbSDimitry Andric   return new CanonicalizeFreezeInLoops();
2755ffd83dbSDimitry Andric }
2765ffd83dbSDimitry Andric 
2775ffd83dbSDimitry Andric char CanonicalizeFreezeInLoops::ID = 0;
278