xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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"
325ffd83dbSDimitry Andric #include "llvm/ADT/DenseMap.h"
335ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
345ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h"
355ffd83dbSDimitry Andric #include "llvm/Analysis/IVDescriptors.h"
365ffd83dbSDimitry Andric #include "llvm/Analysis/IVUsers.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   struct FrozenIndPHIInfo {
715ffd83dbSDimitry Andric     // A freeze instruction that uses an induction phi
725ffd83dbSDimitry Andric     FreezeInst *FI = nullptr;
735ffd83dbSDimitry Andric     // The induction phi, step instruction, the operand idx of StepInst which is
745ffd83dbSDimitry Andric     // a step value
755ffd83dbSDimitry Andric     PHINode *PHI;
765ffd83dbSDimitry Andric     BinaryOperator *StepInst;
775ffd83dbSDimitry Andric     unsigned StepValIdx = 0;
785ffd83dbSDimitry Andric 
795ffd83dbSDimitry Andric     FrozenIndPHIInfo(PHINode *PHI, BinaryOperator *StepInst)
805ffd83dbSDimitry Andric         : PHI(PHI), StepInst(StepInst) {}
815ffd83dbSDimitry Andric   };
825ffd83dbSDimitry Andric 
835ffd83dbSDimitry Andric   // Can freeze instruction be pushed into operands of I?
845ffd83dbSDimitry Andric   // In order to do this, I should not create a poison after I's flags are
855ffd83dbSDimitry Andric   // stripped.
865ffd83dbSDimitry Andric   bool canHandleInst(const Instruction *I) {
875ffd83dbSDimitry Andric     auto Opc = I->getOpcode();
885ffd83dbSDimitry Andric     // If add/sub/mul, drop nsw/nuw flags.
895ffd83dbSDimitry Andric     return Opc == Instruction::Add || Opc == Instruction::Sub ||
905ffd83dbSDimitry Andric            Opc == Instruction::Mul;
915ffd83dbSDimitry Andric   }
925ffd83dbSDimitry Andric 
935ffd83dbSDimitry Andric   void InsertFreezeAndForgetFromSCEV(Use &U);
945ffd83dbSDimitry Andric 
955ffd83dbSDimitry Andric public:
965ffd83dbSDimitry Andric   CanonicalizeFreezeInLoopsImpl(Loop *L, ScalarEvolution &SE, DominatorTree &DT)
975ffd83dbSDimitry Andric       : L(L), SE(SE), DT(DT) {}
985ffd83dbSDimitry Andric   bool run();
995ffd83dbSDimitry Andric };
1005ffd83dbSDimitry Andric 
1015ffd83dbSDimitry Andric } // anonymous namespace
1025ffd83dbSDimitry Andric 
1035ffd83dbSDimitry Andric // Given U = (value, user), replace value with freeze(value), and let
1045ffd83dbSDimitry Andric // SCEV forget user. The inserted freeze is placed in the preheader.
1055ffd83dbSDimitry Andric void CanonicalizeFreezeInLoopsImpl::InsertFreezeAndForgetFromSCEV(Use &U) {
1065ffd83dbSDimitry Andric   auto *PH = L->getLoopPreheader();
1075ffd83dbSDimitry Andric 
1085ffd83dbSDimitry Andric   auto *UserI = cast<Instruction>(U.getUser());
1095ffd83dbSDimitry Andric   auto *ValueToFr = U.get();
1105ffd83dbSDimitry Andric   assert(L->contains(UserI->getParent()) &&
1115ffd83dbSDimitry Andric          "Should not process an instruction that isn't inside the loop");
112*e8d8bef9SDimitry Andric   if (isGuaranteedNotToBeUndefOrPoison(ValueToFr, nullptr, UserI, &DT))
1135ffd83dbSDimitry Andric     return;
1145ffd83dbSDimitry Andric 
1155ffd83dbSDimitry Andric   LLVM_DEBUG(dbgs() << "canonfr: inserting freeze:\n");
1165ffd83dbSDimitry Andric   LLVM_DEBUG(dbgs() << "\tUser: " << *U.getUser() << "\n");
1175ffd83dbSDimitry Andric   LLVM_DEBUG(dbgs() << "\tOperand: " << *U.get() << "\n");
1185ffd83dbSDimitry Andric 
1195ffd83dbSDimitry Andric   U.set(new FreezeInst(ValueToFr, ValueToFr->getName() + ".frozen",
1205ffd83dbSDimitry Andric                        PH->getTerminator()));
1215ffd83dbSDimitry Andric 
1225ffd83dbSDimitry Andric   SE.forgetValue(UserI);
1235ffd83dbSDimitry Andric }
1245ffd83dbSDimitry Andric 
1255ffd83dbSDimitry Andric bool CanonicalizeFreezeInLoopsImpl::run() {
1265ffd83dbSDimitry Andric   // The loop should be in LoopSimplify form.
1275ffd83dbSDimitry Andric   if (!L->isLoopSimplifyForm())
1285ffd83dbSDimitry Andric     return false;
1295ffd83dbSDimitry Andric 
1305ffd83dbSDimitry Andric   SmallVector<FrozenIndPHIInfo, 4> Candidates;
1315ffd83dbSDimitry Andric 
1325ffd83dbSDimitry Andric   for (auto &PHI : L->getHeader()->phis()) {
1335ffd83dbSDimitry Andric     InductionDescriptor ID;
1345ffd83dbSDimitry Andric     if (!InductionDescriptor::isInductionPHI(&PHI, L, &SE, ID))
1355ffd83dbSDimitry Andric       continue;
1365ffd83dbSDimitry Andric 
1375ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "canonfr: PHI: " << PHI << "\n");
1385ffd83dbSDimitry Andric     FrozenIndPHIInfo Info(&PHI, ID.getInductionBinOp());
1395ffd83dbSDimitry Andric     if (!Info.StepInst || !canHandleInst(Info.StepInst)) {
1405ffd83dbSDimitry Andric       // The stepping instruction has unknown form.
1415ffd83dbSDimitry Andric       // Ignore this PHI.
1425ffd83dbSDimitry Andric       continue;
1435ffd83dbSDimitry Andric     }
1445ffd83dbSDimitry Andric 
1455ffd83dbSDimitry Andric     Info.StepValIdx = Info.StepInst->getOperand(0) == &PHI;
1465ffd83dbSDimitry Andric     Value *StepV = Info.StepInst->getOperand(Info.StepValIdx);
1475ffd83dbSDimitry Andric     if (auto *StepI = dyn_cast<Instruction>(StepV)) {
1485ffd83dbSDimitry Andric       if (L->contains(StepI->getParent())) {
1495ffd83dbSDimitry Andric         // The step value is inside the loop. Freezing step value will introduce
1505ffd83dbSDimitry Andric         // another freeze into the loop, so skip this PHI.
1515ffd83dbSDimitry Andric         continue;
1525ffd83dbSDimitry Andric       }
1535ffd83dbSDimitry Andric     }
1545ffd83dbSDimitry Andric 
1555ffd83dbSDimitry Andric     auto Visit = [&](User *U) {
1565ffd83dbSDimitry Andric       if (auto *FI = dyn_cast<FreezeInst>(U)) {
1575ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "canonfr: found: " << *FI << "\n");
1585ffd83dbSDimitry Andric         Info.FI = FI;
1595ffd83dbSDimitry Andric         Candidates.push_back(Info);
1605ffd83dbSDimitry Andric       }
1615ffd83dbSDimitry Andric     };
1625ffd83dbSDimitry Andric     for_each(PHI.users(), Visit);
1635ffd83dbSDimitry Andric     for_each(Info.StepInst->users(), Visit);
1645ffd83dbSDimitry Andric   }
1655ffd83dbSDimitry Andric 
1665ffd83dbSDimitry Andric   if (Candidates.empty())
1675ffd83dbSDimitry Andric     return false;
1685ffd83dbSDimitry Andric 
1695ffd83dbSDimitry Andric   SmallSet<PHINode *, 8> ProcessedPHIs;
1705ffd83dbSDimitry Andric   for (const auto &Info : Candidates) {
1715ffd83dbSDimitry Andric     PHINode *PHI = Info.PHI;
1725ffd83dbSDimitry Andric     if (!ProcessedPHIs.insert(Info.PHI).second)
1735ffd83dbSDimitry Andric       continue;
1745ffd83dbSDimitry Andric 
1755ffd83dbSDimitry Andric     BinaryOperator *StepI = Info.StepInst;
1765ffd83dbSDimitry Andric     assert(StepI && "Step instruction should have been found");
1775ffd83dbSDimitry Andric 
1785ffd83dbSDimitry Andric     // Drop flags from the step instruction.
179*e8d8bef9SDimitry Andric     if (!isGuaranteedNotToBeUndefOrPoison(StepI, nullptr, StepI, &DT)) {
1805ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "canonfr: drop flags: " << *StepI << "\n");
1815ffd83dbSDimitry Andric       StepI->dropPoisonGeneratingFlags();
1825ffd83dbSDimitry Andric       SE.forgetValue(StepI);
1835ffd83dbSDimitry Andric     }
1845ffd83dbSDimitry Andric 
1855ffd83dbSDimitry Andric     InsertFreezeAndForgetFromSCEV(StepI->getOperandUse(Info.StepValIdx));
1865ffd83dbSDimitry Andric 
1875ffd83dbSDimitry Andric     unsigned OperandIdx =
1885ffd83dbSDimitry Andric         PHI->getOperandNumForIncomingValue(PHI->getIncomingValue(0) == StepI);
1895ffd83dbSDimitry Andric     InsertFreezeAndForgetFromSCEV(PHI->getOperandUse(OperandIdx));
1905ffd83dbSDimitry Andric   }
1915ffd83dbSDimitry Andric 
1925ffd83dbSDimitry Andric   // Finally, remove the old freeze instructions.
1935ffd83dbSDimitry Andric   for (const auto &Item : Candidates) {
1945ffd83dbSDimitry Andric     auto *FI = Item.FI;
1955ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "canonfr: removing " << *FI << "\n");
1965ffd83dbSDimitry Andric     SE.forgetValue(FI);
1975ffd83dbSDimitry Andric     FI->replaceAllUsesWith(FI->getOperand(0));
1985ffd83dbSDimitry Andric     FI->eraseFromParent();
1995ffd83dbSDimitry Andric   }
2005ffd83dbSDimitry Andric 
2015ffd83dbSDimitry Andric   return true;
2025ffd83dbSDimitry Andric }
2035ffd83dbSDimitry Andric 
2045ffd83dbSDimitry Andric CanonicalizeFreezeInLoops::CanonicalizeFreezeInLoops() : LoopPass(ID) {
2055ffd83dbSDimitry Andric   initializeCanonicalizeFreezeInLoopsPass(*PassRegistry::getPassRegistry());
2065ffd83dbSDimitry Andric }
2075ffd83dbSDimitry Andric 
2085ffd83dbSDimitry Andric void CanonicalizeFreezeInLoops::getAnalysisUsage(AnalysisUsage &AU) const {
2095ffd83dbSDimitry Andric   AU.addPreservedID(LoopSimplifyID);
2105ffd83dbSDimitry Andric   AU.addRequired<LoopInfoWrapperPass>();
2115ffd83dbSDimitry Andric   AU.addPreserved<LoopInfoWrapperPass>();
2125ffd83dbSDimitry Andric   AU.addRequiredID(LoopSimplifyID);
2135ffd83dbSDimitry Andric   AU.addRequired<ScalarEvolutionWrapperPass>();
2145ffd83dbSDimitry Andric   AU.addPreserved<ScalarEvolutionWrapperPass>();
2155ffd83dbSDimitry Andric   AU.addRequired<DominatorTreeWrapperPass>();
2165ffd83dbSDimitry Andric   AU.addPreserved<DominatorTreeWrapperPass>();
2175ffd83dbSDimitry Andric }
2185ffd83dbSDimitry Andric 
2195ffd83dbSDimitry Andric bool CanonicalizeFreezeInLoops::runOnLoop(Loop *L, LPPassManager &) {
2205ffd83dbSDimitry Andric   if (skipLoop(L))
2215ffd83dbSDimitry Andric     return false;
2225ffd83dbSDimitry Andric 
2235ffd83dbSDimitry Andric   auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
2245ffd83dbSDimitry Andric   auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
2255ffd83dbSDimitry Andric   return CanonicalizeFreezeInLoopsImpl(L, SE, DT).run();
2265ffd83dbSDimitry Andric }
2275ffd83dbSDimitry Andric 
2285ffd83dbSDimitry Andric PreservedAnalyses
2295ffd83dbSDimitry Andric CanonicalizeFreezeInLoopsPass::run(Loop &L, LoopAnalysisManager &AM,
2305ffd83dbSDimitry Andric                                    LoopStandardAnalysisResults &AR,
2315ffd83dbSDimitry Andric                                    LPMUpdater &U) {
2325ffd83dbSDimitry Andric   if (!CanonicalizeFreezeInLoopsImpl(&L, AR.SE, AR.DT).run())
2335ffd83dbSDimitry Andric     return PreservedAnalyses::all();
2345ffd83dbSDimitry Andric 
2355ffd83dbSDimitry Andric   return getLoopPassPreservedAnalyses();
2365ffd83dbSDimitry Andric }
2375ffd83dbSDimitry Andric 
2385ffd83dbSDimitry Andric INITIALIZE_PASS_BEGIN(CanonicalizeFreezeInLoops, "canon-freeze",
2395ffd83dbSDimitry Andric                       "Canonicalize Freeze Instructions in Loops", false, false)
2405ffd83dbSDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
2415ffd83dbSDimitry Andric INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
2425ffd83dbSDimitry Andric INITIALIZE_PASS_DEPENDENCY(LoopSimplify)
2435ffd83dbSDimitry Andric INITIALIZE_PASS_END(CanonicalizeFreezeInLoops, "canon-freeze",
2445ffd83dbSDimitry Andric                     "Canonicalize Freeze Instructions in Loops", false, false)
2455ffd83dbSDimitry Andric 
2465ffd83dbSDimitry Andric Pass *llvm::createCanonicalizeFreezeInLoopsPass() {
2475ffd83dbSDimitry Andric   return new CanonicalizeFreezeInLoops();
2485ffd83dbSDimitry Andric }
2495ffd83dbSDimitry Andric 
2505ffd83dbSDimitry Andric char CanonicalizeFreezeInLoops::ID = 0;
251