29#include "llvm/ADT/BitVector.h"
30#include "llvm/ADT/DenseMap.h"
31#include "llvm/ADT/PackedVector.h"
32#include "llvm/ADT/SmallBitVector.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/Support/Casting.h"
41#define DEBUG_LOGGING 0
46 for (
const auto *FD : RD->
fields()) {
47 if (FD->isUnnamedBitField())
49 if (FD->isZeroSize(FD->getASTContext()))
53 if (
const auto *FieldRD = FD->getType()->getAsRecordDecl();
79 llvm::DenseMap<const VarDecl *, unsigned> map;
82 DeclToIndex() =
default;
88 unsigned size()
const {
return map.size(); }
91 std::optional<unsigned> getValueIndex(
const VarDecl *d)
const;
96void DeclToIndex::computeMap(
const DeclContext &dc) {
100 for ( ; I !=
E; ++I) {
107std::optional<unsigned> DeclToIndex::getValueIndex(
const VarDecl *d)
const {
108 llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
135using ValueVector = llvm::PackedVector<Value, 2, llvm::SmallBitVector>;
137class CFGBlockValues {
141 DeclToIndex declToIndex;
144 CFGBlockValues(
const CFG &cfg);
146 unsigned getNumEntries()
const {
return declToIndex.size(); }
148 void computeSetOfDeclarations(
const DeclContext &dc);
150 ValueVector &getValueVector(
const CFGBlock *block) {
154 void setAllScratchValues(
Value V);
155 void mergeIntoScratch(ValueVector
const &source,
bool isFirst);
156 bool updateValueVectorWithScratch(
const CFGBlock *block);
158 bool hasNoDeclarations()
const {
159 return declToIndex.size() == 0;
164 ValueVector::reference operator[](
const VarDecl *vd);
168 std::optional<unsigned> idx = declToIndex.getValueIndex(vd);
169 return getValueVector(block)[*idx];
175CFGBlockValues::CFGBlockValues(
const CFG &
c) : cfg(
c), vals(0) {}
177void CFGBlockValues::computeSetOfDeclarations(
const DeclContext &dc) {
178 declToIndex.computeMap(dc);
179 unsigned decls = declToIndex.size();
180 scratch.resize(decls);
185 for (
auto &val : vals)
190static void printVector(
const CFGBlock *block, ValueVector &bv,
193 for (
const auto &i : bv)
194 llvm::errs() <<
' ' << i;
195 llvm::errs() <<
" : " << num <<
'\n';
199void CFGBlockValues::setAllScratchValues(
Value V) {
200 for (
unsigned I = 0,
E = scratch.size(); I !=
E; ++I)
204void CFGBlockValues::mergeIntoScratch(ValueVector
const &source,
212bool CFGBlockValues::updateValueVectorWithScratch(
const CFGBlock *block) {
213 ValueVector &dst = getValueVector(block);
214 bool changed = (dst != scratch);
218 printVector(block, scratch, 0);
223void CFGBlockValues::resetScratch() {
227ValueVector::reference CFGBlockValues::operator[](
const VarDecl *vd) {
228 return scratch[*declToIndex.getValueIndex(vd)];
244 const DeclRefExpr *getDeclRefExpr()
const {
return dr; }
245 const VarDecl *getDecl()
const {
return vd; }
253 if (
const auto *CE = dyn_cast<CastExpr>(Ex)) {
254 if (CE->getCastKind() == CK_LValueBitCast) {
255 Ex = CE->getSubExpr();
267 if (
const auto *DRE =
269 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
271 return FindVarResult(VD, DRE);
272 return FindVarResult(
nullptr,
nullptr);
280class ClassifyRefs :
public StmtVisitor<ClassifyRefs> {
292 llvm::DenseMap<const DeclRefExpr *, Class> Classification;
295 return ::isTrackedVar(VD, DC);
298 void classify(
const Expr *
E, Class
C);
313 llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
314 = Classification.find(DRE);
315 if (I != Classification.end())
318 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
334 if (DRE && DRE->
getDecl() == VD)
340void ClassifyRefs::classify(
const Expr *
E, Class
C) {
343 if (
const auto *CO = dyn_cast<ConditionalOperator>(
E)) {
344 classify(CO->getTrueExpr(),
C);
345 classify(CO->getFalseExpr(),
C);
349 if (
const auto *BCO = dyn_cast<BinaryConditionalOperator>(
E)) {
350 classify(BCO->getFalseExpr(),
C);
354 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(
E)) {
355 classify(OVE->getSourceExpr(),
C);
359 if (
const auto *ME = dyn_cast<MemberExpr>(
E)) {
360 if (
const auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
361 if (!VD->isStaticDataMember())
362 classify(ME->getBase(),
C);
367 if (
const auto *BO = dyn_cast<BinaryOperator>(
E)) {
368 switch (BO->getOpcode()) {
371 classify(BO->getLHS(),
C);
374 classify(BO->getRHS(),
C);
383 Classification[DRE] = std::max(Classification[DRE],
C);
386void ClassifyRefs::VisitDeclStmt(
DeclStmt *DS) {
387 for (
auto *DI : DS->
decls()) {
388 auto *VD = dyn_cast<VarDecl>(DI);
391 Classification[DRE] = SelfInit;
402 classify(BO->
getLHS(), Use);
404 classify(BO->
getLHS(), Ignore);
416 classify(cast<Expr>(S), Use);
426 return FTD->getTemplatedDecl()->hasTrivialBody();
427 return FD->hasTrivialBody();
432void ClassifyRefs::VisitCallExpr(
CallExpr *CE) {
437 classify(CE->
getArg(0), Use);
448 if ((*I)->isGLValue()) {
449 if ((*I)->getType().isConstQualified())
450 classify((*I), isTrivialBody ? Ignore : ConstRefUse);
453 const auto *UO = dyn_cast<UnaryOperator>(Ex);
456 classify(Ex, Ignore);
461void ClassifyRefs::VisitCastExpr(
CastExpr *CE) {
464 else if (
const auto *CSE = dyn_cast<CStyleCastExpr>(CE)) {
465 if (CSE->getType()->isVoidType()) {
469 classify(CSE->getSubExpr(), Ignore);
480class TransferFunctions :
public StmtVisitor<TransferFunctions> {
481 CFGBlockValues &vals;
485 const ClassifyRefs &classification;
490 TransferFunctions(CFGBlockValues &vals,
const CFG &cfg,
492 const ClassifyRefs &classification,
494 : vals(vals), cfg(cfg), block(block), ac(ac),
495 classification(classification), objCNoRet(ac.getASTContext()),
499 void reportConstRefUse(
const Expr *ex,
const VarDecl *vd);
512 return ::isTrackedVar(vd, cast<DeclContext>(ac.
getDecl()));
516 return ::findVar(ex, cast<DeclContext>(ac.
getDecl()));
574 Queue.push_back(block);
579 while (!Queue.empty()) {
580 const CFGBlock *B = Queue.pop_back_val();
584 Use.setUninitAfterCall();
592 Value AtPredExit = vals.getValue(Pred, B, vd);
603 Use.setUninitAfterDecl();
607 unsigned &SV = SuccsVisited[Pred->
getBlockID()];
621 Queue.push_back(Pred);
627 for (
const auto *
Block : cfg) {
630 if (SuccsVisited[BlockID] && SuccsVisited[BlockID] <
Block->
succ_size() &&
644 if (isa<SwitchStmt>(Term)) {
652 Use.addUninitBranch(Branch);
657 Use.addUninitBranch(Branch);
670void TransferFunctions::reportUse(
const Expr *ex,
const VarDecl *vd) {
676void TransferFunctions::reportConstRefUse(
const Expr *ex,
const VarDecl *vd) {
684 if (
const auto *DS = dyn_cast<DeclStmt>(FS->getElement())) {
691void TransferFunctions::VisitOMPExecutableDirective(
694 assert(S &&
"Expected non-null used-in-clause child.");
701void TransferFunctions::VisitBlockExpr(
BlockExpr *be) {
703 for (
const auto &I : bd->
captures()) {
704 const VarDecl *vd = I.getVariable();
715void TransferFunctions::VisitCallExpr(
CallExpr *ce) {
717 if (
Callee->hasAttr<ReturnsTwiceAttr>()) {
725 else if (
Callee->hasAttr<AnalyzerNoReturnAttr>()) {
733 vals.setAllScratchValues(
Unknown);
738void TransferFunctions::VisitDeclRefExpr(
DeclRefExpr *dr) {
739 switch (classification.get(dr)) {
740 case ClassifyRefs::Ignore:
742 case ClassifyRefs::Use:
743 reportUse(dr, cast<VarDecl>(dr->
getDecl()));
745 case ClassifyRefs::Init:
748 case ClassifyRefs::SelfInit:
751 case ClassifyRefs::ConstRefUse:
752 reportConstRefUse(dr, cast<VarDecl>(dr->
getDecl()));
760 if (
const VarDecl *VD = Var.getDecl())
765void TransferFunctions::VisitDeclStmt(
DeclStmt *DS) {
766 for (
auto *DI : DS->
decls()) {
767 auto *VD = dyn_cast<VarDecl>(DI);
781 }
else if (VD->getInit()) {
801void TransferFunctions::VisitGCCAsmStmt(
GCCAsmStmt *as) {
812 while (
const auto *UO = dyn_cast<UnaryOperator>(Ex))
828 vals.setAllScratchValues(
Unknown);
838 const ClassifyRefs &classification,
839 llvm::BitVector &wasAnalyzed,
851 vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
856 TransferFunctions tf(vals, cfg, block, ac, classification, handler);
857 for (
const auto &I : *block) {
858 if (std::optional<CFGStmt> cs = I.getAs<
CFGStmt>())
859 tf.Visit(
const_cast<Stmt *
>(cs->getStmt()));
862 if (
auto *as = dyn_cast_or_null<GCCAsmStmt>(terminator.
getStmt()))
865 return vals.updateValueVectorWithScratch(block);
876 llvm::BitVector hadUse;
879 bool hadAnyUse =
false;
882 unsigned currentBlock = 0;
884 PruneBlocksHandler(
unsigned numBlocks) : hadUse(numBlocks,
false) {}
886 ~PruneBlocksHandler()
override =
default;
890 hadUse[currentBlock] =
true;
896 hadUse[currentBlock] =
true;
904 hadUse[currentBlock] =
true;
917 CFGBlockValues vals(cfg);
918 vals.computeSetOfDeclarations(dc);
919 if (vals.hasNoDeclarations())
925 ClassifyRefs classification(ac);
930 ValueVector &vec = vals.getValueVector(&entry);
931 const unsigned n = vals.getNumEntries();
932 for (
unsigned j = 0; j < n; ++j) {
948 bool changed =
runOnBlock(block, cfg, ac, vals,
949 classification, wasAnalyzed, PBH);
951 if (changed || !previouslyVisited[block->
getBlockID()])
953 previouslyVisited[block->
getBlockID()] =
true;
960 for (
const auto *block : cfg)
962 runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the Objective-C statement AST node classes.
C Language Family Type Representation.
static bool isAlwaysUninit(const Value v)
static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc)
static const Expr * stripCasts(ASTContext &C, const Expr *Ex)
static bool isUninitialized(const Value v)
static bool isPointerToConst(const QualType &QT)
static FindVarResult findVar(const Expr *E, const DeclContext *DC)
If E is an expression comprising a reference to a single variable, find that variable.
static bool hasTrivialBody(CallExpr *CE)
static bool recordIsNotEmpty(const RecordDecl *RD)
static const DeclRefExpr * getSelfInitExpr(VarDecl *VD)
static bool runOnBlock(const CFGBlock *block, const CFG &cfg, AnalysisDeclContext &ac, CFGBlockValues &vals, const ClassifyRefs &classification, llvm::BitVector &wasAnalyzed, UninitVariablesHandler &handler)
__device__ __2f16 float c
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.
const Decl * getDecl() const
ASTContext & getASTContext() const
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isCompoundAssignmentOp(Opcode Opc)
Represents a block literal declaration, which is like an unnamed FunctionDecl.
ArrayRef< Capture > captures() const
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
Represents a single basic block in a source-level CFG.
CFGTerminator getTerminator() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
AdjacentBlocks::const_iterator const_pred_iterator
pred_iterator pred_begin()
unsigned getBlockID() const
AdjacentBlocks::const_iterator const_succ_iterator
unsigned succ_size() const
Represents CFGBlock terminator statement.
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
void VisitBlockStmts(Callback &O) const
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
bool isCallToStdMove() const
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
CastKind getCastKind() const
const CFGBlock * dequeue()
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext,...
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
ASTContext & getParentASTContext() const
decl_iterator decls_end() const
decl_iterator decls_begin() const
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.
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
DeclContext * getDeclContext()
This represents one expression.
Expr * IgnoreParenNoopCasts(const ASTContext &Ctx) LLVM_READONLY
Skip past any parentheses and casts which do not change the value (including ptr->int casts of the sa...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Represents a function declaration or definition.
Declaration of a template function.
This represents a GCC inline-assembly statement extension.
This is a basic class for representing single OpenMP executable directive.
ArrayRef< OMPClause * > clauses() const
const Stmt * getStructuredBlock() const
Returns the AST node representing OpenMP structured-block of this OpenMP executable directive,...
bool isStandaloneDirective() const
Returns whether or not this is a Standalone directive.
static llvm::iterator_range< used_clauses_child_iterator > used_clauses_children(ArrayRef< OMPClause * > Clauses)
Represents Objective-C's collection statement.
An expression that sends a message to the given Objective-C object or class.
bool isImplicitNoReturn(const ObjCMessageExpr *ME)
Return true if the given message expression is known to never return.
A (possibly-)qualified type.
bool isConstQualified() const
Determine whether this type is const-qualified.
Represents a struct/union/class.
field_range fields() const
RetTy Visit(PTR(Stmt) S, ParamTys... P)
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Stmt - This represents one statement.
bool isScalarType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isVectorType() const
bool isRVVSizelessBuiltinType() const
Returns true for RVV scalable vector types.
bool isAnyPointerType() const
bool isRecordType() const
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
static bool isIncrementDecrementOp(Opcode Op)
A use of a variable, which might be uninitialized.
@ Always
The use is always uninitialized.
virtual void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use)
Called when the uninitialized variable is used at the given expression.
virtual void handleSelfInit(const VarDecl *vd)
Called when the uninitialized variable analysis detects the idiom 'int x = x'.
virtual ~UninitVariablesHandler()
virtual void handleConstRefUseOfUninitVariable(const VarDecl *vd, const UninitUse &use)
Called when the uninitialized variable is used as const refernce argument.
Represents a variable declaration or definition.
bool isInitCapture() const
Whether this variable is the implicit variable for a lambda init-capture.
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
bool isExceptionVariable() const
Determine whether this variable is the exception variable in a C++ catch statememt or an Objective-C ...
const Expr * getInit() const
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
BlockID
The various types of blocks that can occur within a API notes file.
The JSON file list parser is used to communicate input to InstallAPI.
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
U cast(CodeGen::Address addr)
@ Class
The "class" keyword introduces the elaborated-type-specifier.
A worklist implementation for forward dataflow analysis.
void enqueueSuccessors(const CFGBlock *Block)
Iterator for iterating over Stmt * arrays that contain only T *.
unsigned NumVariablesAnalyzed