20#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/DenseSet.h"
22#include "llvm/ADT/STLExtras.h"
23#include "llvm/Support/raw_ostream.h"
30class LiveVariablesImpl {
32 AnalysisDeclContext &analysisContext;
33 llvm::ImmutableSet<const Expr *>::Factory ESetFact;
34 llvm::ImmutableSet<const VarDecl *>::Factory DSetFact;
35 llvm::ImmutableSet<const BindingDecl *>::Factory BSetFact;
36 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness;
37 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness;
38 llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness;
39 llvm::DenseSet<const DeclRefExpr *> inAssignment;
40 const bool killAtAssign;
42 LiveVariables::LivenessValues
43 merge(LiveVariables::LivenessValues valsA,
44 LiveVariables::LivenessValues valsB);
46 LiveVariables::LivenessValues
47 runOnBlock(
const CFGBlock *block, LiveVariables::LivenessValues val,
48 LiveVariables::Observer *obs =
nullptr);
50 void dumpBlockLiveness(
const SourceManager& M);
51 void dumpExprLiveness(
const SourceManager& M);
53 LiveVariablesImpl(AnalysisDeclContext &ac,
bool KillAtAssign)
54 : analysisContext(ac),
57 BSetFact(
false), killAtAssign(KillAtAssign) {}
61static LiveVariablesImpl &
getImpl(
void *x) {
62 return *((LiveVariablesImpl *) x);
74 if (
const auto *DD = dyn_cast<DecompositionDecl>(D)) {
91 template <
typename SET>
92 SET mergeSets(SET A, SET B) {
96 for (
const auto *Elem : B) {
103void LiveVariables::Observer::anchor() { }
105LiveVariables::LivenessValues
106LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA,
107 LiveVariables::LivenessValues valsB) {
109 llvm::ImmutableSetRef<const Expr *> SSetRefA(
110 valsA.
liveExprs.getRootWithoutRetain(), ESetFact.getTreeFactory()),
111 SSetRefB(valsB.
liveExprs.getRootWithoutRetain(),
112 ESetFact.getTreeFactory());
114 llvm::ImmutableSetRef<const VarDecl *>
115 DSetRefA(valsA.
liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()),
116 DSetRefB(valsB.
liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory());
118 llvm::ImmutableSetRef<const BindingDecl *>
119 BSetRefA(valsA.
liveBindings.getRootWithoutRetain(), BSetFact.getTreeFactory()),
120 BSetRefB(valsB.
liveBindings.getRootWithoutRetain(), BSetFact.getTreeFactory());
122 SSetRefA = mergeSets(SSetRefA, SSetRefB);
123 DSetRefA = mergeSets(DSetRefA, DSetRefB);
124 BSetRefA = mergeSets(BSetRefA, BSetRefB);
128 return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(),
129 DSetRefA.asImmutableSet(),
130 BSetRefA.asImmutableSet());
155 return getImpl(impl).stmtsToLiveness[Loc].isLive(Val);
163class TransferFunctions :
public StmtVisitor<TransferFunctions> {
164 LiveVariablesImpl &LV;
169 TransferFunctions(LiveVariablesImpl &im,
173 : LV(im), val(Val), observer(Observer), currentBlock(CurrentBlock) {}
187 while (
const ArrayType *VT = dyn_cast<ArrayType>(ty)) {
189 if (VAT->getSizeExpr())
192 ty = VT->getElementType().getTypePtr();
201 if (
const FullExpr *FE = dyn_cast<FullExpr>(E)) {
202 E = FE->getSubExpr();
206 E = OVE->getSourceExpr();
215 llvm::ImmutableSet<const Expr *>::Factory &F,
226 llvm::ImmutableSet<const Expr *>::Factory &F,
229 if (
auto const *BO = dyn_cast<BinaryOperator>(
Cond->IgnoreParens());
230 BO && BO->isLogicalOp()) {
236void TransferFunctions::Visit(Stmt *S) {
238 observer->observeStmt(S, currentBlock, val);
242 if (
const auto *E = dyn_cast<Expr>(S)) {
243 val.liveExprs = LV.ESetFact.remove(val.liveExprs, E);
257 case Stmt::StmtExprClass: {
262 case Stmt::CXXMemberCallExprClass: {
266 AddLiveExpr(val.liveExprs, LV.ESetFact, ImplicitObj);
270 case Stmt::ObjCMessageExprClass: {
274 val.liveDecls = LV.DSetFact.add(val.liveDecls,
275 LV.analysisContext.getSelfDecl());
278 case Stmt::DeclStmtClass: {
280 if (
const VarDecl *VD = dyn_cast<VarDecl>(DS->
getSingleDecl())) {
281 for (
const VariableArrayType* VA =
FindVA(VD->getType());
282 VA !=
nullptr; VA =
FindVA(VA->getElementType())) {
283 AddLiveExpr(val.liveExprs, LV.ESetFact, VA->getSizeExpr());
288 case Stmt::PseudoObjectExprClass: {
293 if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
294 child = OV->getSourceExpr();
296 val.liveExprs = LV.ESetFact.add(val.liveExprs, child);
301 case Stmt::ExprWithCleanupsClass: {
305 case Stmt::CXXBindTemporaryExprClass: {
309 case Stmt::UnaryExprOrTypeTraitExprClass: {
313 case Stmt::IfStmtClass: {
320 case Stmt::WhileStmtClass: {
327 case Stmt::DoStmtClass: {
334 case Stmt::ForStmtClass: {
341 case Stmt::ConditionalOperatorClass: {
358 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getTrueExpr());
359 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getFalseExpr());
366 if (
const auto *E = dyn_cast_or_null<Expr>(Child))
376void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
377 if (LV.killAtAssign && B->
getOpcode() == BO_Assign) {
379 LV.inAssignment.insert(DR);
383 if (!LV.killAtAssign)
389 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
390 const Decl* D = DR->getDecl();
393 if (
const BindingDecl* BD = dyn_cast<BindingDecl>(D)) {
394 Killed = !BD->getType()->isReferenceType();
396 if (
const auto *HV = BD->getHoldingVar())
397 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
399 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
401 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
404 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
410void TransferFunctions::VisitBlockExpr(BlockExpr *BE) {
411 for (
const VarDecl *VD :
412 LV.analysisContext.getReferencedBlockVars(BE->
getBlockDecl())) {
415 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
419void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
421 bool InAssignment = LV.inAssignment.contains(DR);
422 if (
const auto *BD = dyn_cast<BindingDecl>(D)) {
424 if (
const auto *HV = BD->getHoldingVar())
425 val.liveDecls = LV.DSetFact.add(val.liveDecls, HV);
427 val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
429 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
431 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
435void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
436 for (
const auto *DI : DS->
decls()) {
437 if (
const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
438 for (
const auto *BD : DD->bindings()) {
439 if (
const auto *HV = BD->getHoldingVar())
440 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
442 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
447 val.liveDecls = LV.DSetFact.remove(val.liveDecls, DD);
448 }
else if (
const auto *VD = dyn_cast<VarDecl>(DI)) {
450 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
455void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) {
457 DeclRefExpr *DR =
nullptr;
458 const VarDecl *VD =
nullptr;
460 Stmt *element =
OS->getElement();
461 if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
464 else if ((DR = dyn_cast<DeclRefExpr>(
cast<Expr>(element)->IgnoreParens()))) {
469 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
473void TransferFunctions::
474VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE)
485 val.liveExprs = LV.ESetFact.add(val.liveExprs, subEx->
IgnoreParens());
489LiveVariables::LivenessValues
490LiveVariablesImpl::runOnBlock(
const CFGBlock *block,
491 LiveVariables::LivenessValues val,
492 LiveVariables::Observer *obs) {
494 TransferFunctions TF(*
this, val, obs, block);
498 TF.Visit(
const_cast<Stmt*
>(term));
502 ei = block->
rend(); it != ei; ++it) {
503 const CFGElement &elem = *it;
505 if (std::optional<CFGAutomaticObjDtor> Dtor =
506 elem.
getAs<CFGAutomaticObjDtor>()) {
511 if (!elem.
getAs<CFGStmt>())
514 const Stmt *S = elem.
castAs<CFGStmt>().getStmt();
515 TF.Visit(
const_cast<Stmt*
>(S));
516 stmtsToLiveness[S] = val;
524 getImpl(impl).runOnBlock(B,
getImpl(impl).blocksEndToLiveness[B], &obs);
527LiveVariables::LiveVariables(
void *im) : impl(im) {}
530 delete (LiveVariablesImpl*) impl;
533std::unique_ptr<LiveVariables>
546 LiveVariablesImpl *LV =
new LiveVariablesImpl(AC, killAtAssign);
567 val = LV->merge(val, LV->blocksBeginToLiveness[succ]);
572 everAnalyzedBlock[block->
getBlockID()] =
true;
573 else if (prevVal == val)
579 LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val);
585 return std::unique_ptr<LiveVariables>(
new LiveVariables(LV));
589 getImpl(impl).dumpBlockLiveness(M);
592void LiveVariablesImpl::dumpBlockLiveness(
const SourceManager &M) {
593 std::vector<const CFGBlock *> vec;
594 vec.reserve(blocksEndToLiveness.size());
595 llvm::append_range(vec, llvm::make_first_range(blocksEndToLiveness));
600 std::vector<const VarDecl*> declVec;
603 llvm::errs() <<
"\n[ B" << block->
getBlockID()
604 <<
" (live variables at block exit) ]\n";
606 llvm::append_range(declVec, blocksEndToLiveness[block].liveDecls);
607 llvm::sort(declVec, [](
const Decl *A,
const Decl *B) {
611 for (
const VarDecl *VD : declVec) {
614 llvm::errs() <<
">\n";
617 llvm::errs() <<
"\n";
621 getImpl(impl).dumpExprLiveness(M);
624void LiveVariablesImpl::dumpExprLiveness(
const SourceManager &M) {
625 const ASTContext &Ctx = analysisContext.getASTContext();
626 auto ByIDs = [&Ctx](
const Expr *L,
const Expr *R) {
627 return L->
getID(Ctx) < R->getID(Ctx);
631 for (
const CFGBlock *B : *analysisContext.getCFG()) {
632 llvm::errs() <<
"\n[ B" << B->getBlockID()
633 <<
" (live expressions at block exit) ]\n";
634 std::vector<const Expr *> LiveExprs;
635 llvm::append_range(LiveExprs, blocksEndToLiveness[B].liveExprs);
636 llvm::sort(LiveExprs, ByIDs);
637 for (
const Expr *E : LiveExprs) {
638 llvm::errs() <<
"\n";
641 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)
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 a single basic block in a source-level CFG.
reverse_iterator rbegin()
ElementList::const_reverse_iterator const_reverse_iterator
Stmt * getTerminatorStmt()
unsigned getBlockID() const
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()
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 getLocation() const
SourceLocation getBeginLoc() const LLVM_READONLY
std::string getAsString() const
Retrieve the human-readable string for this name.
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
bool operator==(const LivenessValues &V) const
llvm::ImmutableSet< const VarDecl * > liveDecls
bool isLive(const Expr *E) 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.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Represents Objective-C's collection statement.
@ 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()
void print(raw_ostream &OS, const SourceManager &SM) const
This class handles loading and caching of source files into memory.
void Visit(PTR(Stmt) S, ParamTys... P)
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Stmt - This represents one statement.
StmtClass getStmtClass() const
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
Represents a variable declaration or definition.
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Represents a C array with a specified size that is not an integer-constant-expression.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
U cast(CodeGen::Address addr)
A worklist implementation for backward dataflow analysis.
void enqueuePredecessors(const CFGBlock *Block)