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 {
34 AnalysisDeclContext &analysisContext;
35 SetTy<const Expr *>::Factory ESetFact;
36 SetTy<const VarDecl *>::Factory DSetFact;
37 SetTy<const BindingDecl *>::Factory BSetFact;
38 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness;
39 llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness;
40 llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness;
41 llvm::DenseSet<const DeclRefExpr *> inAssignment;
42 const bool killAtAssign;
44 LiveVariables::LivenessValues
45 merge(LiveVariables::LivenessValues valsA,
46 LiveVariables::LivenessValues valsB);
48 LiveVariables::LivenessValues
49 runOnBlock(
const CFGBlock *block, LiveVariables::LivenessValues val,
50 LiveVariables::Observer *obs =
nullptr);
52 void dumpBlockLiveness(
const SourceManager& M);
53 void dumpExprLiveness(
const SourceManager& M);
55 LiveVariablesImpl(AnalysisDeclContext &ac,
bool KillAtAssign)
56 : analysisContext(ac), killAtAssign(KillAtAssign) {}
60static LiveVariablesImpl &
getImpl(
void *x) {
61 return *((LiveVariablesImpl *) x);
73 if (
const auto *DD = dyn_cast<DecompositionDecl>(D)) {
89void LiveVariables::Observer::anchor() { }
125 return getImpl(impl).stmtsToLiveness[Loc].isLive(Val);
133class TransferFunctions :
public StmtVisitor<TransferFunctions> {
134 LiveVariablesImpl &LV;
139 TransferFunctions(LiveVariablesImpl &im,
143 : LV(im), val(Val), observer(Observer), currentBlock(CurrentBlock) {}
157 while (
const ArrayType *VT = dyn_cast<ArrayType>(ty)) {
159 if (VAT->getSizeExpr())
162 ty = VT->getElementType().getTypePtr();
171 if (
const FullExpr *FE = dyn_cast<FullExpr>(E)) {
172 E = FE->getSubExpr();
176 E = OVE->getSourceExpr();
200 if (
auto const *BO = dyn_cast<BinaryOperator>(
Cond->IgnoreParens());
201 BO && BO->isLogicalOp()) {
207void TransferFunctions::Visit(Stmt *S) {
209 observer->observeStmt(S, currentBlock, val);
213 if (
const auto *E = dyn_cast<Expr>(S)) {
214 val.liveExprs = LV.ESetFact.remove(val.liveExprs, E);
228 case Stmt::StmtExprClass: {
233 case Stmt::CXXMemberCallExprClass: {
237 AddLiveExpr(val.liveExprs, LV.ESetFact, ImplicitObj);
241 case Stmt::ObjCMessageExprClass: {
245 val.liveDecls = LV.DSetFact.add(val.liveDecls,
246 LV.analysisContext.getSelfDecl());
249 case Stmt::DeclStmtClass: {
251 if (
const VarDecl *VD = dyn_cast<VarDecl>(DS->
getSingleDecl())) {
252 for (
const VariableArrayType* VA =
FindVA(VD->getType());
253 VA !=
nullptr; VA =
FindVA(VA->getElementType())) {
254 AddLiveExpr(val.liveExprs, LV.ESetFact, VA->getSizeExpr());
259 case Stmt::AttributedStmtClass: {
264 AddLiveExpr(val.liveExprs, LV.ESetFact, Attr->getAssumption());
268 case Stmt::PseudoObjectExprClass: {
273 if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
274 child = OV->getSourceExpr();
276 val.liveExprs = LV.ESetFact.add(val.liveExprs, child);
281 case Stmt::ExprWithCleanupsClass: {
285 case Stmt::CXXBindTemporaryExprClass: {
289 case Stmt::UnaryExprOrTypeTraitExprClass: {
293 case Stmt::IfStmtClass: {
300 case Stmt::WhileStmtClass: {
307 case Stmt::DoStmtClass: {
314 case Stmt::ForStmtClass: {
321 case Stmt::ConditionalOperatorClass: {
338 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getTrueExpr());
339 AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getFalseExpr());
346 if (
const auto *E = dyn_cast_or_null<Expr>(Child))
356void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
357 if (LV.killAtAssign && B->
getOpcode() == BO_Assign) {
359 LV.inAssignment.insert(DR);
363 if (!LV.killAtAssign)
369 if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
370 const Decl* D = DR->getDecl();
373 if (
const BindingDecl* BD = dyn_cast<BindingDecl>(D)) {
374 Killed = !BD->getType()->isReferenceType();
376 if (
const auto *HV = BD->getHoldingVar())
377 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
379 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
381 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
384 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
390void TransferFunctions::VisitBlockExpr(BlockExpr *BE) {
391 for (
const VarDecl *VD :
392 LV.analysisContext.getReferencedBlockVars(BE->
getBlockDecl())) {
395 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
399void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
401 bool InAssignment = LV.inAssignment.contains(DR);
402 if (
const auto *BD = dyn_cast<BindingDecl>(D)) {
404 if (
const auto *HV = BD->getHoldingVar())
405 val.liveDecls = LV.DSetFact.add(val.liveDecls, HV);
407 val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
409 }
else if (
const auto *VD = dyn_cast<VarDecl>(D)) {
411 val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
415void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
416 for (
const auto *DI : DS->
decls()) {
417 if (
const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
418 for (
const auto *BD : DD->bindings()) {
419 if (
const auto *HV = BD->getHoldingVar())
420 val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
422 val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
427 val.liveDecls = LV.DSetFact.remove(val.liveDecls, DD);
428 }
else if (
const auto *VD = dyn_cast<VarDecl>(DI)) {
430 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
435void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) {
437 DeclRefExpr *DR =
nullptr;
438 const VarDecl *VD =
nullptr;
440 Stmt *element =
OS->getElement();
441 if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
444 else if ((DR = dyn_cast<DeclRefExpr>(
cast<Expr>(element)->IgnoreParens()))) {
449 val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
453void TransferFunctions::
454VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE)
465 val.liveExprs = LV.ESetFact.add(val.liveExprs, subEx->
IgnoreParens());
469LiveVariables::LivenessValues
470LiveVariablesImpl::runOnBlock(
const CFGBlock *block,
471 LiveVariables::LivenessValues val,
472 LiveVariables::Observer *obs) {
474 TransferFunctions TF(*
this, val, obs, block);
478 TF.Visit(
const_cast<Stmt*
>(term));
482 ei = block->
rend(); it != ei; ++it) {
483 const CFGElement &elem = *it;
485 if (std::optional<CFGAutomaticObjDtor> Dtor =
486 elem.
getAs<CFGAutomaticObjDtor>()) {
491 if (!elem.
getAs<CFGStmt>())
494 const Stmt *S = elem.
castAs<CFGStmt>().getStmt();
495 TF.Visit(
const_cast<Stmt*
>(S));
496 stmtsToLiveness[S] = val;
504 getImpl(impl).runOnBlock(B,
getImpl(impl).blocksEndToLiveness[B], &obs);
507LiveVariables::LiveVariables(
void *im) : impl(im) {}
510 delete (LiveVariablesImpl*) impl;
513std::unique_ptr<LiveVariables>
526 LiveVariablesImpl *LV =
new LiveVariablesImpl(AC, killAtAssign);
547 val = LV->merge(val, LV->blocksBeginToLiveness[succ]);
552 everAnalyzedBlock[block->
getBlockID()] =
true;
553 else if (prevVal == val)
559 LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val);
565 return std::unique_ptr<LiveVariables>(
new LiveVariables(LV));
569 getImpl(impl).dumpBlockLiveness(M);
572void LiveVariablesImpl::dumpBlockLiveness(
const SourceManager &M) {
573 std::vector<const CFGBlock *> vec;
574 vec.reserve(blocksEndToLiveness.size());
575 llvm::append_range(vec, llvm::make_first_range(blocksEndToLiveness));
580 std::vector<const VarDecl*> declVec;
583 llvm::errs() <<
"\n[ B" << block->
getBlockID()
584 <<
" (live variables at block exit) ]\n";
586 llvm::append_range(declVec, blocksEndToLiveness[block].liveDecls);
587 llvm::sort(declVec, [](
const Decl *A,
const Decl *B) {
591 for (
const VarDecl *VD : declVec) {
594 llvm::errs() <<
">\n";
597 llvm::errs() <<
"\n";
601 getImpl(impl).dumpExprLiveness(M);
604void LiveVariablesImpl::dumpExprLiveness(
const SourceManager &M) {
605 const ASTContext &Ctx = analysisContext.getASTContext();
606 auto ByIDs = [&Ctx](
const Expr *L,
const Expr *R) {
607 return L->
getID(Ctx) < R->getID(Ctx);
611 for (
const CFGBlock *B : *analysisContext.getCFG()) {
612 llvm::errs() <<
"\n[ B" << B->getBlockID()
613 <<
" (live expressions at block exit) ]\n";
614 std::vector<const Expr *> LiveExprs;
615 llvm::append_range(LiveExprs, blocksEndToLiveness[B].liveExprs);
616 llvm::sort(LiveExprs, ByIDs);
617 for (
const Expr *E : LiveExprs) {
618 llvm::errs() <<
"\n";
621 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(LiveVariables::SetTy< const Expr * > &Set, LiveVariables::SetTy< const Expr * >::Factory &F, const Expr *E)
static LiveVariablesImpl & getImpl(void *x)
static const Expr * LookThroughExpr(const Expr *E)
static void AddAllConditionalTerms(LiveVariables::SetTy< const Expr * > &Set, LiveVariables::SetTy< 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.
bool operator==(const LivenessValues &V) const
SetTy< const BindingDecl * > liveBindings
SetTy< const Expr * > liveExprs
bool isLive(const Expr *E) const
SetTy< const VarDecl * > liveDecls
llvm::ImmutableSet< T, llvm::ImutContainerInfo< T >, false > SetTy
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)