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();
200 if (
const Expr *Ex = dyn_cast<Expr>(E))
202 if (
const FullExpr *FE = dyn_cast<FullExpr>(E)) {
203 E = FE->getSubExpr();
207 E = OVE->getSourceExpr();
216 llvm::ImmutableSet<const Expr *>::Factory &F,
227 llvm::ImmutableSet<const Expr *>::Factory &F,
230 if (
auto const *BO = dyn_cast<BinaryOperator>(
Cond->IgnoreParens());
231 BO && BO->isLogicalOp()) {
237void TransferFunctions::Visit(Stmt *S) {
239 observer->observeStmt(S, currentBlock, val);
243 if (
const auto *E = dyn_cast<Expr>(S)) {
244 val.liveExprs = LV.ESetFact.remove(val.liveExprs, E);
252 case Stmt::StmtExprClass: {
257 case Stmt::CXXMemberCallExprClass: {
261 AddLiveExpr(val.liveExprs, LV.ESetFact, ImplicitObj);
265 case Stmt::ObjCMessageExprClass: {
269 val.liveDecls = LV.DSetFact.add(val.liveDecls,
270 LV.analysisContext.getSelfDecl());
273 case Stmt::DeclStmtClass: {
275 if (
const VarDecl *VD = dyn_cast<VarDecl>(DS->
getSingleDecl())) {
276 for (
const VariableArrayType* VA =
FindVA(VD->getType());
277 VA !=
nullptr; VA =
FindVA(VA->getElementType())) {
278 AddLiveExpr(val.liveExprs, LV.ESetFact, VA->getSizeExpr());
283 case Stmt::PseudoObjectExprClass: {
288 if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
289 child = OV->getSourceExpr();
291 val.liveExprs = LV.ESetFact.add(val.liveExprs, child);
296 case Stmt::ExprWithCleanupsClass: {
300 case Stmt::CXXBindTemporaryExprClass: {
304 case Stmt::UnaryExprOrTypeTraitExprClass: {
308 case Stmt::IfStmtClass: {
315 case Stmt::WhileStmtClass: {
322 case Stmt::DoStmtClass: {
329 case Stmt::ForStmtClass: {
336 case Stmt::ConditionalOperatorClass: {
353 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getTrueExpr());
354 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getFalseExpr());
363 if (
const auto *E = dyn_cast_or_null<Expr>(Child))
373void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
374 if (LV.killAtAssign && B->
getOpcode() == BO_Assign) {
376 LV.inAssignment.insert(DR);
380 if (!LV.killAtAssign)
386 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
387 const Decl* D = DR->getDecl();
390 if (
const BindingDecl* BD = dyn_cast<BindingDecl>(D)) {
391 Killed = !BD->getType()->isReferenceType();
393 if (
const auto *HV = BD->getHoldingVar())
394 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
396 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
398 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
401 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
407void TransferFunctions::VisitBlockExpr(BlockExpr *BE) {
408 for (
const VarDecl *VD :
409 LV.analysisContext.getReferencedBlockVars(BE->
getBlockDecl())) {
412 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
416void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
418 bool InAssignment = LV.inAssignment.contains(DR);
419 if (
const auto *BD = dyn_cast<BindingDecl>(D)) {
421 if (
const auto *HV = BD->getHoldingVar())
422 val.liveDecls = LV.DSetFact.add(val.liveDecls, HV);
424 val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
426 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
428 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
432void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
433 for (
const auto *DI : DS->
decls()) {
434 if (
const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
435 for (
const auto *BD : DD->bindings()) {
436 if (
const auto *HV = BD->getHoldingVar())
437 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
439 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
444 val.liveDecls = LV.DSetFact.remove(val.liveDecls, DD);
445 }
else if (
const auto *VD = dyn_cast<VarDecl>(DI)) {
447 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
452void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) {
454 DeclRefExpr *DR =
nullptr;
455 const VarDecl *VD =
nullptr;
457 Stmt *element =
OS->getElement();
458 if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
461 else if ((DR = dyn_cast<DeclRefExpr>(
cast<Expr>(element)->IgnoreParens()))) {
466 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
470void TransferFunctions::
471VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE)
482 val.liveExprs = LV.ESetFact.add(val.liveExprs, subEx->
IgnoreParens());
486LiveVariables::LivenessValues
487LiveVariablesImpl::runOnBlock(
const CFGBlock *block,
488 LiveVariables::LivenessValues val,
489 LiveVariables::Observer *obs) {
491 TransferFunctions TF(*
this, val, obs, block);
495 TF.Visit(
const_cast<Stmt*
>(term));
499 ei = block->
rend(); it != ei; ++it) {
500 const CFGElement &elem = *it;
502 if (std::optional<CFGAutomaticObjDtor> Dtor =
503 elem.
getAs<CFGAutomaticObjDtor>()) {
508 if (!elem.
getAs<CFGStmt>())
511 const Stmt *S = elem.
castAs<CFGStmt>().getStmt();
512 TF.Visit(
const_cast<Stmt*
>(S));
513 stmtsToLiveness[S] = val;
521 getImpl(impl).runOnBlock(B,
getImpl(impl).blocksEndToLiveness[B], &obs);
524LiveVariables::LiveVariables(
void *im) : impl(im) {}
527 delete (LiveVariablesImpl*) impl;
530std::unique_ptr<LiveVariables>
543 LiveVariablesImpl *LV =
new LiveVariablesImpl(AC, killAtAssign);
564 val = LV->merge(val, LV->blocksBeginToLiveness[succ]);
569 everAnalyzedBlock[block->
getBlockID()] =
true;
570 else if (prevVal == val)
576 LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val);
582 return std::unique_ptr<LiveVariables>(
new LiveVariables(LV));
586 getImpl(impl).dumpBlockLiveness(M);
589void LiveVariablesImpl::dumpBlockLiveness(
const SourceManager &M) {
590 std::vector<const CFGBlock *> vec;
591 vec.reserve(blocksEndToLiveness.size());
592 llvm::append_range(vec, llvm::make_first_range(blocksEndToLiveness));
597 std::vector<const VarDecl*> declVec;
600 llvm::errs() <<
"\n[ B" << block->
getBlockID()
601 <<
" (live variables at block exit) ]\n";
603 llvm::append_range(declVec, blocksEndToLiveness[block].liveDecls);
604 llvm::sort(declVec, [](
const Decl *A,
const Decl *B) {
608 for (
const VarDecl *VD : declVec) {
611 llvm::errs() <<
">\n";
614 llvm::errs() <<
"\n";
618 getImpl(impl).dumpExprLiveness(M);
621void LiveVariablesImpl::dumpExprLiveness(
const SourceManager &M) {
622 const ASTContext &Ctx = analysisContext.getASTContext();
623 auto ByIDs = [&Ctx](
const Expr *L,
const Expr *R) {
624 return L->
getID(Ctx) < R->getID(Ctx);
628 for (
const CFGBlock *B : *analysisContext.getCFG()) {
629 llvm::errs() <<
"\n[ B" << B->getBlockID()
630 <<
" (live expressions at block exit) ]\n";
631 std::vector<const Expr *> LiveExprs;
632 llvm::append_range(LiveExprs, blocksEndToLiveness[B].liveExprs);
633 llvm::sort(LiveExprs, ByIDs);
634 for (
const Expr *E : LiveExprs) {
635 llvm::errs() <<
"\n";
638 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)