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::AttributedStmtClass: {
293 AddLiveExpr(val.liveExprs, LV.ESetFact, Attr->getAssumption());
297 case Stmt::PseudoObjectExprClass: {
302 if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
303 child = OV->getSourceExpr();
305 val.liveExprs = LV.ESetFact.add(val.liveExprs, child);
310 case Stmt::ExprWithCleanupsClass: {
314 case Stmt::CXXBindTemporaryExprClass: {
318 case Stmt::UnaryExprOrTypeTraitExprClass: {
322 case Stmt::IfStmtClass: {
329 case Stmt::WhileStmtClass: {
336 case Stmt::DoStmtClass: {
343 case Stmt::ForStmtClass: {
350 case Stmt::ConditionalOperatorClass: {
367 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getTrueExpr());
368 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getFalseExpr());
375 if (
const auto *E = dyn_cast_or_null<Expr>(Child))
385void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
386 if (LV.killAtAssign && B->
getOpcode() == BO_Assign) {
388 LV.inAssignment.insert(DR);
392 if (!LV.killAtAssign)
398 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
399 const Decl* D = DR->getDecl();
402 if (
const BindingDecl* BD = dyn_cast<BindingDecl>(D)) {
403 Killed = !BD->getType()->isReferenceType();
405 if (
const auto *HV = BD->getHoldingVar())
406 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
408 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
410 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
413 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
419void TransferFunctions::VisitBlockExpr(BlockExpr *BE) {
420 for (
const VarDecl *VD :
421 LV.analysisContext.getReferencedBlockVars(BE->
getBlockDecl())) {
424 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
428void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
430 bool InAssignment = LV.inAssignment.contains(DR);
431 if (
const auto *BD = dyn_cast<BindingDecl>(D)) {
433 if (
const auto *HV = BD->getHoldingVar())
434 val.liveDecls = LV.DSetFact.add(val.liveDecls, HV);
436 val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
438 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
440 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
444void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
445 for (
const auto *DI : DS->
decls()) {
446 if (
const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
447 for (
const auto *BD : DD->bindings()) {
448 if (
const auto *HV = BD->getHoldingVar())
449 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
451 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
456 val.liveDecls = LV.DSetFact.remove(val.liveDecls, DD);
457 }
else if (
const auto *VD = dyn_cast<VarDecl>(DI)) {
459 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
464void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) {
466 DeclRefExpr *DR =
nullptr;
467 const VarDecl *VD =
nullptr;
469 Stmt *element =
OS->getElement();
470 if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
473 else if ((DR = dyn_cast<DeclRefExpr>(
cast<Expr>(element)->IgnoreParens()))) {
478 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
482void TransferFunctions::
483VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE)
494 val.liveExprs = LV.ESetFact.add(val.liveExprs, subEx->
IgnoreParens());
498LiveVariables::LivenessValues
499LiveVariablesImpl::runOnBlock(
const CFGBlock *block,
500 LiveVariables::LivenessValues val,
501 LiveVariables::Observer *obs) {
503 TransferFunctions TF(*
this, val, obs, block);
507 TF.Visit(
const_cast<Stmt*
>(term));
511 ei = block->
rend(); it != ei; ++it) {
512 const CFGElement &elem = *it;
514 if (std::optional<CFGAutomaticObjDtor> Dtor =
515 elem.
getAs<CFGAutomaticObjDtor>()) {
520 if (!elem.
getAs<CFGStmt>())
523 const Stmt *S = elem.
castAs<CFGStmt>().getStmt();
524 TF.Visit(
const_cast<Stmt*
>(S));
525 stmtsToLiveness[S] = val;
533 getImpl(impl).runOnBlock(B,
getImpl(impl).blocksEndToLiveness[B], &obs);
536LiveVariables::LiveVariables(
void *im) : impl(im) {}
539 delete (LiveVariablesImpl*) impl;
542std::unique_ptr<LiveVariables>
555 LiveVariablesImpl *LV =
new LiveVariablesImpl(AC, killAtAssign);
576 val = LV->merge(val, LV->blocksBeginToLiveness[succ]);
581 everAnalyzedBlock[block->
getBlockID()] =
true;
582 else if (prevVal == val)
588 LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val);
594 return std::unique_ptr<LiveVariables>(
new LiveVariables(LV));
598 getImpl(impl).dumpBlockLiveness(M);
601void LiveVariablesImpl::dumpBlockLiveness(
const SourceManager &M) {
602 std::vector<const CFGBlock *> vec;
603 vec.reserve(blocksEndToLiveness.size());
604 llvm::append_range(vec, llvm::make_first_range(blocksEndToLiveness));
609 std::vector<const VarDecl*> declVec;
612 llvm::errs() <<
"\n[ B" << block->
getBlockID()
613 <<
" (live variables at block exit) ]\n";
615 llvm::append_range(declVec, blocksEndToLiveness[block].liveDecls);
616 llvm::sort(declVec, [](
const Decl *A,
const Decl *B) {
620 for (
const VarDecl *VD : declVec) {
623 llvm::errs() <<
">\n";
626 llvm::errs() <<
"\n";
630 getImpl(impl).dumpExprLiveness(M);
633void LiveVariablesImpl::dumpExprLiveness(
const SourceManager &M) {
634 const ASTContext &Ctx = analysisContext.getASTContext();
635 auto ByIDs = [&Ctx](
const Expr *L,
const Expr *R) {
636 return L->
getID(Ctx) < R->getID(Ctx);
640 for (
const CFGBlock *B : *analysisContext.getCFG()) {
641 llvm::errs() <<
"\n[ B" << B->getBlockID()
642 <<
" (live expressions at block exit) ]\n";
643 std::vector<const Expr *> LiveExprs;
644 llvm::append_range(LiveExprs, blocksEndToLiveness[B].liveExprs);
645 llvm::sort(LiveExprs, ByIDs);
646 for (
const Expr *E : LiveExprs) {
647 llvm::errs() <<
"\n";
650 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.
ArrayRef< const Attr * > getAttrs() const
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.
auto getSpecificAttrs(const Container &container)
U cast(CodeGen::Address addr)
A worklist implementation for backward dataflow analysis.
void enqueuePredecessors(const CFGBlock *Block)