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);
251 case Stmt::StmtExprClass: {
256 case Stmt::CXXMemberCallExprClass: {
260 AddLiveExpr(val.liveExprs, LV.ESetFact, ImplicitObj);
264 case Stmt::ObjCMessageExprClass: {
268 val.liveDecls = LV.DSetFact.add(val.liveDecls,
269 LV.analysisContext.getSelfDecl());
272 case Stmt::DeclStmtClass: {
274 if (
const VarDecl *VD = dyn_cast<VarDecl>(DS->
getSingleDecl())) {
275 for (
const VariableArrayType* VA =
FindVA(VD->getType());
276 VA !=
nullptr; VA =
FindVA(VA->getElementType())) {
277 AddLiveExpr(val.liveExprs, LV.ESetFact, VA->getSizeExpr());
282 case Stmt::PseudoObjectExprClass: {
287 if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
288 child = OV->getSourceExpr();
290 val.liveExprs = LV.ESetFact.add(val.liveExprs, child);
295 case Stmt::ExprWithCleanupsClass: {
299 case Stmt::CXXBindTemporaryExprClass: {
303 case Stmt::UnaryExprOrTypeTraitExprClass: {
307 case Stmt::IfStmtClass: {
314 case Stmt::WhileStmtClass: {
321 case Stmt::DoStmtClass: {
328 case Stmt::ForStmtClass: {
335 case Stmt::ConditionalOperatorClass: {
352 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getTrueExpr());
353 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getFalseExpr());
362 if (
const auto *E = dyn_cast_or_null<Expr>(Child))
372void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
373 if (LV.killAtAssign && B->
getOpcode() == BO_Assign) {
375 LV.inAssignment.insert(DR);
379 if (!LV.killAtAssign)
385 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
386 const Decl* D = DR->getDecl();
389 if (
const BindingDecl* BD = dyn_cast<BindingDecl>(D)) {
390 Killed = !BD->getType()->isReferenceType();
392 if (
const auto *HV = BD->getHoldingVar())
393 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
395 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
397 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
400 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
406void TransferFunctions::VisitBlockExpr(BlockExpr *BE) {
407 for (
const VarDecl *VD :
408 LV.analysisContext.getReferencedBlockVars(BE->
getBlockDecl())) {
411 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
415void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
417 bool InAssignment = LV.inAssignment.contains(DR);
418 if (
const auto *BD = dyn_cast<BindingDecl>(D)) {
420 if (
const auto *HV = BD->getHoldingVar())
421 val.liveDecls = LV.DSetFact.add(val.liveDecls, HV);
423 val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
425 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
427 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
431void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
432 for (
const auto *DI : DS->
decls()) {
433 if (
const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
434 for (
const auto *BD : DD->bindings()) {
435 if (
const auto *HV = BD->getHoldingVar())
436 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
438 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
443 val.liveDecls = LV.DSetFact.remove(val.liveDecls, DD);
444 }
else if (
const auto *VD = dyn_cast<VarDecl>(DI)) {
446 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
451void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) {
453 DeclRefExpr *DR =
nullptr;
454 const VarDecl *VD =
nullptr;
456 Stmt *element =
OS->getElement();
457 if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
460 else if ((DR = dyn_cast<DeclRefExpr>(
cast<Expr>(element)->IgnoreParens()))) {
465 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
469void TransferFunctions::
470VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE)
481 val.liveExprs = LV.ESetFact.add(val.liveExprs, subEx->
IgnoreParens());
485LiveVariables::LivenessValues
486LiveVariablesImpl::runOnBlock(
const CFGBlock *block,
487 LiveVariables::LivenessValues val,
488 LiveVariables::Observer *obs) {
490 TransferFunctions TF(*
this, val, obs, block);
494 TF.Visit(
const_cast<Stmt*
>(term));
498 ei = block->
rend(); it != ei; ++it) {
499 const CFGElement &elem = *it;
501 if (std::optional<CFGAutomaticObjDtor> Dtor =
502 elem.
getAs<CFGAutomaticObjDtor>()) {
507 if (!elem.
getAs<CFGStmt>())
510 const Stmt *S = elem.
castAs<CFGStmt>().getStmt();
511 TF.Visit(
const_cast<Stmt*
>(S));
512 stmtsToLiveness[S] = val;
520 getImpl(impl).runOnBlock(B,
getImpl(impl).blocksEndToLiveness[B], &obs);
523LiveVariables::LiveVariables(
void *im) : impl(im) {}
526 delete (LiveVariablesImpl*) impl;
529std::unique_ptr<LiveVariables>
542 LiveVariablesImpl *LV =
new LiveVariablesImpl(AC, killAtAssign);
563 val = LV->merge(val, LV->blocksBeginToLiveness[succ]);
568 everAnalyzedBlock[block->
getBlockID()] =
true;
569 else if (prevVal == val)
575 LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val);
581 return std::unique_ptr<LiveVariables>(
new LiveVariables(LV));
585 getImpl(impl).dumpBlockLiveness(M);
588void LiveVariablesImpl::dumpBlockLiveness(
const SourceManager &M) {
589 std::vector<const CFGBlock *> vec;
590 vec.reserve(blocksEndToLiveness.size());
591 llvm::append_range(vec, llvm::make_first_range(blocksEndToLiveness));
596 std::vector<const VarDecl*> declVec;
599 llvm::errs() <<
"\n[ B" << block->
getBlockID()
600 <<
" (live variables at block exit) ]\n";
602 llvm::append_range(declVec, blocksEndToLiveness[block].liveDecls);
603 llvm::sort(declVec, [](
const Decl *A,
const Decl *B) {
607 for (
const VarDecl *VD : declVec) {
610 llvm::errs() <<
">\n";
613 llvm::errs() <<
"\n";
617 getImpl(impl).dumpExprLiveness(M);
620void LiveVariablesImpl::dumpExprLiveness(
const SourceManager &M) {
621 const ASTContext &Ctx = analysisContext.getASTContext();
622 auto ByIDs = [&Ctx](
const Expr *L,
const Expr *R) {
623 return L->
getID(Ctx) < R->getID(Ctx);
627 for (
const CFGBlock *B : *analysisContext.getCFG()) {
628 llvm::errs() <<
"\n[ B" << B->getBlockID()
629 <<
" (live expressions at block exit) ]\n";
630 std::vector<const Expr *> LiveExprs;
631 llvm::append_range(LiveExprs, blocksEndToLiveness[B].liveExprs);
632 llvm::sort(LiveExprs, ByIDs);
633 for (
const Expr *E : LiveExprs) {
634 llvm::errs() <<
"\n";
637 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)