20#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/STLExtras.h"
22#include "llvm/Support/raw_ostream.h"
29class LiveVariablesImpl {
32 llvm::ImmutableSet<const Expr *>::Factory ESetFact;
33 llvm::ImmutableSet<const VarDecl *>::Factory DSetFact;
34 llvm::ImmutableSet<const BindingDecl *>::Factory BSetFact;
35 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness;
36 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness;
37 llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness;
38 llvm::DenseMap<const DeclRefExpr *, unsigned> inAssignment;
39 const bool killAtAssign;
53 : analysisContext(ac),
56 BSetFact(
false), killAtAssign(KillAtAssign) {}
60static LiveVariablesImpl &
getImpl(
void *x) {
61 return *((LiveVariablesImpl *) x);
73 if (
const auto *DD = dyn_cast<DecompositionDecl>(
D)) {
76 alive |= liveBindings.contains(BD);
81 alive |= liveDecls.contains(DD);
84 return liveDecls.contains(
D);
88 template <
typename SET>
89 SET mergeSets(SET A, SET B) {
93 for (
typename SET::iterator it = B.begin(), ei = B.end(); it != ei; ++it) {
100void LiveVariables::Observer::anchor() { }
106 llvm::ImmutableSetRef<const Expr *> SSetRefA(
107 valsA.
liveExprs.getRootWithoutRetain(), ESetFact.getTreeFactory()),
108 SSetRefB(valsB.
liveExprs.getRootWithoutRetain(),
109 ESetFact.getTreeFactory());
111 llvm::ImmutableSetRef<const VarDecl *>
112 DSetRefA(valsA.
liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()),
113 DSetRefB(valsB.
liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory());
115 llvm::ImmutableSetRef<const BindingDecl *>
116 BSetRefA(valsA.
liveBindings.getRootWithoutRetain(), BSetFact.getTreeFactory()),
117 BSetRefB(valsB.
liveBindings.getRootWithoutRetain(), BSetFact.getTreeFactory());
119 SSetRefA = mergeSets(SSetRefA, SSetRefB);
120 DSetRefA = mergeSets(DSetRefA, DSetRefB);
121 BSetRefA = mergeSets(BSetRefA, BSetRefB);
126 DSetRefA.asImmutableSet(),
127 BSetRefA.asImmutableSet());
131 return liveExprs ==
V.liveExprs && liveDecls ==
V.liveDecls;
139 return D->hasGlobalStorage();
151 return getImpl(impl).stmtsToLiveness[
Loc].isLive(Val);
159class TransferFunctions :
public StmtVisitor<TransferFunctions> {
160 LiveVariablesImpl &LV;
165 TransferFunctions(LiveVariablesImpl &im,
169 : LV(im), val(Val), observer(Observer), currentBlock(
CurrentBlock) {}
184 while (
const ArrayType *VT = dyn_cast<ArrayType>(ty)) {
186 if (VAT->getSizeExpr())
189 ty = VT->getElementType().getTypePtr();
197 if (
const Expr *Ex = dyn_cast<Expr>(
E))
199 if (
const FullExpr *FE = dyn_cast<FullExpr>(
E)) {
200 E = FE->getSubExpr();
204 E = OVE->getSourceExpr();
213 llvm::ImmutableSet<const Expr *>::Factory &F,
224 llvm::ImmutableSet<const Expr *>::Factory &F,
227 if (
auto const *BO = dyn_cast<BinaryOperator>(Cond->
IgnoreParens());
228 BO && BO->isLogicalOp()) {
234void TransferFunctions::Visit(
Stmt *S) {
236 observer->observeStmt(S, currentBlock, val);
240 if (
const auto *
E = dyn_cast<Expr>(S)) {
241 val.liveExprs = LV.ESetFact.remove(val.liveExprs,
E);
246 switch (S->getStmtClass()) {
249 case Stmt::StmtExprClass: {
251 S = cast<StmtExpr>(S)->getSubStmt();
254 case Stmt::CXXMemberCallExprClass: {
258 AddLiveExpr(val.liveExprs, LV.ESetFact, ImplicitObj);
262 case Stmt::ObjCMessageExprClass: {
266 val.liveDecls = LV.DSetFact.add(val.liveDecls,
267 LV.analysisContext.getSelfDecl());
270 case Stmt::DeclStmtClass: {
271 const DeclStmt *DS = cast<DeclStmt>(S);
274 VA !=
nullptr; VA =
FindVA(VA->getElementType())) {
275 AddLiveExpr(val.liveExprs, LV.ESetFact, VA->getSizeExpr());
280 case Stmt::PseudoObjectExprClass: {
283 Expr *child = cast<PseudoObjectExpr>(S)->getResultExpr();
286 child = OV->getSourceExpr();
288 val.liveExprs = LV.ESetFact.add(val.liveExprs, child);
293 case Stmt::ExprWithCleanupsClass: {
294 S = cast<ExprWithCleanups>(S)->getSubExpr();
297 case Stmt::CXXBindTemporaryExprClass: {
298 S = cast<CXXBindTemporaryExpr>(S)->getSubExpr();
301 case Stmt::UnaryExprOrTypeTraitExprClass: {
305 case Stmt::IfStmtClass: {
309 AddLiveExpr(val.liveExprs, LV.ESetFact, cast<IfStmt>(S)->getCond());
312 case Stmt::WhileStmtClass: {
316 AddLiveExpr(val.liveExprs, LV.ESetFact, cast<WhileStmt>(S)->getCond());
319 case Stmt::DoStmtClass: {
323 AddLiveExpr(val.liveExprs, LV.ESetFact, cast<DoStmt>(S)->getCond());
326 case Stmt::ForStmtClass: {
330 AddLiveExpr(val.liveExprs, LV.ESetFact, cast<ForStmt>(S)->getCond());
333 case Stmt::ConditionalOperatorClass: {
348 auto const *CO = cast<ConditionalOperator>(S);
350 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getTrueExpr());
351 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getFalseExpr());
359 for (
Stmt *Child : S->children()) {
360 if (
const auto *
E = dyn_cast_or_null<Expr>(Child))
371 if (LV.killAtAssign && B->
getOpcode() == BO_Assign) {
373 LV.inAssignment[DR] = 1;
377 if (!LV.killAtAssign)
383 if (
DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
384 const Decl*
D = DR->getDecl();
388 Killed = !BD->getType()->isReferenceType();
390 if (
const auto *HV = BD->getHoldingVar())
391 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
393 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
395 }
else if (
const auto *VD = dyn_cast<VarDecl>(
D)) {
398 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
402 if (Killed && observer)
403 observer->observerKill(DR);
408void TransferFunctions::VisitBlockExpr(
BlockExpr *BE) {
410 LV.analysisContext.getReferencedBlockVars(BE->
getBlockDecl())) {
413 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
417void TransferFunctions::VisitDeclRefExpr(
DeclRefExpr *DR) {
419 bool InAssignment = LV.inAssignment[DR];
420 if (
const auto *BD = dyn_cast<BindingDecl>(
D)) {
422 if (
const auto *HV = BD->getHoldingVar())
423 val.liveDecls = LV.DSetFact.
add(val.liveDecls, HV);
425 val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
427 }
else if (
const auto *VD = dyn_cast<VarDecl>(
D)) {
429 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
433void TransferFunctions::VisitDeclStmt(
DeclStmt *DS) {
434 for (
const auto *DI : DS->
decls()) {
435 if (
const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
436 for (
const auto *BD : DD->bindings()) {
437 if (
const auto *HV = BD->getHoldingVar())
438 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
440 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
445 val.liveDecls = LV.DSetFact.remove(val.liveDecls, DD);
446 }
else if (
const auto *VD = dyn_cast<VarDecl>(DI)) {
448 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
458 Stmt *element = OS->getElement();
459 if (
DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
462 else if ((DR = dyn_cast<DeclRefExpr>(cast<Expr>(element)->IgnoreParens()))) {
463 VD = cast<VarDecl>(DR->
getDecl());
467 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
469 observer->observerKill(DR);
473void TransferFunctions::
485 val.liveExprs = LV.ESetFact.add(val.liveExprs, subEx->
IgnoreParens());
489void TransferFunctions::VisitUnaryOperator(
UnaryOperator *UO) {
508 if (isa<VarDecl>(
D) || isa<BindingDecl>(
D)) {
510 observer->observerKill(DR);
516LiveVariablesImpl::runOnBlock(
const CFGBlock *block,
520 TransferFunctions TF(*
this, val, obs, block);
524 TF.Visit(
const_cast<Stmt*
>(term));
528 ei = block->
rend(); it != ei; ++it) {
531 if (std::optional<CFGAutomaticObjDtor> Dtor =
541 TF.Visit(
const_cast<Stmt*
>(S));
542 stmtsToLiveness[S] = val;
548 const CFG *cfg =
getImpl(impl).analysisContext.getCFG();
550 getImpl(impl).runOnBlock(B,
getImpl(impl).blocksEndToLiveness[B], &obs);
553LiveVariables::LiveVariables(
void *im) : impl(im) {}
556 delete (LiveVariablesImpl*) impl;
559std::unique_ptr<LiveVariables>
563 CFG *cfg = AC.getCFG();
572 LiveVariablesImpl *LV =
new LiveVariablesImpl(AC, killAtAssign);
592 ei = block->
succ_end(); it != ei; ++it) {
594 val = LV->merge(val, LV->blocksBeginToLiveness[succ]);
599 everAnalyzedBlock[block->
getBlockID()] =
true;
600 else if (prevVal.
equals(val))
606 LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val);
612 return std::unique_ptr<LiveVariables>(
new LiveVariables(LV));
616 getImpl(impl).dumpBlockLiveness(M);
619void LiveVariablesImpl::dumpBlockLiveness(
const SourceManager &M) {
620 std::vector<const CFGBlock *> vec;
621 for (
const auto &KV : blocksEndToLiveness) {
622 vec.push_back(KV.first);
628 std::vector<const VarDecl*> declVec;
630 for (std::vector<const CFGBlock *>::iterator
631 it = vec.begin(), ei = vec.end(); it != ei; ++it) {
632 llvm::errs() <<
"\n[ B" << (*it)->getBlockID()
633 <<
" (live variables at block exit) ]\n";
638 for (llvm::ImmutableSet<const VarDecl *>::iterator si =
640 se = vals.
liveDecls.end(); si != se; ++si) {
641 declVec.push_back(*si);
644 llvm::sort(declVec, [](
const Decl *A,
const Decl *B) {
648 for (std::vector<const VarDecl*>::iterator di = declVec.begin(),
649 de = declVec.end(); di != de; ++di) {
650 llvm::errs() <<
" " << (*di)->getDeclName().getAsString()
652 (*di)->getLocation().print(llvm::errs(), M);
653 llvm::errs() <<
">\n";
656 llvm::errs() <<
"\n";
660 getImpl(impl).dumpExprLiveness(M);
663void LiveVariablesImpl::dumpExprLiveness(
const SourceManager &M) {
664 const ASTContext &Ctx = analysisContext.getASTContext();
665 auto ByIDs = [&Ctx](
const Expr *L,
const Expr *R) {
666 return L->
getID(Ctx) < R->getID(Ctx);
670 for (
const CFGBlock *B : *analysisContext.getCFG()) {
671 llvm::errs() <<
"\n[ B" << B->getBlockID()
672 <<
" (live expressions at block exit) ]\n";
673 std::vector<const Expr *> LiveExprs;
674 llvm::append_range(LiveExprs, blocksEndToLiveness[B].liveExprs);
675 llvm::sort(LiveExprs, ByIDs);
676 for (
const Expr *
E : LiveExprs) {
677 llvm::errs() <<
"\n";
680 llvm::errs() <<
"\n";
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static const VariableArrayType * FindVA(const Type *t)
static bool writeShouldKill(const VarDecl *VD)
static void AddLiveExpr(llvm::ImmutableSet< const Expr * > &Set, llvm::ImmutableSet< const Expr * >::Factory &F, const Expr *E)
static LiveVariablesImpl & getImpl(void *x)
static const Expr * LookThroughExpr(const Expr *E)
static void AddAllConditionalTerms(llvm::ImmutableSet< const Expr * > &Set, llvm::ImmutableSet< const Expr * >::Factory &F, const Expr *Cond)
Add as a live expression all individual conditions in a logical expression.
static bool isAlwaysAlive(const VarDecl *D)
const CFGBlock * CurrentBlock
Defines the SourceManager interface.
static bool runOnBlock(const CFGBlock *block, const CFG &cfg, AnalysisDeclContext &ac, CFGBlockValues &vals, const ClassifyRefs &classification, llvm::BitVector &wasAnalyzed, UninitVariablesHandler &handler)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Represents an array type, per C99 6.7.5.2 - Array Declarators.
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isAssignmentOp(Opcode Opc)
A binding in a decomposition declaration.
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
Represents C++ object destructor implicitly generated for automatic object or temporary bound to cons...
Represents a single basic block in a source-level CFG.
reverse_iterator rbegin()
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
unsigned getBlockID() const
AdjacentBlocks::const_iterator const_succ_iterator
Represents a top-level expression in a basic block.
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
llvm::iterator_range< iterator > nodes()
Represents a call to a member function that may be written either with member call syntax (e....
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
void enqueueBlock(const CFGBlock *Block)
const CFGBlock * dequeue()
A reference to a declared variable, function, enum, etc.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
const Decl * getSingleDecl() const
Decl - This represents one declaration (or definition), e.g.
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
FullExpr - Represents a "full-expression" node.
llvm::ImmutableSet< const BindingDecl * > liveBindings
llvm::ImmutableSet< const Expr * > liveExprs
llvm::ImmutableSet< const VarDecl * > liveDecls
bool isLive(const Expr *E) const
bool equals(const LivenessValues &V) const
void dumpExprLiveness(const SourceManager &M)
Print to stderr the expression liveness information associated with each basic block.
void dumpBlockLiveness(const SourceManager &M)
Print to stderr the variable liveness information associated with each basic block.
void runOnAllBlocks(Observer &obs)
~LiveVariables() override
static const void * getTag()
bool isLive(const CFGBlock *B, const VarDecl *D)
Return true if a variable is live at the end of a specified block.
static std::unique_ptr< LiveVariables > computeLiveness(AnalysisDeclContext &analysisContext, bool killAtAssign)
Compute the liveness information for a given CFG.
Represents Objective-C's collection statement.
An expression that sends a message to the given Objective-C object or class.
@ SuperInstance
The receiver is the instance of the superclass object.
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
static const void * getTag()
This class handles loading and caching of source files into memory.
RetTy Visit(PTR(Stmt) S, ParamTys... P)
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Stmt - This represents one statement.
void dump() const
Dumps the specified AST fragment and all subtrees to llvm::errs().
int64_t getID(const ASTContext &Context) const
The base class of the type hierarchy.
bool isReferenceType() const
bool isVariableArrayType() const
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
bool isArgumentType() const
UnaryExprOrTypeTrait getKind() const
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
Represents a variable declaration or definition.
Represents a C array with a specified size that is not an integer-constant-expression.
The JSON file list parser is used to communicate input to InstallAPI.
A worklist implementation for backward dataflow analysis.
void enqueuePredecessors(const CFGBlock *Block)