1*5ffd83dbSDimitry Andric //===- StackLifetime.cpp - Alloca Lifetime Analysis -----------------------===// 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 #include "llvm/Analysis/StackLifetime.h" 10*5ffd83dbSDimitry Andric #include "llvm/ADT/DepthFirstIterator.h" 11*5ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h" 12*5ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h" 13*5ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h" 14*5ffd83dbSDimitry Andric #include "llvm/Config/llvm-config.h" 15*5ffd83dbSDimitry Andric #include "llvm/IR/AssemblyAnnotationWriter.h" 16*5ffd83dbSDimitry Andric #include "llvm/IR/BasicBlock.h" 17*5ffd83dbSDimitry Andric #include "llvm/IR/CFG.h" 18*5ffd83dbSDimitry Andric #include "llvm/IR/InstIterator.h" 19*5ffd83dbSDimitry Andric #include "llvm/IR/Instructions.h" 20*5ffd83dbSDimitry Andric #include "llvm/IR/IntrinsicInst.h" 21*5ffd83dbSDimitry Andric #include "llvm/IR/Intrinsics.h" 22*5ffd83dbSDimitry Andric #include "llvm/IR/User.h" 23*5ffd83dbSDimitry Andric #include "llvm/IR/Value.h" 24*5ffd83dbSDimitry Andric #include "llvm/Pass.h" 25*5ffd83dbSDimitry Andric #include "llvm/Support/Casting.h" 26*5ffd83dbSDimitry Andric #include "llvm/Support/CommandLine.h" 27*5ffd83dbSDimitry Andric #include "llvm/Support/Compiler.h" 28*5ffd83dbSDimitry Andric #include "llvm/Support/Debug.h" 29*5ffd83dbSDimitry Andric #include "llvm/Support/FormattedStream.h" 30*5ffd83dbSDimitry Andric #include <algorithm> 31*5ffd83dbSDimitry Andric #include <memory> 32*5ffd83dbSDimitry Andric #include <tuple> 33*5ffd83dbSDimitry Andric 34*5ffd83dbSDimitry Andric using namespace llvm; 35*5ffd83dbSDimitry Andric 36*5ffd83dbSDimitry Andric #define DEBUG_TYPE "stack-lifetime" 37*5ffd83dbSDimitry Andric 38*5ffd83dbSDimitry Andric const StackLifetime::LiveRange & 39*5ffd83dbSDimitry Andric StackLifetime::getLiveRange(const AllocaInst *AI) const { 40*5ffd83dbSDimitry Andric const auto IT = AllocaNumbering.find(AI); 41*5ffd83dbSDimitry Andric assert(IT != AllocaNumbering.end()); 42*5ffd83dbSDimitry Andric return LiveRanges[IT->second]; 43*5ffd83dbSDimitry Andric } 44*5ffd83dbSDimitry Andric 45*5ffd83dbSDimitry Andric bool StackLifetime::isReachable(const Instruction *I) const { 46*5ffd83dbSDimitry Andric return BlockInstRange.find(I->getParent()) != BlockInstRange.end(); 47*5ffd83dbSDimitry Andric } 48*5ffd83dbSDimitry Andric 49*5ffd83dbSDimitry Andric bool StackLifetime::isAliveAfter(const AllocaInst *AI, 50*5ffd83dbSDimitry Andric const Instruction *I) const { 51*5ffd83dbSDimitry Andric const BasicBlock *BB = I->getParent(); 52*5ffd83dbSDimitry Andric auto ItBB = BlockInstRange.find(BB); 53*5ffd83dbSDimitry Andric assert(ItBB != BlockInstRange.end() && "Unreachable is not expected"); 54*5ffd83dbSDimitry Andric 55*5ffd83dbSDimitry Andric // Search the block for the first instruction following 'I'. 56*5ffd83dbSDimitry Andric auto It = std::upper_bound(Instructions.begin() + ItBB->getSecond().first + 1, 57*5ffd83dbSDimitry Andric Instructions.begin() + ItBB->getSecond().second, I, 58*5ffd83dbSDimitry Andric [](const Instruction *L, const Instruction *R) { 59*5ffd83dbSDimitry Andric return L->comesBefore(R); 60*5ffd83dbSDimitry Andric }); 61*5ffd83dbSDimitry Andric --It; 62*5ffd83dbSDimitry Andric unsigned InstNum = It - Instructions.begin(); 63*5ffd83dbSDimitry Andric return getLiveRange(AI).test(InstNum); 64*5ffd83dbSDimitry Andric } 65*5ffd83dbSDimitry Andric 66*5ffd83dbSDimitry Andric static bool readMarker(const Instruction *I, bool *IsStart) { 67*5ffd83dbSDimitry Andric if (!I->isLifetimeStartOrEnd()) 68*5ffd83dbSDimitry Andric return false; 69*5ffd83dbSDimitry Andric 70*5ffd83dbSDimitry Andric auto *II = cast<IntrinsicInst>(I); 71*5ffd83dbSDimitry Andric *IsStart = II->getIntrinsicID() == Intrinsic::lifetime_start; 72*5ffd83dbSDimitry Andric return true; 73*5ffd83dbSDimitry Andric } 74*5ffd83dbSDimitry Andric 75*5ffd83dbSDimitry Andric void StackLifetime::collectMarkers() { 76*5ffd83dbSDimitry Andric InterestingAllocas.resize(NumAllocas); 77*5ffd83dbSDimitry Andric DenseMap<const BasicBlock *, SmallDenseMap<const IntrinsicInst *, Marker>> 78*5ffd83dbSDimitry Andric BBMarkerSet; 79*5ffd83dbSDimitry Andric 80*5ffd83dbSDimitry Andric // Compute the set of start/end markers per basic block. 81*5ffd83dbSDimitry Andric for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) { 82*5ffd83dbSDimitry Andric const AllocaInst *AI = Allocas[AllocaNo]; 83*5ffd83dbSDimitry Andric SmallVector<const Instruction *, 8> WorkList; 84*5ffd83dbSDimitry Andric WorkList.push_back(AI); 85*5ffd83dbSDimitry Andric while (!WorkList.empty()) { 86*5ffd83dbSDimitry Andric const Instruction *I = WorkList.pop_back_val(); 87*5ffd83dbSDimitry Andric for (const User *U : I->users()) { 88*5ffd83dbSDimitry Andric if (auto *BI = dyn_cast<BitCastInst>(U)) { 89*5ffd83dbSDimitry Andric WorkList.push_back(BI); 90*5ffd83dbSDimitry Andric continue; 91*5ffd83dbSDimitry Andric } 92*5ffd83dbSDimitry Andric auto *UI = dyn_cast<IntrinsicInst>(U); 93*5ffd83dbSDimitry Andric if (!UI) 94*5ffd83dbSDimitry Andric continue; 95*5ffd83dbSDimitry Andric bool IsStart; 96*5ffd83dbSDimitry Andric if (!readMarker(UI, &IsStart)) 97*5ffd83dbSDimitry Andric continue; 98*5ffd83dbSDimitry Andric if (IsStart) 99*5ffd83dbSDimitry Andric InterestingAllocas.set(AllocaNo); 100*5ffd83dbSDimitry Andric BBMarkerSet[UI->getParent()][UI] = {AllocaNo, IsStart}; 101*5ffd83dbSDimitry Andric } 102*5ffd83dbSDimitry Andric } 103*5ffd83dbSDimitry Andric } 104*5ffd83dbSDimitry Andric 105*5ffd83dbSDimitry Andric // Compute instruction numbering. Only the following instructions are 106*5ffd83dbSDimitry Andric // considered: 107*5ffd83dbSDimitry Andric // * Basic block entries 108*5ffd83dbSDimitry Andric // * Lifetime markers 109*5ffd83dbSDimitry Andric // For each basic block, compute 110*5ffd83dbSDimitry Andric // * the list of markers in the instruction order 111*5ffd83dbSDimitry Andric // * the sets of allocas whose lifetime starts or ends in this BB 112*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Instructions:\n"); 113*5ffd83dbSDimitry Andric for (const BasicBlock *BB : depth_first(&F)) { 114*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " " << Instructions.size() << ": BB " << BB->getName() 115*5ffd83dbSDimitry Andric << "\n"); 116*5ffd83dbSDimitry Andric auto BBStart = Instructions.size(); 117*5ffd83dbSDimitry Andric Instructions.push_back(nullptr); 118*5ffd83dbSDimitry Andric 119*5ffd83dbSDimitry Andric BlockLifetimeInfo &BlockInfo = 120*5ffd83dbSDimitry Andric BlockLiveness.try_emplace(BB, NumAllocas).first->getSecond(); 121*5ffd83dbSDimitry Andric 122*5ffd83dbSDimitry Andric auto &BlockMarkerSet = BBMarkerSet[BB]; 123*5ffd83dbSDimitry Andric if (BlockMarkerSet.empty()) { 124*5ffd83dbSDimitry Andric BlockInstRange[BB] = std::make_pair(BBStart, Instructions.size()); 125*5ffd83dbSDimitry Andric continue; 126*5ffd83dbSDimitry Andric } 127*5ffd83dbSDimitry Andric 128*5ffd83dbSDimitry Andric auto ProcessMarker = [&](const IntrinsicInst *I, const Marker &M) { 129*5ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " " << Instructions.size() << ": " 130*5ffd83dbSDimitry Andric << (M.IsStart ? "start " : "end ") << M.AllocaNo 131*5ffd83dbSDimitry Andric << ", " << *I << "\n"); 132*5ffd83dbSDimitry Andric 133*5ffd83dbSDimitry Andric BBMarkers[BB].push_back({Instructions.size(), M}); 134*5ffd83dbSDimitry Andric Instructions.push_back(I); 135*5ffd83dbSDimitry Andric 136*5ffd83dbSDimitry Andric if (M.IsStart) { 137*5ffd83dbSDimitry Andric BlockInfo.End.reset(M.AllocaNo); 138*5ffd83dbSDimitry Andric BlockInfo.Begin.set(M.AllocaNo); 139*5ffd83dbSDimitry Andric } else { 140*5ffd83dbSDimitry Andric BlockInfo.Begin.reset(M.AllocaNo); 141*5ffd83dbSDimitry Andric BlockInfo.End.set(M.AllocaNo); 142*5ffd83dbSDimitry Andric } 143*5ffd83dbSDimitry Andric }; 144*5ffd83dbSDimitry Andric 145*5ffd83dbSDimitry Andric if (BlockMarkerSet.size() == 1) { 146*5ffd83dbSDimitry Andric ProcessMarker(BlockMarkerSet.begin()->getFirst(), 147*5ffd83dbSDimitry Andric BlockMarkerSet.begin()->getSecond()); 148*5ffd83dbSDimitry Andric } else { 149*5ffd83dbSDimitry Andric // Scan the BB to determine the marker order. 150*5ffd83dbSDimitry Andric for (const Instruction &I : *BB) { 151*5ffd83dbSDimitry Andric const IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I); 152*5ffd83dbSDimitry Andric if (!II) 153*5ffd83dbSDimitry Andric continue; 154*5ffd83dbSDimitry Andric auto It = BlockMarkerSet.find(II); 155*5ffd83dbSDimitry Andric if (It == BlockMarkerSet.end()) 156*5ffd83dbSDimitry Andric continue; 157*5ffd83dbSDimitry Andric ProcessMarker(II, It->getSecond()); 158*5ffd83dbSDimitry Andric } 159*5ffd83dbSDimitry Andric } 160*5ffd83dbSDimitry Andric 161*5ffd83dbSDimitry Andric BlockInstRange[BB] = std::make_pair(BBStart, Instructions.size()); 162*5ffd83dbSDimitry Andric } 163*5ffd83dbSDimitry Andric } 164*5ffd83dbSDimitry Andric 165*5ffd83dbSDimitry Andric void StackLifetime::calculateLocalLiveness() { 166*5ffd83dbSDimitry Andric bool Changed = true; 167*5ffd83dbSDimitry Andric while (Changed) { 168*5ffd83dbSDimitry Andric Changed = false; 169*5ffd83dbSDimitry Andric 170*5ffd83dbSDimitry Andric for (const BasicBlock *BB : depth_first(&F)) { 171*5ffd83dbSDimitry Andric BlockLifetimeInfo &BlockInfo = BlockLiveness.find(BB)->getSecond(); 172*5ffd83dbSDimitry Andric 173*5ffd83dbSDimitry Andric // Compute LiveIn by unioning together the LiveOut sets of all preds. 174*5ffd83dbSDimitry Andric BitVector LocalLiveIn; 175*5ffd83dbSDimitry Andric for (auto *PredBB : predecessors(BB)) { 176*5ffd83dbSDimitry Andric LivenessMap::const_iterator I = BlockLiveness.find(PredBB); 177*5ffd83dbSDimitry Andric // If a predecessor is unreachable, ignore it. 178*5ffd83dbSDimitry Andric if (I == BlockLiveness.end()) 179*5ffd83dbSDimitry Andric continue; 180*5ffd83dbSDimitry Andric switch (Type) { 181*5ffd83dbSDimitry Andric case LivenessType::May: 182*5ffd83dbSDimitry Andric LocalLiveIn |= I->second.LiveOut; 183*5ffd83dbSDimitry Andric break; 184*5ffd83dbSDimitry Andric case LivenessType::Must: 185*5ffd83dbSDimitry Andric if (LocalLiveIn.empty()) 186*5ffd83dbSDimitry Andric LocalLiveIn = I->second.LiveOut; 187*5ffd83dbSDimitry Andric else 188*5ffd83dbSDimitry Andric LocalLiveIn &= I->second.LiveOut; 189*5ffd83dbSDimitry Andric break; 190*5ffd83dbSDimitry Andric } 191*5ffd83dbSDimitry Andric } 192*5ffd83dbSDimitry Andric 193*5ffd83dbSDimitry Andric // Compute LiveOut by subtracting out lifetimes that end in this 194*5ffd83dbSDimitry Andric // block, then adding in lifetimes that begin in this block. If 195*5ffd83dbSDimitry Andric // we have both BEGIN and END markers in the same basic block 196*5ffd83dbSDimitry Andric // then we know that the BEGIN marker comes after the END, 197*5ffd83dbSDimitry Andric // because we already handle the case where the BEGIN comes 198*5ffd83dbSDimitry Andric // before the END when collecting the markers (and building the 199*5ffd83dbSDimitry Andric // BEGIN/END vectors). 200*5ffd83dbSDimitry Andric BitVector LocalLiveOut = LocalLiveIn; 201*5ffd83dbSDimitry Andric LocalLiveOut.reset(BlockInfo.End); 202*5ffd83dbSDimitry Andric LocalLiveOut |= BlockInfo.Begin; 203*5ffd83dbSDimitry Andric 204*5ffd83dbSDimitry Andric // Update block LiveIn set, noting whether it has changed. 205*5ffd83dbSDimitry Andric if (LocalLiveIn.test(BlockInfo.LiveIn)) { 206*5ffd83dbSDimitry Andric BlockInfo.LiveIn |= LocalLiveIn; 207*5ffd83dbSDimitry Andric } 208*5ffd83dbSDimitry Andric 209*5ffd83dbSDimitry Andric // Update block LiveOut set, noting whether it has changed. 210*5ffd83dbSDimitry Andric if (LocalLiveOut.test(BlockInfo.LiveOut)) { 211*5ffd83dbSDimitry Andric Changed = true; 212*5ffd83dbSDimitry Andric BlockInfo.LiveOut |= LocalLiveOut; 213*5ffd83dbSDimitry Andric } 214*5ffd83dbSDimitry Andric } 215*5ffd83dbSDimitry Andric } // while changed. 216*5ffd83dbSDimitry Andric } 217*5ffd83dbSDimitry Andric 218*5ffd83dbSDimitry Andric void StackLifetime::calculateLiveIntervals() { 219*5ffd83dbSDimitry Andric for (auto IT : BlockLiveness) { 220*5ffd83dbSDimitry Andric const BasicBlock *BB = IT.getFirst(); 221*5ffd83dbSDimitry Andric BlockLifetimeInfo &BlockInfo = IT.getSecond(); 222*5ffd83dbSDimitry Andric unsigned BBStart, BBEnd; 223*5ffd83dbSDimitry Andric std::tie(BBStart, BBEnd) = BlockInstRange[BB]; 224*5ffd83dbSDimitry Andric 225*5ffd83dbSDimitry Andric BitVector Started, Ended; 226*5ffd83dbSDimitry Andric Started.resize(NumAllocas); 227*5ffd83dbSDimitry Andric Ended.resize(NumAllocas); 228*5ffd83dbSDimitry Andric SmallVector<unsigned, 8> Start; 229*5ffd83dbSDimitry Andric Start.resize(NumAllocas); 230*5ffd83dbSDimitry Andric 231*5ffd83dbSDimitry Andric // LiveIn ranges start at the first instruction. 232*5ffd83dbSDimitry Andric for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) { 233*5ffd83dbSDimitry Andric if (BlockInfo.LiveIn.test(AllocaNo)) { 234*5ffd83dbSDimitry Andric Started.set(AllocaNo); 235*5ffd83dbSDimitry Andric Start[AllocaNo] = BBStart; 236*5ffd83dbSDimitry Andric } 237*5ffd83dbSDimitry Andric } 238*5ffd83dbSDimitry Andric 239*5ffd83dbSDimitry Andric for (auto &It : BBMarkers[BB]) { 240*5ffd83dbSDimitry Andric unsigned InstNo = It.first; 241*5ffd83dbSDimitry Andric bool IsStart = It.second.IsStart; 242*5ffd83dbSDimitry Andric unsigned AllocaNo = It.second.AllocaNo; 243*5ffd83dbSDimitry Andric 244*5ffd83dbSDimitry Andric if (IsStart) { 245*5ffd83dbSDimitry Andric assert(!Started.test(AllocaNo) || Start[AllocaNo] == BBStart); 246*5ffd83dbSDimitry Andric if (!Started.test(AllocaNo)) { 247*5ffd83dbSDimitry Andric Started.set(AllocaNo); 248*5ffd83dbSDimitry Andric Ended.reset(AllocaNo); 249*5ffd83dbSDimitry Andric Start[AllocaNo] = InstNo; 250*5ffd83dbSDimitry Andric } 251*5ffd83dbSDimitry Andric } else { 252*5ffd83dbSDimitry Andric assert(!Ended.test(AllocaNo)); 253*5ffd83dbSDimitry Andric if (Started.test(AllocaNo)) { 254*5ffd83dbSDimitry Andric LiveRanges[AllocaNo].addRange(Start[AllocaNo], InstNo); 255*5ffd83dbSDimitry Andric Started.reset(AllocaNo); 256*5ffd83dbSDimitry Andric } 257*5ffd83dbSDimitry Andric Ended.set(AllocaNo); 258*5ffd83dbSDimitry Andric } 259*5ffd83dbSDimitry Andric } 260*5ffd83dbSDimitry Andric 261*5ffd83dbSDimitry Andric for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) 262*5ffd83dbSDimitry Andric if (Started.test(AllocaNo)) 263*5ffd83dbSDimitry Andric LiveRanges[AllocaNo].addRange(Start[AllocaNo], BBEnd); 264*5ffd83dbSDimitry Andric } 265*5ffd83dbSDimitry Andric } 266*5ffd83dbSDimitry Andric 267*5ffd83dbSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 268*5ffd83dbSDimitry Andric LLVM_DUMP_METHOD void StackLifetime::dumpAllocas() const { 269*5ffd83dbSDimitry Andric dbgs() << "Allocas:\n"; 270*5ffd83dbSDimitry Andric for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) 271*5ffd83dbSDimitry Andric dbgs() << " " << AllocaNo << ": " << *Allocas[AllocaNo] << "\n"; 272*5ffd83dbSDimitry Andric } 273*5ffd83dbSDimitry Andric 274*5ffd83dbSDimitry Andric LLVM_DUMP_METHOD void StackLifetime::dumpBlockLiveness() const { 275*5ffd83dbSDimitry Andric dbgs() << "Block liveness:\n"; 276*5ffd83dbSDimitry Andric for (auto IT : BlockLiveness) { 277*5ffd83dbSDimitry Andric const BasicBlock *BB = IT.getFirst(); 278*5ffd83dbSDimitry Andric const BlockLifetimeInfo &BlockInfo = BlockLiveness.find(BB)->getSecond(); 279*5ffd83dbSDimitry Andric auto BlockRange = BlockInstRange.find(BB)->getSecond(); 280*5ffd83dbSDimitry Andric dbgs() << " BB [" << BlockRange.first << ", " << BlockRange.second 281*5ffd83dbSDimitry Andric << "): begin " << BlockInfo.Begin << ", end " << BlockInfo.End 282*5ffd83dbSDimitry Andric << ", livein " << BlockInfo.LiveIn << ", liveout " 283*5ffd83dbSDimitry Andric << BlockInfo.LiveOut << "\n"; 284*5ffd83dbSDimitry Andric } 285*5ffd83dbSDimitry Andric } 286*5ffd83dbSDimitry Andric 287*5ffd83dbSDimitry Andric LLVM_DUMP_METHOD void StackLifetime::dumpLiveRanges() const { 288*5ffd83dbSDimitry Andric dbgs() << "Alloca liveness:\n"; 289*5ffd83dbSDimitry Andric for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) 290*5ffd83dbSDimitry Andric dbgs() << " " << AllocaNo << ": " << LiveRanges[AllocaNo] << "\n"; 291*5ffd83dbSDimitry Andric } 292*5ffd83dbSDimitry Andric #endif 293*5ffd83dbSDimitry Andric 294*5ffd83dbSDimitry Andric StackLifetime::StackLifetime(const Function &F, 295*5ffd83dbSDimitry Andric ArrayRef<const AllocaInst *> Allocas, 296*5ffd83dbSDimitry Andric LivenessType Type) 297*5ffd83dbSDimitry Andric : F(F), Type(Type), Allocas(Allocas), NumAllocas(Allocas.size()) { 298*5ffd83dbSDimitry Andric LLVM_DEBUG(dumpAllocas()); 299*5ffd83dbSDimitry Andric 300*5ffd83dbSDimitry Andric for (unsigned I = 0; I < NumAllocas; ++I) 301*5ffd83dbSDimitry Andric AllocaNumbering[Allocas[I]] = I; 302*5ffd83dbSDimitry Andric 303*5ffd83dbSDimitry Andric collectMarkers(); 304*5ffd83dbSDimitry Andric } 305*5ffd83dbSDimitry Andric 306*5ffd83dbSDimitry Andric void StackLifetime::run() { 307*5ffd83dbSDimitry Andric LiveRanges.resize(NumAllocas, LiveRange(Instructions.size())); 308*5ffd83dbSDimitry Andric for (unsigned I = 0; I < NumAllocas; ++I) 309*5ffd83dbSDimitry Andric if (!InterestingAllocas.test(I)) 310*5ffd83dbSDimitry Andric LiveRanges[I] = getFullLiveRange(); 311*5ffd83dbSDimitry Andric 312*5ffd83dbSDimitry Andric calculateLocalLiveness(); 313*5ffd83dbSDimitry Andric LLVM_DEBUG(dumpBlockLiveness()); 314*5ffd83dbSDimitry Andric calculateLiveIntervals(); 315*5ffd83dbSDimitry Andric LLVM_DEBUG(dumpLiveRanges()); 316*5ffd83dbSDimitry Andric } 317*5ffd83dbSDimitry Andric 318*5ffd83dbSDimitry Andric class StackLifetime::LifetimeAnnotationWriter 319*5ffd83dbSDimitry Andric : public AssemblyAnnotationWriter { 320*5ffd83dbSDimitry Andric const StackLifetime &SL; 321*5ffd83dbSDimitry Andric 322*5ffd83dbSDimitry Andric void printInstrAlive(unsigned InstrNo, formatted_raw_ostream &OS) { 323*5ffd83dbSDimitry Andric SmallVector<StringRef, 16> Names; 324*5ffd83dbSDimitry Andric for (const auto &KV : SL.AllocaNumbering) { 325*5ffd83dbSDimitry Andric if (SL.LiveRanges[KV.getSecond()].test(InstrNo)) 326*5ffd83dbSDimitry Andric Names.push_back(KV.getFirst()->getName()); 327*5ffd83dbSDimitry Andric } 328*5ffd83dbSDimitry Andric llvm::sort(Names); 329*5ffd83dbSDimitry Andric OS << " ; Alive: <" << llvm::join(Names, " ") << ">\n"; 330*5ffd83dbSDimitry Andric } 331*5ffd83dbSDimitry Andric 332*5ffd83dbSDimitry Andric void emitBasicBlockStartAnnot(const BasicBlock *BB, 333*5ffd83dbSDimitry Andric formatted_raw_ostream &OS) override { 334*5ffd83dbSDimitry Andric auto ItBB = SL.BlockInstRange.find(BB); 335*5ffd83dbSDimitry Andric if (ItBB == SL.BlockInstRange.end()) 336*5ffd83dbSDimitry Andric return; // Unreachable. 337*5ffd83dbSDimitry Andric printInstrAlive(ItBB->getSecond().first, OS); 338*5ffd83dbSDimitry Andric } 339*5ffd83dbSDimitry Andric 340*5ffd83dbSDimitry Andric void printInfoComment(const Value &V, formatted_raw_ostream &OS) override { 341*5ffd83dbSDimitry Andric const Instruction *Instr = dyn_cast<Instruction>(&V); 342*5ffd83dbSDimitry Andric if (!Instr || !SL.isReachable(Instr)) 343*5ffd83dbSDimitry Andric return; 344*5ffd83dbSDimitry Andric 345*5ffd83dbSDimitry Andric SmallVector<StringRef, 16> Names; 346*5ffd83dbSDimitry Andric for (const auto &KV : SL.AllocaNumbering) { 347*5ffd83dbSDimitry Andric if (SL.isAliveAfter(KV.getFirst(), Instr)) 348*5ffd83dbSDimitry Andric Names.push_back(KV.getFirst()->getName()); 349*5ffd83dbSDimitry Andric } 350*5ffd83dbSDimitry Andric llvm::sort(Names); 351*5ffd83dbSDimitry Andric OS << "\n ; Alive: <" << llvm::join(Names, " ") << ">\n"; 352*5ffd83dbSDimitry Andric } 353*5ffd83dbSDimitry Andric 354*5ffd83dbSDimitry Andric public: 355*5ffd83dbSDimitry Andric LifetimeAnnotationWriter(const StackLifetime &SL) : SL(SL) {} 356*5ffd83dbSDimitry Andric }; 357*5ffd83dbSDimitry Andric 358*5ffd83dbSDimitry Andric void StackLifetime::print(raw_ostream &OS) { 359*5ffd83dbSDimitry Andric LifetimeAnnotationWriter AAW(*this); 360*5ffd83dbSDimitry Andric F.print(OS, &AAW); 361*5ffd83dbSDimitry Andric } 362*5ffd83dbSDimitry Andric 363*5ffd83dbSDimitry Andric PreservedAnalyses StackLifetimePrinterPass::run(Function &F, 364*5ffd83dbSDimitry Andric FunctionAnalysisManager &AM) { 365*5ffd83dbSDimitry Andric SmallVector<const AllocaInst *, 8> Allocas; 366*5ffd83dbSDimitry Andric for (auto &I : instructions(F)) 367*5ffd83dbSDimitry Andric if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) 368*5ffd83dbSDimitry Andric Allocas.push_back(AI); 369*5ffd83dbSDimitry Andric StackLifetime SL(F, Allocas, Type); 370*5ffd83dbSDimitry Andric SL.run(); 371*5ffd83dbSDimitry Andric SL.print(OS); 372*5ffd83dbSDimitry Andric return PreservedAnalyses::all(); 373*5ffd83dbSDimitry Andric } 374