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
61 llvm::DenseMap<const VarDecl *, unsigned> map;
64 DeclToIndex() =
default;
70 unsigned size()
const {
return map.size(); }
73 std::optional<unsigned> getValueIndex(
const VarDecl *d)
const;
78void DeclToIndex::computeMap(
const DeclContext &dc) {
82 for ( ; I != E; ++I) {
89std::optional<unsigned> DeclToIndex::getValueIndex(
const VarDecl *d)
const {
90 llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
117using ValueVector = llvm::PackedVector<Value, 2, llvm::SmallBitVector>;
119class CFGBlockValues {
123 DeclToIndex declToIndex;
126 CFGBlockValues(
const CFG &cfg);
128 unsigned getNumEntries()
const {
return declToIndex.size(); }
130 void computeSetOfDeclarations(
const DeclContext &dc);
132 ValueVector &getValueVector(
const CFGBlock *block) {
136 void setAllScratchValues(
Value V);
137 void mergeIntoScratch(ValueVector
const &source,
bool isFirst);
138 bool updateValueVectorWithScratch(
const CFGBlock *block);
140 bool hasNoDeclarations()
const {
141 return declToIndex.size() == 0;
146 ValueVector::reference operator[](
const VarDecl *vd);
150 std::optional<unsigned> idx = declToIndex.getValueIndex(vd);
151 return getValueVector(block)[*idx];
157CFGBlockValues::CFGBlockValues(
const CFG &
c) : cfg(
c), vals(0) {}
159void CFGBlockValues::computeSetOfDeclarations(
const DeclContext &dc) {
160 declToIndex.computeMap(dc);
161 unsigned decls = declToIndex.size();
162 scratch.resize(decls);
167 for (
auto &val : vals)
172static void printVector(
const CFGBlock *block, ValueVector &bv,
175 for (
const auto &i : bv)
176 llvm::errs() <<
' ' << i;
177 llvm::errs() <<
" : " << num <<
'\n';
181void CFGBlockValues::setAllScratchValues(
Value V) {
182 for (
unsigned I = 0, E = scratch.size(); I != E; ++I)
186void CFGBlockValues::mergeIntoScratch(ValueVector
const &source,
194bool CFGBlockValues::updateValueVectorWithScratch(
const CFGBlock *block) {
195 ValueVector &dst = getValueVector(block);
196 bool changed = (dst != scratch);
200 printVector(block, scratch, 0);
205void CFGBlockValues::resetScratch() {
209ValueVector::reference CFGBlockValues::operator[](
const VarDecl *vd) {
210 return scratch[*declToIndex.getValueIndex(vd)];
226 const DeclRefExpr *getDeclRefExpr()
const {
return dr; }
227 const VarDecl *getDecl()
const {
return vd; }
235 if (
const auto *CE = dyn_cast<CastExpr>(Ex)) {
236 if (CE->getCastKind() == CK_LValueBitCast) {
237 Ex = CE->getSubExpr();
249 if (
const auto *DRE =
251 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
253 return FindVarResult(VD, DRE);
254 return FindVarResult(
nullptr,
nullptr);
262class ClassifyRefs :
public StmtVisitor<ClassifyRefs> {
274 llvm::DenseMap<const DeclRefExpr *, Class> Classification;
277 return ::isTrackedVar(VD, DC);
280 void classify(
const Expr *E, Class
C);
295 llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
296 = Classification.find(DRE);
297 if (I != Classification.end())
300 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
316 if (DRE && DRE->
getDecl() == VD)
322void ClassifyRefs::classify(
const Expr *E, Class
C) {
325 if (
const auto *CO = dyn_cast<ConditionalOperator>(E)) {
326 classify(CO->getTrueExpr(),
C);
327 classify(CO->getFalseExpr(),
C);
331 if (
const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) {
332 classify(BCO->getFalseExpr(),
C);
336 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) {
337 classify(OVE->getSourceExpr(),
C);
341 if (
const auto *ME = dyn_cast<MemberExpr>(E)) {
342 if (
const auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
343 if (!VD->isStaticDataMember())
344 classify(ME->getBase(),
C);
349 if (
const auto *BO = dyn_cast<BinaryOperator>(E)) {
350 switch (BO->getOpcode()) {
353 classify(BO->getLHS(),
C);
356 classify(BO->getRHS(),
C);
363 FindVarResult Var =
findVar(E, DC);
365 Classification[DRE] = std::max(Classification[DRE],
C);
368void ClassifyRefs::VisitDeclStmt(
DeclStmt *DS) {
369 for (
auto *DI : DS->
decls()) {
370 auto *VD = dyn_cast<VarDecl>(DI);
373 Classification[DRE] = SelfInit;
384 classify(BO->
getLHS(), Use);
386 classify(BO->
getLHS(), Ignore);
398 classify(cast<Expr>(S), Use);
408 return FTD->getTemplatedDecl()->hasTrivialBody();
409 return FD->hasTrivialBody();
414void ClassifyRefs::VisitCallExpr(
CallExpr *CE) {
419 classify(CE->
getArg(0), Use);
430 if ((*I)->isGLValue()) {
431 if ((*I)->getType().isConstQualified())
432 classify((*I), isTrivialBody ? Ignore : ConstRefUse);
435 const auto *UO = dyn_cast<UnaryOperator>(Ex);
438 classify(Ex, Ignore);
443void ClassifyRefs::VisitCastExpr(
CastExpr *CE) {
446 else if (
const auto *CSE = dyn_cast<CStyleCastExpr>(CE)) {
447 if (CSE->getType()->isVoidType()) {
451 classify(CSE->getSubExpr(), Ignore);
462class TransferFunctions :
public StmtVisitor<TransferFunctions> {
463 CFGBlockValues &vals;
467 const ClassifyRefs &classification;
472 TransferFunctions(CFGBlockValues &vals,
const CFG &cfg,
474 const ClassifyRefs &classification,
476 : vals(vals), cfg(cfg), block(block), ac(ac),
477 classification(classification), objCNoRet(ac.getASTContext()),
481 void reportConstRefUse(
const Expr *ex,
const VarDecl *vd);
494 return ::isTrackedVar(vd, cast<DeclContext>(ac.
getDecl()));
498 return ::findVar(ex, cast<DeclContext>(ac.
getDecl()));
556 Queue.push_back(block);
561 while (!Queue.empty()) {
562 const CFGBlock *B = Queue.pop_back_val();
566 Use.setUninitAfterCall();
574 Value AtPredExit = vals.getValue(Pred, B, vd);
585 Use.setUninitAfterDecl();
589 unsigned &SV = SuccsVisited[Pred->
getBlockID()];
603 Queue.push_back(Pred);
609 for (
const auto *
Block : cfg) {
611 const Stmt *Term =
Block->getTerminatorStmt();
612 if (SuccsVisited[BlockID] && SuccsVisited[BlockID] <
Block->succ_size() &&
618 E =
Block->succ_end(); I != E; ++I) {
626 if (isa<SwitchStmt>(Term)) {
634 Use.addUninitBranch(Branch);
639 Use.addUninitBranch(Branch);
652void TransferFunctions::reportUse(
const Expr *ex,
const VarDecl *vd) {
658void TransferFunctions::reportConstRefUse(
const Expr *ex,
const VarDecl *vd) {
666 if (
const auto *DS = dyn_cast<DeclStmt>(FS->getElement())) {
673void TransferFunctions::VisitOMPExecutableDirective(
676 assert(S &&
"Expected non-null used-in-clause child.");
683void TransferFunctions::VisitBlockExpr(
BlockExpr *be) {
685 for (
const auto &I : bd->
captures()) {
686 const VarDecl *vd = I.getVariable();
697void TransferFunctions::VisitCallExpr(
CallExpr *ce) {
699 if (
Callee->hasAttr<ReturnsTwiceAttr>()) {
707 else if (
Callee->hasAttr<AnalyzerNoReturnAttr>()) {
715 vals.setAllScratchValues(
Unknown);
720void TransferFunctions::VisitDeclRefExpr(
DeclRefExpr *dr) {
721 switch (classification.get(dr)) {
722 case ClassifyRefs::Ignore:
724 case ClassifyRefs::Use:
725 reportUse(dr, cast<VarDecl>(dr->
getDecl()));
727 case ClassifyRefs::Init:
730 case ClassifyRefs::SelfInit:
733 case ClassifyRefs::ConstRefUse:
734 reportConstRefUse(dr, cast<VarDecl>(dr->
getDecl()));
742 if (
const VarDecl *VD = Var.getDecl())
747void TransferFunctions::VisitDeclStmt(
DeclStmt *DS) {
748 for (
auto *DI : DS->
decls()) {
749 auto *VD = dyn_cast<VarDecl>(DI);
763 }
else if (VD->getInit()) {
783void TransferFunctions::VisitGCCAsmStmt(
GCCAsmStmt *as) {
794 while (
const auto *UO = dyn_cast<UnaryOperator>(Ex))
810 vals.setAllScratchValues(
Unknown);
820 const ClassifyRefs &classification,
821 llvm::BitVector &wasAnalyzed,
828 E = block->
pred_end(); I != E; ++I) {
833 vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
838 TransferFunctions tf(vals, cfg, block, ac, classification, handler);
839 for (
const auto &I : *block) {
840 if (std::optional<CFGStmt> cs = I.getAs<
CFGStmt>())
841 tf.Visit(
const_cast<Stmt *
>(cs->getStmt()));
844 if (
auto *as = dyn_cast_or_null<GCCAsmStmt>(terminator.
getStmt()))
847 return vals.updateValueVectorWithScratch(block);
858 llvm::BitVector hadUse;
861 bool hadAnyUse =
false;
864 unsigned currentBlock = 0;
866 PruneBlocksHandler(
unsigned numBlocks) : hadUse(numBlocks,
false) {}
868 ~PruneBlocksHandler()
override =
default;
872 hadUse[currentBlock] =
true;
878 hadUse[currentBlock] =
true;
886 hadUse[currentBlock] =
true;
899 CFGBlockValues vals(cfg);
900 vals.computeSetOfDeclarations(dc);
901 if (vals.hasNoDeclarations())
907 ClassifyRefs classification(ac);
912 ValueVector &vec = vals.getValueVector(&entry);
913 const unsigned n = vals.getNumEntries();
914 for (
unsigned j = 0; j < n; ++j) {
930 bool changed =
runOnBlock(block, cfg, ac, vals,
931 classification, wasAnalyzed, PBH);
933 if (changed || !previouslyVisited[block->
getBlockID()])
935 previouslyVisited[block->
getBlockID()] =
true;
942 for (
const auto *block : cfg)
944 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 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()
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.
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 isAnyPointerType() const
bool isRecordType() const
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.
@ C
Languages that the frontend can parse and compile.
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
U cast(CodeGen::Address addr)
A worklist implementation for forward dataflow analysis.
void enqueueSuccessors(const CFGBlock *Block)
Iterator for iterating over Stmt * arrays that contain only T *.
unsigned NumVariablesAnalyzed