1 #include "clang/Analysis/Analyses/LiveVariables.h" 2 #include "clang/AST/Stmt.h" 3 #include "clang/Analysis/CFG.h" 4 #include "clang/Analysis/AnalysisContext.h" 5 #include "clang/AST/StmtVisitor.h" 6 7 #include "llvm/ADT/PostOrderIterator.h" 8 #include "llvm/ADT/DenseMap.h" 9 10 #include <deque> 11 #include <algorithm> 12 #include <vector> 13 14 using namespace clang; 15 16 namespace { 17 18 // FIXME: This is copy-pasted from ThreadSafety.c. I wanted a patch that 19 // contained working code before refactoring the implementation of both 20 // files. 21 class CFGBlockSet { 22 llvm::BitVector VisitedBlockIDs; 23 24 public: 25 // po_iterator requires this iterator, but the only interface needed is the 26 // value_type typedef. 27 struct iterator { 28 typedef const CFGBlock *value_type; 29 }; 30 31 CFGBlockSet() {} 32 CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {} 33 34 /// \brief Set the bit associated with a particular CFGBlock. 35 /// This is the important method for the SetType template parameter. 36 bool insert(const CFGBlock *Block) { 37 // Note that insert() is called by po_iterator, which doesn't check to make 38 // sure that Block is non-null. Moreover, the CFGBlock iterator will 39 // occasionally hand out null pointers for pruned edges, so we catch those 40 // here. 41 if (Block == 0) 42 return false; // if an edge is trivially false. 43 if (VisitedBlockIDs.test(Block->getBlockID())) 44 return false; 45 VisitedBlockIDs.set(Block->getBlockID()); 46 return true; 47 } 48 49 /// \brief Check if the bit for a CFGBlock has been already set. 50 /// This method is for tracking visited blocks in the main threadsafety loop. 51 /// Block must not be null. 52 bool alreadySet(const CFGBlock *Block) { 53 return VisitedBlockIDs.test(Block->getBlockID()); 54 } 55 }; 56 57 /// \brief We create a helper class which we use to iterate through CFGBlocks in 58 /// the topological order. 59 class TopologicallySortedCFG { 60 typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator; 61 62 std::vector<const CFGBlock*> Blocks; 63 64 typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy; 65 BlockOrderTy BlockOrder; 66 67 68 public: 69 typedef std::vector<const CFGBlock*>::reverse_iterator iterator; 70 71 TopologicallySortedCFG(const CFG *CFGraph) { 72 Blocks.reserve(CFGraph->getNumBlockIDs()); 73 CFGBlockSet BSet(CFGraph); 74 75 for (po_iterator I = po_iterator::begin(CFGraph, BSet), 76 E = po_iterator::end(CFGraph, BSet); I != E; ++I) { 77 BlockOrder[*I] = Blocks.size() + 1; 78 Blocks.push_back(*I); 79 } 80 } 81 82 iterator begin() { 83 return Blocks.rbegin(); 84 } 85 86 iterator end() { 87 return Blocks.rend(); 88 } 89 90 bool empty() { 91 return begin() == end(); 92 } 93 94 struct BlockOrderCompare; 95 friend struct BlockOrderCompare; 96 97 struct BlockOrderCompare { 98 const TopologicallySortedCFG &TSC; 99 public: 100 BlockOrderCompare(const TopologicallySortedCFG &tsc) : TSC(tsc) {} 101 102 bool operator()(const CFGBlock *b1, const CFGBlock *b2) const { 103 TopologicallySortedCFG::BlockOrderTy::const_iterator b1It = TSC.BlockOrder.find(b1); 104 TopologicallySortedCFG::BlockOrderTy::const_iterator b2It = TSC.BlockOrder.find(b2); 105 106 unsigned b1V = (b1It == TSC.BlockOrder.end()) ? 0 : b1It->second; 107 unsigned b2V = (b2It == TSC.BlockOrder.end()) ? 0 : b2It->second; 108 return b1V > b2V; 109 } 110 }; 111 112 BlockOrderCompare getComparator() const { 113 return BlockOrderCompare(*this); 114 } 115 }; 116 117 class DataflowWorklist { 118 SmallVector<const CFGBlock *, 20> worklist; 119 llvm::BitVector enqueuedBlocks; 120 TopologicallySortedCFG TSC; 121 public: 122 DataflowWorklist(const CFG &cfg) 123 : enqueuedBlocks(cfg.getNumBlockIDs()), 124 TSC(&cfg) {} 125 126 void enqueueBlock(const CFGBlock *block); 127 void enqueueSuccessors(const CFGBlock *block); 128 void enqueuePredecessors(const CFGBlock *block); 129 130 const CFGBlock *dequeue(); 131 132 void sortWorklist(); 133 }; 134 135 } 136 137 void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) { 138 if (block && !enqueuedBlocks[block->getBlockID()]) { 139 enqueuedBlocks[block->getBlockID()] = true; 140 worklist.push_back(block); 141 } 142 } 143 144 void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) { 145 const unsigned OldWorklistSize = worklist.size(); 146 for (CFGBlock::const_succ_iterator I = block->succ_begin(), 147 E = block->succ_end(); I != E; ++I) { 148 enqueueBlock(*I); 149 } 150 151 if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) 152 return; 153 154 sortWorklist(); 155 } 156 157 void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) { 158 const unsigned OldWorklistSize = worklist.size(); 159 for (CFGBlock::const_pred_iterator I = block->pred_begin(), 160 E = block->pred_end(); I != E; ++I) { 161 enqueueBlock(*I); 162 } 163 164 if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) 165 return; 166 167 sortWorklist(); 168 } 169 170 void DataflowWorklist::sortWorklist() { 171 std::sort(worklist.begin(), worklist.end(), TSC.getComparator()); 172 } 173 174 175 const CFGBlock *DataflowWorklist::dequeue() { 176 if (worklist.empty()) 177 return 0; 178 const CFGBlock *b = worklist.back(); 179 worklist.pop_back(); 180 enqueuedBlocks[b->getBlockID()] = false; 181 return b; 182 } 183 184 namespace { 185 class LiveVariablesImpl { 186 public: 187 AnalysisContext &analysisContext; 188 std::vector<LiveVariables::LivenessValues> cfgBlockValues; 189 llvm::ImmutableSet<const Stmt *>::Factory SSetFact; 190 llvm::ImmutableSet<const VarDecl *>::Factory DSetFact; 191 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness; 192 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness; 193 llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness; 194 llvm::DenseMap<const DeclRefExpr *, unsigned> inAssignment; 195 const bool killAtAssign; 196 197 LiveVariables::LivenessValues 198 merge(LiveVariables::LivenessValues valsA, 199 LiveVariables::LivenessValues valsB); 200 201 LiveVariables::LivenessValues runOnBlock(const CFGBlock *block, 202 LiveVariables::LivenessValues val, 203 LiveVariables::Observer *obs = 0); 204 205 void dumpBlockLiveness(const SourceManager& M); 206 207 LiveVariablesImpl(AnalysisContext &ac, bool KillAtAssign) 208 : analysisContext(ac), 209 SSetFact(false), // Do not canonicalize ImmutableSets by default. 210 DSetFact(false), // This is a *major* performance win. 211 killAtAssign(KillAtAssign) {} 212 }; 213 } 214 215 static LiveVariablesImpl &getImpl(void *x) { 216 return *((LiveVariablesImpl *) x); 217 } 218 219 //===----------------------------------------------------------------------===// 220 // Operations and queries on LivenessValues. 221 //===----------------------------------------------------------------------===// 222 223 bool LiveVariables::LivenessValues::isLive(const Stmt *S) const { 224 return liveStmts.contains(S); 225 } 226 227 bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const { 228 return liveDecls.contains(D); 229 } 230 231 namespace { 232 template <typename SET> 233 SET mergeSets(SET A, SET B) { 234 if (A.isEmpty()) 235 return B; 236 237 for (typename SET::iterator it = B.begin(), ei = B.end(); it != ei; ++it) { 238 A = A.add(*it); 239 } 240 return A; 241 } 242 } 243 244 LiveVariables::LivenessValues 245 LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA, 246 LiveVariables::LivenessValues valsB) { 247 248 llvm::ImmutableSetRef<const Stmt *> 249 SSetRefA(valsA.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()), 250 SSetRefB(valsB.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()); 251 252 253 llvm::ImmutableSetRef<const VarDecl *> 254 DSetRefA(valsA.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()), 255 DSetRefB(valsB.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()); 256 257 258 SSetRefA = mergeSets(SSetRefA, SSetRefB); 259 DSetRefA = mergeSets(DSetRefA, DSetRefB); 260 261 // asImmutableSet() canonicalizes the tree, allowing us to do an easy 262 // comparison afterwards. 263 return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(), 264 DSetRefA.asImmutableSet()); 265 } 266 267 bool LiveVariables::LivenessValues::equals(const LivenessValues &V) const { 268 return liveStmts == V.liveStmts && liveDecls == V.liveDecls; 269 } 270 271 //===----------------------------------------------------------------------===// 272 // Query methods. 273 //===----------------------------------------------------------------------===// 274 275 static bool isAlwaysAlive(const VarDecl *D) { 276 return D->hasGlobalStorage(); 277 } 278 279 bool LiveVariables::isLive(const CFGBlock *B, const VarDecl *D) { 280 return isAlwaysAlive(D) || getImpl(impl).blocksEndToLiveness[B].isLive(D); 281 } 282 283 bool LiveVariables::isLive(const Stmt *S, const VarDecl *D) { 284 return isAlwaysAlive(D) || getImpl(impl).stmtsToLiveness[S].isLive(D); 285 } 286 287 bool LiveVariables::isLive(const Stmt *Loc, const Stmt *S) { 288 return getImpl(impl).stmtsToLiveness[Loc].isLive(S); 289 } 290 291 //===----------------------------------------------------------------------===// 292 // Dataflow computation. 293 //===----------------------------------------------------------------------===// 294 295 namespace { 296 class TransferFunctions : public StmtVisitor<TransferFunctions> { 297 LiveVariablesImpl &LV; 298 LiveVariables::LivenessValues &val; 299 LiveVariables::Observer *observer; 300 const CFGBlock *currentBlock; 301 public: 302 TransferFunctions(LiveVariablesImpl &im, 303 LiveVariables::LivenessValues &Val, 304 LiveVariables::Observer *Observer, 305 const CFGBlock *CurrentBlock) 306 : LV(im), val(Val), observer(Observer), currentBlock(CurrentBlock) {} 307 308 void VisitBinaryOperator(BinaryOperator *BO); 309 void VisitBlockExpr(BlockExpr *BE); 310 void VisitDeclRefExpr(DeclRefExpr *DR); 311 void VisitDeclStmt(DeclStmt *DS); 312 void VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS); 313 void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE); 314 void VisitUnaryOperator(UnaryOperator *UO); 315 void Visit(Stmt *S); 316 }; 317 } 318 319 static const VariableArrayType *FindVA(QualType Ty) { 320 const Type *ty = Ty.getTypePtr(); 321 while (const ArrayType *VT = dyn_cast<ArrayType>(ty)) { 322 if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(VT)) 323 if (VAT->getSizeExpr()) 324 return VAT; 325 326 ty = VT->getElementType().getTypePtr(); 327 } 328 329 return 0; 330 } 331 332 void TransferFunctions::Visit(Stmt *S) { 333 if (observer) 334 observer->observeStmt(S, currentBlock, val); 335 336 StmtVisitor<TransferFunctions>::Visit(S); 337 338 if (isa<Expr>(S)) { 339 val.liveStmts = LV.SSetFact.remove(val.liveStmts, S); 340 } 341 342 // Mark all children expressions live. 343 344 switch (S->getStmtClass()) { 345 default: 346 break; 347 case Stmt::StmtExprClass: { 348 // For statement expressions, look through the compound statement. 349 S = cast<StmtExpr>(S)->getSubStmt(); 350 break; 351 } 352 case Stmt::CXXMemberCallExprClass: { 353 // Include the implicit "this" pointer as being live. 354 CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S); 355 val.liveStmts = 356 LV.SSetFact.add(val.liveStmts, 357 CE->getImplicitObjectArgument()->IgnoreParens()); 358 break; 359 } 360 case Stmt::DeclStmtClass: { 361 const DeclStmt *DS = cast<DeclStmt>(S); 362 if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) { 363 for (const VariableArrayType* VA = FindVA(VD->getType()); 364 VA != 0; VA = FindVA(VA->getElementType())) { 365 val.liveStmts = LV.SSetFact.add(val.liveStmts, 366 VA->getSizeExpr()->IgnoreParens()); 367 } 368 } 369 break; 370 } 371 // FIXME: These cases eventually shouldn't be needed. 372 case Stmt::ExprWithCleanupsClass: { 373 S = cast<ExprWithCleanups>(S)->getSubExpr(); 374 break; 375 } 376 case Stmt::CXXBindTemporaryExprClass: { 377 S = cast<CXXBindTemporaryExpr>(S)->getSubExpr(); 378 break; 379 } 380 case Stmt::UnaryExprOrTypeTraitExprClass: { 381 // No need to unconditionally visit subexpressions. 382 return; 383 } 384 } 385 386 for (Stmt::child_iterator it = S->child_begin(), ei = S->child_end(); 387 it != ei; ++it) { 388 if (Stmt *child = *it) { 389 if (Expr *Ex = dyn_cast<Expr>(child)) 390 child = Ex->IgnoreParens(); 391 392 val.liveStmts = LV.SSetFact.add(val.liveStmts, child); 393 } 394 } 395 } 396 397 void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) { 398 if (B->isAssignmentOp()) { 399 if (!LV.killAtAssign) 400 return; 401 402 // Assigning to a variable? 403 Expr *LHS = B->getLHS()->IgnoreParens(); 404 405 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) 406 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 407 // Assignments to references don't kill the ref's address 408 if (VD->getType()->isReferenceType()) 409 return; 410 411 if (!isAlwaysAlive(VD)) { 412 // The variable is now dead. 413 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); 414 } 415 416 if (observer) 417 observer->observerKill(DR); 418 } 419 } 420 } 421 422 void TransferFunctions::VisitBlockExpr(BlockExpr *BE) { 423 AnalysisContext::referenced_decls_iterator I, E; 424 llvm::tie(I, E) = 425 LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl()); 426 for ( ; I != E ; ++I) { 427 const VarDecl *VD = *I; 428 if (isAlwaysAlive(VD)) 429 continue; 430 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD); 431 } 432 } 433 434 void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) { 435 if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl())) 436 if (!isAlwaysAlive(D) && LV.inAssignment.find(DR) == LV.inAssignment.end()) 437 val.liveDecls = LV.DSetFact.add(val.liveDecls, D); 438 } 439 440 void TransferFunctions::VisitDeclStmt(DeclStmt *DS) { 441 for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end(); 442 DI != DE; ++DI) 443 if (VarDecl *VD = dyn_cast<VarDecl>(*DI)) { 444 if (!isAlwaysAlive(VD)) 445 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); 446 } 447 } 448 449 void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) { 450 // Kill the iteration variable. 451 DeclRefExpr *DR = 0; 452 const VarDecl *VD = 0; 453 454 Stmt *element = OS->getElement(); 455 if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) { 456 VD = cast<VarDecl>(DS->getSingleDecl()); 457 } 458 else if ((DR = dyn_cast<DeclRefExpr>(cast<Expr>(element)->IgnoreParens()))) { 459 VD = cast<VarDecl>(DR->getDecl()); 460 } 461 462 if (VD) { 463 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); 464 if (observer && DR) 465 observer->observerKill(DR); 466 } 467 } 468 469 void TransferFunctions:: 470 VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE) 471 { 472 // While sizeof(var) doesn't technically extend the liveness of 'var', it 473 // does extent the liveness of metadata if 'var' is a VariableArrayType. 474 // We handle that special case here. 475 if (UE->getKind() != UETT_SizeOf || UE->isArgumentType()) 476 return; 477 478 const Expr *subEx = UE->getArgumentExpr(); 479 if (subEx->getType()->isVariableArrayType()) { 480 assert(subEx->isLValue()); 481 val.liveStmts = LV.SSetFact.add(val.liveStmts, subEx->IgnoreParens()); 482 } 483 } 484 485 void TransferFunctions::VisitUnaryOperator(UnaryOperator *UO) { 486 // Treat ++/-- as a kill. 487 // Note we don't actually have to do anything if we don't have an observer, 488 // since a ++/-- acts as both a kill and a "use". 489 if (!observer) 490 return; 491 492 switch (UO->getOpcode()) { 493 default: 494 return; 495 case UO_PostInc: 496 case UO_PostDec: 497 case UO_PreInc: 498 case UO_PreDec: 499 break; 500 } 501 502 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParens())) 503 if (isa<VarDecl>(DR->getDecl())) { 504 // Treat ++/-- as a kill. 505 observer->observerKill(DR); 506 } 507 } 508 509 LiveVariables::LivenessValues 510 LiveVariablesImpl::runOnBlock(const CFGBlock *block, 511 LiveVariables::LivenessValues val, 512 LiveVariables::Observer *obs) { 513 514 TransferFunctions TF(*this, val, obs, block); 515 516 // Visit the terminator (if any). 517 if (const Stmt *term = block->getTerminator()) 518 TF.Visit(const_cast<Stmt*>(term)); 519 520 // Apply the transfer function for all Stmts in the block. 521 for (CFGBlock::const_reverse_iterator it = block->rbegin(), 522 ei = block->rend(); it != ei; ++it) { 523 const CFGElement &elem = *it; 524 if (!isa<CFGStmt>(elem)) 525 continue; 526 527 const Stmt *S = cast<CFGStmt>(elem).getStmt(); 528 TF.Visit(const_cast<Stmt*>(S)); 529 stmtsToLiveness[S] = val; 530 } 531 return val; 532 } 533 534 void LiveVariables::runOnAllBlocks(LiveVariables::Observer &obs) { 535 const CFG *cfg = getImpl(impl).analysisContext.getCFG(); 536 for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) 537 getImpl(impl).runOnBlock(*it, getImpl(impl).blocksEndToLiveness[*it], &obs); 538 } 539 540 LiveVariables::LiveVariables(void *im) : impl(im) {} 541 542 LiveVariables::~LiveVariables() { 543 delete (LiveVariablesImpl*) impl; 544 } 545 546 LiveVariables * 547 LiveVariables::computeLiveness(AnalysisContext &AC, 548 bool killAtAssign) { 549 550 // No CFG? Bail out. 551 CFG *cfg = AC.getCFG(); 552 if (!cfg) 553 return 0; 554 555 LiveVariablesImpl *LV = new LiveVariablesImpl(AC, killAtAssign); 556 557 // Construct the dataflow worklist. Enqueue the exit block as the 558 // start of the analysis. 559 DataflowWorklist worklist(*cfg); 560 llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs()); 561 562 // FIXME: we should enqueue using post order. 563 for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) { 564 const CFGBlock *block = *it; 565 worklist.enqueueBlock(block); 566 567 // FIXME: Scan for DeclRefExprs using in the LHS of an assignment. 568 // We need to do this because we lack context in the reverse analysis 569 // to determine if a DeclRefExpr appears in such a context, and thus 570 // doesn't constitute a "use". 571 if (killAtAssign) 572 for (CFGBlock::const_iterator bi = block->begin(), be = block->end(); 573 bi != be; ++bi) { 574 if (const CFGStmt *cs = bi->getAs<CFGStmt>()) { 575 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(cs->getStmt())) { 576 if (BO->getOpcode() == BO_Assign) { 577 if (const DeclRefExpr *DR = 578 dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) { 579 LV->inAssignment[DR] = 1; 580 } 581 } 582 } 583 } 584 } 585 } 586 587 worklist.sortWorklist(); 588 589 while (const CFGBlock *block = worklist.dequeue()) { 590 // Determine if the block's end value has changed. If not, we 591 // have nothing left to do for this block. 592 LivenessValues &prevVal = LV->blocksEndToLiveness[block]; 593 594 // Merge the values of all successor blocks. 595 LivenessValues val; 596 for (CFGBlock::const_succ_iterator it = block->succ_begin(), 597 ei = block->succ_end(); it != ei; ++it) { 598 if (const CFGBlock *succ = *it) { 599 val = LV->merge(val, LV->blocksBeginToLiveness[succ]); 600 } 601 } 602 603 if (!everAnalyzedBlock[block->getBlockID()]) 604 everAnalyzedBlock[block->getBlockID()] = true; 605 else if (prevVal.equals(val)) 606 continue; 607 608 prevVal = val; 609 610 // Update the dataflow value for the start of this block. 611 LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val); 612 613 // Enqueue the value to the predecessors. 614 worklist.enqueuePredecessors(block); 615 } 616 617 return new LiveVariables(LV); 618 } 619 620 static bool compare_entries(const CFGBlock *A, const CFGBlock *B) { 621 return A->getBlockID() < B->getBlockID(); 622 } 623 624 static bool compare_vd_entries(const Decl *A, const Decl *B) { 625 SourceLocation ALoc = A->getLocStart(); 626 SourceLocation BLoc = B->getLocStart(); 627 return ALoc.getRawEncoding() < BLoc.getRawEncoding(); 628 } 629 630 void LiveVariables::dumpBlockLiveness(const SourceManager &M) { 631 getImpl(impl).dumpBlockLiveness(M); 632 } 633 634 void LiveVariablesImpl::dumpBlockLiveness(const SourceManager &M) { 635 std::vector<const CFGBlock *> vec; 636 for (llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues>::iterator 637 it = blocksEndToLiveness.begin(), ei = blocksEndToLiveness.end(); 638 it != ei; ++it) { 639 vec.push_back(it->first); 640 } 641 std::sort(vec.begin(), vec.end(), compare_entries); 642 643 std::vector<const VarDecl*> declVec; 644 645 for (std::vector<const CFGBlock *>::iterator 646 it = vec.begin(), ei = vec.end(); it != ei; ++it) { 647 llvm::errs() << "\n[ B" << (*it)->getBlockID() 648 << " (live variables at block exit) ]\n"; 649 650 LiveVariables::LivenessValues vals = blocksEndToLiveness[*it]; 651 declVec.clear(); 652 653 for (llvm::ImmutableSet<const VarDecl *>::iterator si = 654 vals.liveDecls.begin(), 655 se = vals.liveDecls.end(); si != se; ++si) { 656 declVec.push_back(*si); 657 } 658 659 std::sort(declVec.begin(), declVec.end(), compare_vd_entries); 660 661 for (std::vector<const VarDecl*>::iterator di = declVec.begin(), 662 de = declVec.end(); di != de; ++di) { 663 llvm::errs() << " " << (*di)->getDeclName().getAsString() 664 << " <"; 665 (*di)->getLocation().dump(M); 666 llvm::errs() << ">\n"; 667 } 668 } 669 llvm::errs() << "\n"; 670 } 671 672