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