clang API Documentation
00001 #include "clang/Analysis/Analyses/LiveVariables.h" 00002 #include "clang/Analysis/Analyses/PostOrderCFGView.h" 00003 00004 #include "clang/AST/Stmt.h" 00005 #include "clang/Analysis/CFG.h" 00006 #include "clang/Analysis/AnalysisContext.h" 00007 #include "clang/AST/StmtVisitor.h" 00008 00009 #include "llvm/ADT/PostOrderIterator.h" 00010 #include "llvm/ADT/DenseMap.h" 00011 00012 #include <deque> 00013 #include <algorithm> 00014 #include <vector> 00015 00016 using namespace clang; 00017 00018 namespace { 00019 00020 class DataflowWorklist { 00021 SmallVector<const CFGBlock *, 20> worklist; 00022 llvm::BitVector enqueuedBlocks; 00023 PostOrderCFGView *POV; 00024 public: 00025 DataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx) 00026 : enqueuedBlocks(cfg.getNumBlockIDs()), 00027 POV(Ctx.getAnalysis<PostOrderCFGView>()) {} 00028 00029 void enqueueBlock(const CFGBlock *block); 00030 void enqueueSuccessors(const CFGBlock *block); 00031 void enqueuePredecessors(const CFGBlock *block); 00032 00033 const CFGBlock *dequeue(); 00034 00035 void sortWorklist(); 00036 }; 00037 00038 } 00039 00040 void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) { 00041 if (block && !enqueuedBlocks[block->getBlockID()]) { 00042 enqueuedBlocks[block->getBlockID()] = true; 00043 worklist.push_back(block); 00044 } 00045 } 00046 00047 void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) { 00048 const unsigned OldWorklistSize = worklist.size(); 00049 for (CFGBlock::const_succ_iterator I = block->succ_begin(), 00050 E = block->succ_end(); I != E; ++I) { 00051 enqueueBlock(*I); 00052 } 00053 00054 if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) 00055 return; 00056 00057 sortWorklist(); 00058 } 00059 00060 void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) { 00061 const unsigned OldWorklistSize = worklist.size(); 00062 for (CFGBlock::const_pred_iterator I = block->pred_begin(), 00063 E = block->pred_end(); I != E; ++I) { 00064 enqueueBlock(*I); 00065 } 00066 00067 if (OldWorklistSize == 0 || OldWorklistSize == worklist.size()) 00068 return; 00069 00070 sortWorklist(); 00071 } 00072 00073 void DataflowWorklist::sortWorklist() { 00074 std::sort(worklist.begin(), worklist.end(), POV->getComparator()); 00075 } 00076 00077 const CFGBlock *DataflowWorklist::dequeue() { 00078 if (worklist.empty()) 00079 return 0; 00080 const CFGBlock *b = worklist.back(); 00081 worklist.pop_back(); 00082 enqueuedBlocks[b->getBlockID()] = false; 00083 return b; 00084 } 00085 00086 namespace { 00087 class LiveVariablesImpl { 00088 public: 00089 AnalysisDeclContext &analysisContext; 00090 std::vector<LiveVariables::LivenessValues> cfgBlockValues; 00091 llvm::ImmutableSet<const Stmt *>::Factory SSetFact; 00092 llvm::ImmutableSet<const VarDecl *>::Factory DSetFact; 00093 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness; 00094 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness; 00095 llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness; 00096 llvm::DenseMap<const DeclRefExpr *, unsigned> inAssignment; 00097 const bool killAtAssign; 00098 00099 LiveVariables::LivenessValues 00100 merge(LiveVariables::LivenessValues valsA, 00101 LiveVariables::LivenessValues valsB); 00102 00103 LiveVariables::LivenessValues runOnBlock(const CFGBlock *block, 00104 LiveVariables::LivenessValues val, 00105 LiveVariables::Observer *obs = 0); 00106 00107 void dumpBlockLiveness(const SourceManager& M); 00108 00109 LiveVariablesImpl(AnalysisDeclContext &ac, bool KillAtAssign) 00110 : analysisContext(ac), 00111 SSetFact(false), // Do not canonicalize ImmutableSets by default. 00112 DSetFact(false), // This is a *major* performance win. 00113 killAtAssign(KillAtAssign) {} 00114 }; 00115 } 00116 00117 static LiveVariablesImpl &getImpl(void *x) { 00118 return *((LiveVariablesImpl *) x); 00119 } 00120 00121 //===----------------------------------------------------------------------===// 00122 // Operations and queries on LivenessValues. 00123 //===----------------------------------------------------------------------===// 00124 00125 bool LiveVariables::LivenessValues::isLive(const Stmt *S) const { 00126 return liveStmts.contains(S); 00127 } 00128 00129 bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const { 00130 return liveDecls.contains(D); 00131 } 00132 00133 namespace { 00134 template <typename SET> 00135 SET mergeSets(SET A, SET B) { 00136 if (A.isEmpty()) 00137 return B; 00138 00139 for (typename SET::iterator it = B.begin(), ei = B.end(); it != ei; ++it) { 00140 A = A.add(*it); 00141 } 00142 return A; 00143 } 00144 } 00145 00146 void LiveVariables::Observer::anchor() { } 00147 00148 LiveVariables::LivenessValues 00149 LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA, 00150 LiveVariables::LivenessValues valsB) { 00151 00152 llvm::ImmutableSetRef<const Stmt *> 00153 SSetRefA(valsA.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()), 00154 SSetRefB(valsB.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()); 00155 00156 00157 llvm::ImmutableSetRef<const VarDecl *> 00158 DSetRefA(valsA.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()), 00159 DSetRefB(valsB.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()); 00160 00161 00162 SSetRefA = mergeSets(SSetRefA, SSetRefB); 00163 DSetRefA = mergeSets(DSetRefA, DSetRefB); 00164 00165 // asImmutableSet() canonicalizes the tree, allowing us to do an easy 00166 // comparison afterwards. 00167 return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(), 00168 DSetRefA.asImmutableSet()); 00169 } 00170 00171 bool LiveVariables::LivenessValues::equals(const LivenessValues &V) const { 00172 return liveStmts == V.liveStmts && liveDecls == V.liveDecls; 00173 } 00174 00175 //===----------------------------------------------------------------------===// 00176 // Query methods. 00177 //===----------------------------------------------------------------------===// 00178 00179 static bool isAlwaysAlive(const VarDecl *D) { 00180 return D->hasGlobalStorage(); 00181 } 00182 00183 bool LiveVariables::isLive(const CFGBlock *B, const VarDecl *D) { 00184 return isAlwaysAlive(D) || getImpl(impl).blocksEndToLiveness[B].isLive(D); 00185 } 00186 00187 bool LiveVariables::isLive(const Stmt *S, const VarDecl *D) { 00188 return isAlwaysAlive(D) || getImpl(impl).stmtsToLiveness[S].isLive(D); 00189 } 00190 00191 bool LiveVariables::isLive(const Stmt *Loc, const Stmt *S) { 00192 return getImpl(impl).stmtsToLiveness[Loc].isLive(S); 00193 } 00194 00195 //===----------------------------------------------------------------------===// 00196 // Dataflow computation. 00197 //===----------------------------------------------------------------------===// 00198 00199 namespace { 00200 class TransferFunctions : public StmtVisitor<TransferFunctions> { 00201 LiveVariablesImpl &LV; 00202 LiveVariables::LivenessValues &val; 00203 LiveVariables::Observer *observer; 00204 const CFGBlock *currentBlock; 00205 public: 00206 TransferFunctions(LiveVariablesImpl &im, 00207 LiveVariables::LivenessValues &Val, 00208 LiveVariables::Observer *Observer, 00209 const CFGBlock *CurrentBlock) 00210 : LV(im), val(Val), observer(Observer), currentBlock(CurrentBlock) {} 00211 00212 void VisitBinaryOperator(BinaryOperator *BO); 00213 void VisitBlockExpr(BlockExpr *BE); 00214 void VisitDeclRefExpr(DeclRefExpr *DR); 00215 void VisitDeclStmt(DeclStmt *DS); 00216 void VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS); 00217 void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE); 00218 void VisitUnaryOperator(UnaryOperator *UO); 00219 void Visit(Stmt *S); 00220 }; 00221 } 00222 00223 static const VariableArrayType *FindVA(QualType Ty) { 00224 const Type *ty = Ty.getTypePtr(); 00225 while (const ArrayType *VT = dyn_cast<ArrayType>(ty)) { 00226 if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(VT)) 00227 if (VAT->getSizeExpr()) 00228 return VAT; 00229 00230 ty = VT->getElementType().getTypePtr(); 00231 } 00232 00233 return 0; 00234 } 00235 00236 static const Stmt *LookThroughStmt(const Stmt *S) { 00237 while (S) { 00238 if (const Expr *Ex = dyn_cast<Expr>(S)) 00239 S = Ex->IgnoreParens(); 00240 if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S)) { 00241 S = EWC->getSubExpr(); 00242 continue; 00243 } 00244 if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) { 00245 S = OVE->getSourceExpr(); 00246 continue; 00247 } 00248 break; 00249 } 00250 return S; 00251 } 00252 00253 static void AddLiveStmt(llvm::ImmutableSet<const Stmt *> &Set, 00254 llvm::ImmutableSet<const Stmt *>::Factory &F, 00255 const Stmt *S) { 00256 Set = F.add(Set, LookThroughStmt(S)); 00257 } 00258 00259 void TransferFunctions::Visit(Stmt *S) { 00260 if (observer) 00261 observer->observeStmt(S, currentBlock, val); 00262 00263 StmtVisitor<TransferFunctions>::Visit(S); 00264 00265 if (isa<Expr>(S)) { 00266 val.liveStmts = LV.SSetFact.remove(val.liveStmts, S); 00267 } 00268 00269 // Mark all children expressions live. 00270 00271 switch (S->getStmtClass()) { 00272 default: 00273 break; 00274 case Stmt::StmtExprClass: { 00275 // For statement expressions, look through the compound statement. 00276 S = cast<StmtExpr>(S)->getSubStmt(); 00277 break; 00278 } 00279 case Stmt::CXXMemberCallExprClass: { 00280 // Include the implicit "this" pointer as being live. 00281 CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S); 00282 if (Expr *ImplicitObj = CE->getImplicitObjectArgument()) { 00283 AddLiveStmt(val.liveStmts, LV.SSetFact, ImplicitObj); 00284 } 00285 break; 00286 } 00287 case Stmt::DeclStmtClass: { 00288 const DeclStmt *DS = cast<DeclStmt>(S); 00289 if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) { 00290 for (const VariableArrayType* VA = FindVA(VD->getType()); 00291 VA != 0; VA = FindVA(VA->getElementType())) { 00292 AddLiveStmt(val.liveStmts, LV.SSetFact, VA->getSizeExpr()); 00293 } 00294 } 00295 break; 00296 } 00297 case Stmt::PseudoObjectExprClass: { 00298 // A pseudo-object operation only directly consumes its result 00299 // expression. 00300 Expr *child = cast<PseudoObjectExpr>(S)->getResultExpr(); 00301 if (!child) return; 00302 if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child)) 00303 child = OV->getSourceExpr(); 00304 child = child->IgnoreParens(); 00305 val.liveStmts = LV.SSetFact.add(val.liveStmts, child); 00306 return; 00307 } 00308 00309 // FIXME: These cases eventually shouldn't be needed. 00310 case Stmt::ExprWithCleanupsClass: { 00311 S = cast<ExprWithCleanups>(S)->getSubExpr(); 00312 break; 00313 } 00314 case Stmt::CXXBindTemporaryExprClass: { 00315 S = cast<CXXBindTemporaryExpr>(S)->getSubExpr(); 00316 break; 00317 } 00318 case Stmt::UnaryExprOrTypeTraitExprClass: { 00319 // No need to unconditionally visit subexpressions. 00320 return; 00321 } 00322 } 00323 00324 for (Stmt::child_iterator it = S->child_begin(), ei = S->child_end(); 00325 it != ei; ++it) { 00326 if (Stmt *child = *it) 00327 AddLiveStmt(val.liveStmts, LV.SSetFact, child); 00328 } 00329 } 00330 00331 void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) { 00332 if (B->isAssignmentOp()) { 00333 if (!LV.killAtAssign) 00334 return; 00335 00336 // Assigning to a variable? 00337 Expr *LHS = B->getLHS()->IgnoreParens(); 00338 00339 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) 00340 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 00341 // Assignments to references don't kill the ref's address 00342 if (VD->getType()->isReferenceType()) 00343 return; 00344 00345 if (!isAlwaysAlive(VD)) { 00346 // The variable is now dead. 00347 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); 00348 } 00349 00350 if (observer) 00351 observer->observerKill(DR); 00352 } 00353 } 00354 } 00355 00356 void TransferFunctions::VisitBlockExpr(BlockExpr *BE) { 00357 AnalysisDeclContext::referenced_decls_iterator I, E; 00358 llvm::tie(I, E) = 00359 LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl()); 00360 for ( ; I != E ; ++I) { 00361 const VarDecl *VD = *I; 00362 if (isAlwaysAlive(VD)) 00363 continue; 00364 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD); 00365 } 00366 } 00367 00368 void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) { 00369 if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl())) 00370 if (!isAlwaysAlive(D) && LV.inAssignment.find(DR) == LV.inAssignment.end()) 00371 val.liveDecls = LV.DSetFact.add(val.liveDecls, D); 00372 } 00373 00374 void TransferFunctions::VisitDeclStmt(DeclStmt *DS) { 00375 for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end(); 00376 DI != DE; ++DI) 00377 if (VarDecl *VD = dyn_cast<VarDecl>(*DI)) { 00378 if (!isAlwaysAlive(VD)) 00379 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); 00380 } 00381 } 00382 00383 void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) { 00384 // Kill the iteration variable. 00385 DeclRefExpr *DR = 0; 00386 const VarDecl *VD = 0; 00387 00388 Stmt *element = OS->getElement(); 00389 if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) { 00390 VD = cast<VarDecl>(DS->getSingleDecl()); 00391 } 00392 else if ((DR = dyn_cast<DeclRefExpr>(cast<Expr>(element)->IgnoreParens()))) { 00393 VD = cast<VarDecl>(DR->getDecl()); 00394 } 00395 00396 if (VD) { 00397 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD); 00398 if (observer && DR) 00399 observer->observerKill(DR); 00400 } 00401 } 00402 00403 void TransferFunctions:: 00404 VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE) 00405 { 00406 // While sizeof(var) doesn't technically extend the liveness of 'var', it 00407 // does extent the liveness of metadata if 'var' is a VariableArrayType. 00408 // We handle that special case here. 00409 if (UE->getKind() != UETT_SizeOf || UE->isArgumentType()) 00410 return; 00411 00412 const Expr *subEx = UE->getArgumentExpr(); 00413 if (subEx->getType()->isVariableArrayType()) { 00414 assert(subEx->isLValue()); 00415 val.liveStmts = LV.SSetFact.add(val.liveStmts, subEx->IgnoreParens()); 00416 } 00417 } 00418 00419 void TransferFunctions::VisitUnaryOperator(UnaryOperator *UO) { 00420 // Treat ++/-- as a kill. 00421 // Note we don't actually have to do anything if we don't have an observer, 00422 // since a ++/-- acts as both a kill and a "use". 00423 if (!observer) 00424 return; 00425 00426 switch (UO->getOpcode()) { 00427 default: 00428 return; 00429 case UO_PostInc: 00430 case UO_PostDec: 00431 case UO_PreInc: 00432 case UO_PreDec: 00433 break; 00434 } 00435 00436 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(UO->getSubExpr()->IgnoreParens())) 00437 if (isa<VarDecl>(DR->getDecl())) { 00438 // Treat ++/-- as a kill. 00439 observer->observerKill(DR); 00440 } 00441 } 00442 00443 LiveVariables::LivenessValues 00444 LiveVariablesImpl::runOnBlock(const CFGBlock *block, 00445 LiveVariables::LivenessValues val, 00446 LiveVariables::Observer *obs) { 00447 00448 TransferFunctions TF(*this, val, obs, block); 00449 00450 // Visit the terminator (if any). 00451 if (const Stmt *term = block->getTerminator()) 00452 TF.Visit(const_cast<Stmt*>(term)); 00453 00454 // Apply the transfer function for all Stmts in the block. 00455 for (CFGBlock::const_reverse_iterator it = block->rbegin(), 00456 ei = block->rend(); it != ei; ++it) { 00457 const CFGElement &elem = *it; 00458 if (!isa<CFGStmt>(elem)) 00459 continue; 00460 00461 const Stmt *S = cast<CFGStmt>(elem).getStmt(); 00462 TF.Visit(const_cast<Stmt*>(S)); 00463 stmtsToLiveness[S] = val; 00464 } 00465 return val; 00466 } 00467 00468 void LiveVariables::runOnAllBlocks(LiveVariables::Observer &obs) { 00469 const CFG *cfg = getImpl(impl).analysisContext.getCFG(); 00470 for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) 00471 getImpl(impl).runOnBlock(*it, getImpl(impl).blocksEndToLiveness[*it], &obs); 00472 } 00473 00474 LiveVariables::LiveVariables(void *im) : impl(im) {} 00475 00476 LiveVariables::~LiveVariables() { 00477 delete (LiveVariablesImpl*) impl; 00478 } 00479 00480 LiveVariables * 00481 LiveVariables::computeLiveness(AnalysisDeclContext &AC, 00482 bool killAtAssign) { 00483 00484 // No CFG? Bail out. 00485 CFG *cfg = AC.getCFG(); 00486 if (!cfg) 00487 return 0; 00488 00489 LiveVariablesImpl *LV = new LiveVariablesImpl(AC, killAtAssign); 00490 00491 // Construct the dataflow worklist. Enqueue the exit block as the 00492 // start of the analysis. 00493 DataflowWorklist worklist(*cfg, AC); 00494 llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs()); 00495 00496 // FIXME: we should enqueue using post order. 00497 for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) { 00498 const CFGBlock *block = *it; 00499 worklist.enqueueBlock(block); 00500 00501 // FIXME: Scan for DeclRefExprs using in the LHS of an assignment. 00502 // We need to do this because we lack context in the reverse analysis 00503 // to determine if a DeclRefExpr appears in such a context, and thus 00504 // doesn't constitute a "use". 00505 if (killAtAssign) 00506 for (CFGBlock::const_iterator bi = block->begin(), be = block->end(); 00507 bi != be; ++bi) { 00508 if (const CFGStmt *cs = bi->getAs<CFGStmt>()) { 00509 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(cs->getStmt())) { 00510 if (BO->getOpcode() == BO_Assign) { 00511 if (const DeclRefExpr *DR = 00512 dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) { 00513 LV->inAssignment[DR] = 1; 00514 } 00515 } 00516 } 00517 } 00518 } 00519 } 00520 00521 worklist.sortWorklist(); 00522 00523 while (const CFGBlock *block = worklist.dequeue()) { 00524 // Determine if the block's end value has changed. If not, we 00525 // have nothing left to do for this block. 00526 LivenessValues &prevVal = LV->blocksEndToLiveness[block]; 00527 00528 // Merge the values of all successor blocks. 00529 LivenessValues val; 00530 for (CFGBlock::const_succ_iterator it = block->succ_begin(), 00531 ei = block->succ_end(); it != ei; ++it) { 00532 if (const CFGBlock *succ = *it) { 00533 val = LV->merge(val, LV->blocksBeginToLiveness[succ]); 00534 } 00535 } 00536 00537 if (!everAnalyzedBlock[block->getBlockID()]) 00538 everAnalyzedBlock[block->getBlockID()] = true; 00539 else if (prevVal.equals(val)) 00540 continue; 00541 00542 prevVal = val; 00543 00544 // Update the dataflow value for the start of this block. 00545 LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val); 00546 00547 // Enqueue the value to the predecessors. 00548 worklist.enqueuePredecessors(block); 00549 } 00550 00551 return new LiveVariables(LV); 00552 } 00553 00554 static bool compare_entries(const CFGBlock *A, const CFGBlock *B) { 00555 return A->getBlockID() < B->getBlockID(); 00556 } 00557 00558 static bool compare_vd_entries(const Decl *A, const Decl *B) { 00559 SourceLocation ALoc = A->getLocStart(); 00560 SourceLocation BLoc = B->getLocStart(); 00561 return ALoc.getRawEncoding() < BLoc.getRawEncoding(); 00562 } 00563 00564 void LiveVariables::dumpBlockLiveness(const SourceManager &M) { 00565 getImpl(impl).dumpBlockLiveness(M); 00566 } 00567 00568 void LiveVariablesImpl::dumpBlockLiveness(const SourceManager &M) { 00569 std::vector<const CFGBlock *> vec; 00570 for (llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues>::iterator 00571 it = blocksEndToLiveness.begin(), ei = blocksEndToLiveness.end(); 00572 it != ei; ++it) { 00573 vec.push_back(it->first); 00574 } 00575 std::sort(vec.begin(), vec.end(), compare_entries); 00576 00577 std::vector<const VarDecl*> declVec; 00578 00579 for (std::vector<const CFGBlock *>::iterator 00580 it = vec.begin(), ei = vec.end(); it != ei; ++it) { 00581 llvm::errs() << "\n[ B" << (*it)->getBlockID() 00582 << " (live variables at block exit) ]\n"; 00583 00584 LiveVariables::LivenessValues vals = blocksEndToLiveness[*it]; 00585 declVec.clear(); 00586 00587 for (llvm::ImmutableSet<const VarDecl *>::iterator si = 00588 vals.liveDecls.begin(), 00589 se = vals.liveDecls.end(); si != se; ++si) { 00590 declVec.push_back(*si); 00591 } 00592 00593 std::sort(declVec.begin(), declVec.end(), compare_vd_entries); 00594 00595 for (std::vector<const VarDecl*>::iterator di = declVec.begin(), 00596 de = declVec.end(); di != de; ++di) { 00597 llvm::errs() << " " << (*di)->getDeclName().getAsString() 00598 << " <"; 00599 (*di)->getLocation().dump(M); 00600 llvm::errs() << ">\n"; 00601 } 00602 } 00603 llvm::errs() << "\n"; 00604 } 00605 00606 const void *LiveVariables::getTag() { static int x; return &x; } 00607 const void *RelaxedLiveVariables::getTag() { static int x; return &x; }