28#include "llvm/ADT/BitVector.h"
29#include "llvm/ADT/DenseMap.h"
30#include "llvm/ADT/PackedVector.h"
31#include "llvm/ADT/SmallBitVector.h"
32#include "llvm/ADT/SmallVector.h"
39#define DEBUG_LOGGING 0
44 for (
const auto *FD : RD->
fields()) {
45 if (FD->isUnnamedBitField())
47 if (FD->isZeroSize(FD->getASTContext()))
51 if (
const auto *FieldRD = FD->getType()->getAsRecordDecl();
77 llvm::DenseMap<const VarDecl *, unsigned> map;
80 DeclToIndex() =
default;
86 unsigned size()
const {
return map.size(); }
89 std::optional<unsigned> getValueIndex(
const VarDecl *d)
const;
94void DeclToIndex::computeMap(
const DeclContext &dc) {
98 for ( ; I !=
E; ++I) {
105std::optional<unsigned> DeclToIndex::getValueIndex(
const VarDecl *d)
const {
106 llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
133using ValueVector = llvm::PackedVector<Value, 2, llvm::SmallBitVector>;
135class CFGBlockValues {
139 DeclToIndex declToIndex;
142 CFGBlockValues(
const CFG &cfg);
144 unsigned getNumEntries()
const {
return declToIndex.size(); }
146 void computeSetOfDeclarations(
const DeclContext &dc);
148 ValueVector &getValueVector(
const CFGBlock *block) {
152 void setAllScratchValues(
Value V);
153 void mergeIntoScratch(ValueVector
const &source,
bool isFirst);
154 bool updateValueVectorWithScratch(
const CFGBlock *block);
156 bool hasNoDeclarations()
const {
157 return declToIndex.size() == 0;
162 ValueVector::reference operator[](
const VarDecl *vd);
165 std::optional<unsigned> idx = declToIndex.getValueIndex(vd);
166 return getValueVector(block)[*idx];
172CFGBlockValues::CFGBlockValues(
const CFG &
c) : cfg(
c), vals(0) {}
174void CFGBlockValues::computeSetOfDeclarations(
const DeclContext &dc) {
175 declToIndex.computeMap(dc);
176 unsigned decls = declToIndex.size();
177 scratch.resize(decls);
182 for (
auto &val : vals)
187static void printVector(
const CFGBlock *block, ValueVector &bv,
190 for (
const auto &i : bv)
191 llvm::errs() <<
' ' << i;
192 llvm::errs() <<
" : " << num <<
'\n';
196void CFGBlockValues::setAllScratchValues(
Value V) {
197 for (
unsigned I = 0,
E = scratch.size(); I !=
E; ++I)
201void CFGBlockValues::mergeIntoScratch(ValueVector
const &source,
209bool CFGBlockValues::updateValueVectorWithScratch(
const CFGBlock *block) {
210 ValueVector &
dst = getValueVector(block);
211 bool changed = (
dst != scratch);
215 printVector(block, scratch, 0);
220void CFGBlockValues::resetScratch() {
224ValueVector::reference CFGBlockValues::operator[](
const VarDecl *vd) {
225 return scratch[*declToIndex.getValueIndex(vd)];
241 const DeclRefExpr *getDeclRefExpr()
const {
return dr; }
242 const VarDecl *getDecl()
const {
return vd; }
250 if (
const auto *CE = dyn_cast<CastExpr>(Ex)) {
251 if (CE->getCastKind() == CK_LValueBitCast) {
252 Ex = CE->getSubExpr();
264 if (
const auto *DRE =
266 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
268 return FindVarResult(VD, DRE);
269 return FindVarResult(
nullptr,
nullptr);
277class ClassifyRefs :
public StmtVisitor<ClassifyRefs> {
279 enum Class {
Init, Use, SelfInit, ConstRefUse, ConstPtrUse, Ignore };
283 llvm::DenseMap<const DeclRefExpr *, Class> Classification;
286 return ::isTrackedVar(VD, DC);
289 void classify(
const Expr *
E, Class
C);
304 llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
305 = Classification.find(DRE);
306 if (I != Classification.end())
309 const auto *VD = dyn_cast<VarDecl>(DRE->
getDecl());
325 if (DRE && DRE->
getDecl() == VD)
331void ClassifyRefs::classify(
const Expr *
E, Class
C) {
334 if (
const auto *CO = dyn_cast<ConditionalOperator>(
E)) {
335 classify(CO->getTrueExpr(),
C);
336 classify(CO->getFalseExpr(),
C);
340 if (
const auto *BCO = dyn_cast<BinaryConditionalOperator>(
E)) {
341 classify(BCO->getFalseExpr(),
C);
345 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(
E)) {
346 classify(OVE->getSourceExpr(),
C);
350 if (
const auto *ME = dyn_cast<MemberExpr>(
E)) {
351 if (
const auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
352 if (!VD->isStaticDataMember())
353 classify(ME->getBase(),
C);
358 if (
const auto *BO = dyn_cast<BinaryOperator>(
E)) {
359 switch (BO->getOpcode()) {
362 classify(BO->getLHS(),
C);
365 classify(BO->getRHS(),
C);
373 if (
const DeclRefExpr *DRE = Var.getDeclRefExpr()) {
374 auto &
Class = Classification[DRE];
375 Class = std::max(Class,
C);
379void ClassifyRefs::VisitDeclStmt(
DeclStmt *DS) {
380 for (
auto *DI : DS->
decls()) {
381 auto *VD = dyn_cast<VarDecl>(DI);
384 Classification[DRE] = SelfInit;
395 classify(BO->
getLHS(), Use);
397 classify(BO->
getLHS(), Ignore);
409 classify(cast<Expr>(S), Use);
419 return FTD->getTemplatedDecl()->hasTrivialBody();
420 return FD->hasTrivialBody();
425void ClassifyRefs::VisitCallExpr(
CallExpr *CE) {
430 classify(CE->
getArg(0), Use);
441 if ((*I)->isGLValue()) {
442 if ((*I)->getType().isConstQualified())
443 classify((*I), isTrivialBody ? Ignore : ConstRefUse);
446 const auto *UO = dyn_cast<UnaryOperator>(Ex);
448 classify(UO->
getSubExpr(), isTrivialBody ? Ignore : ConstPtrUse);
453void ClassifyRefs::VisitCastExpr(
CastExpr *CE) {
456 else if (
const auto *CSE = dyn_cast<CStyleCastExpr>(CE)) {
457 if (CSE->getType()->isVoidType()) {
461 classify(CSE->getSubExpr(), Ignore);
472class TransferFunctions :
public StmtVisitor<TransferFunctions> {
473 CFGBlockValues &vals;
477 const ClassifyRefs &classification;
482 TransferFunctions(CFGBlockValues &vals,
const CFG &cfg,
484 const ClassifyRefs &classification,
486 : vals(vals), cfg(cfg), block(block), ac(ac),
487 classification(classification), objCNoRet(ac.getASTContext()),
491 void reportConstRefUse(
const Expr *ex,
const VarDecl *vd);
492 void reportConstPtrUse(
const Expr *ex,
const VarDecl *vd);
505 return ::isTrackedVar(vd, cast<DeclContext>(ac.
getDecl()));
509 return ::findVar(ex, cast<DeclContext>(ac.
getDecl()));
567 Queue.push_back(block);
572 while (!Queue.empty()) {
573 const CFGBlock *B = Queue.pop_back_val();
577 Use.setUninitAfterCall();
585 Value AtPredExit = vals.getValue(Pred, vd);
596 Use.setUninitAfterDecl();
600 unsigned &SV = SuccsVisited[Pred->
getBlockID()];
614 Queue.push_back(Pred);
620 for (
const auto *
Block : cfg) {
625 if (SuccsVisited[BlockID] && SuccsVisited[BlockID] <
Block->
succ_size() &&
638 if (isa<SwitchStmt>(Term)) {
646 Use.addUninitBranch(Branch);
651 Use.addUninitBranch(Branch);
664void TransferFunctions::reportUse(
const Expr *ex,
const VarDecl *vd) {
670void TransferFunctions::reportConstRefUse(
const Expr *ex,
const VarDecl *vd) {
673 auto use = getUninitUse(ex, vd, v);
674 use.setConstRefUse();
679void TransferFunctions::reportConstPtrUse(
const Expr *ex,
const VarDecl *vd) {
682 auto use = getUninitUse(ex, vd, v);
683 use.setConstPtrUse();
690 if (
const auto *DS = dyn_cast<DeclStmt>(FS->getElement())) {
697void TransferFunctions::VisitOMPExecutableDirective(
700 assert(S &&
"Expected non-null used-in-clause child.");
707void TransferFunctions::VisitBlockExpr(
BlockExpr *be) {
709 for (
const auto &I : bd->
captures()) {
710 const VarDecl *vd = I.getVariable();
721void TransferFunctions::VisitCallExpr(
CallExpr *ce) {
723 if (
Callee->hasAttr<ReturnsTwiceAttr>()) {
731 else if (
Callee->hasAttr<AnalyzerNoReturnAttr>()) {
739 vals.setAllScratchValues(
Unknown);
744void TransferFunctions::VisitDeclRefExpr(
DeclRefExpr *dr) {
745 switch (classification.get(dr)) {
746 case ClassifyRefs::Ignore:
748 case ClassifyRefs::Use:
749 reportUse(dr, cast<VarDecl>(dr->
getDecl()));
751 case ClassifyRefs::Init:
754 case ClassifyRefs::SelfInit:
757 case ClassifyRefs::ConstRefUse:
758 reportConstRefUse(dr, cast<VarDecl>(dr->
getDecl()));
760 case ClassifyRefs::ConstPtrUse:
761 reportConstPtrUse(dr, cast<VarDecl>(dr->
getDecl()));
769 if (
const VarDecl *VD = Var.getDecl())
774void TransferFunctions::VisitDeclStmt(
DeclStmt *DS) {
775 for (
auto *DI : DS->
decls()) {
776 auto *VD = dyn_cast<VarDecl>(DI);
790 }
else if (VD->getInit()) {
810void TransferFunctions::VisitGCCAsmStmt(
GCCAsmStmt *as) {
821 while (
const auto *UO = dyn_cast<UnaryOperator>(Ex))
837 vals.setAllScratchValues(
Unknown);
847 const ClassifyRefs &classification,
848 llvm::BitVector &wasAnalyzed,
860 vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
865 TransferFunctions tf(vals, cfg, block, ac, classification, handler);
866 for (
const auto &I : *block) {
867 if (std::optional<CFGStmt> cs = I.getAs<
CFGStmt>())
868 tf.Visit(
const_cast<Stmt *
>(cs->getStmt()));
871 if (
auto *as = dyn_cast_or_null<GCCAsmStmt>(terminator.
getStmt()))
874 return vals.updateValueVectorWithScratch(block);
885 llvm::BitVector hadUse;
888 bool hadAnyUse =
false;
891 unsigned currentBlock = 0;
893 PruneBlocksHandler(
unsigned numBlocks) : hadUse(numBlocks,
false) {}
895 ~PruneBlocksHandler()
override =
default;
899 hadUse[currentBlock] =
true;
907 hadUse[currentBlock] =
true;
920 CFGBlockValues vals(cfg);
921 vals.computeSetOfDeclarations(dc);
922 if (vals.hasNoDeclarations())
928 ClassifyRefs classification(ac);
933 ValueVector &vec = vals.getValueVector(&entry);
934 const unsigned n = vals.getNumEntries();
935 for (
unsigned j = 0; j < n; ++j) {
951 bool changed =
runOnBlock(block, cfg, ac, vals,
952 classification, wasAnalyzed, PBH);
954 if (changed || !previouslyVisited[block->
getBlockID()])
956 previouslyVisited[block->
getBlockID()] =
true;
963 for (
const auto *block : cfg)
965 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.
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
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
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()
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.
const half4 dst(half4 Src0, half4 Src1)
A worklist implementation for forward dataflow analysis.
void enqueueSuccessors(const CFGBlock *Block)
Iterator for iterating over Stmt * arrays that contain only T *.
unsigned NumVariablesAnalyzed