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;
83 void computeMap(
const DeclContext &dc);
86 unsigned size()
const {
return map.size(); }
89 std::optional<unsigned> getValueIndex(
const VarDecl *d)
const;
94void DeclToIndex::computeMap(
const DeclContext &dc) {
96 DeclContext::specific_decl_iterator<VarDecl> I(dc.
decls_begin()),
98 for ( ; I != E; ++I) {
99 const VarDecl *vd = *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 {
137 SmallVector<ValueVector, 8> vals;
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);
164 Value getValue(
const CFGBlock *block,
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)];
236 const DeclRefExpr *dr;
239 FindVarResult(
const VarDecl *vd,
const DeclRefExpr *dr) : vd(vd), dr(dr) {}
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 ConstStmtVisitor<ClassifyRefs> {
279 enum Class {
Init, Use, SelfInit, ConstRefUse, ConstPtrUse, Ignore };
282 const DeclContext *DC;
283 llvm::DenseMap<const DeclRefExpr *, Class> Classification;
286 return ::isTrackedVar(VD, DC);
289 void classify(
const Expr *E,
Class C);
292 ClassifyRefs(AnalysisDeclContext &AC) : DC(
cast<DeclContext>(AC.getDecl())) {}
294 void VisitDeclStmt(
const DeclStmt *DS);
295 void VisitUnaryOperator(
const UnaryOperator *UO);
296 void VisitBinaryOperator(
const BinaryOperator *BO);
297 void VisitCallExpr(
const CallExpr *CE);
298 void VisitCastExpr(
const CastExpr *CE);
299 void VisitOMPExecutableDirective(
const OMPExecutableDirective *ED);
301 void operator()(
const Stmt *S) { Visit(S); }
303 Class get(
const DeclRefExpr *DRE)
const {
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);
372 FindVarResult Var =
findVar(E, DC);
373 if (
const DeclRefExpr *DRE = Var.getDeclRefExpr()) {
374 auto &
Class = Classification[DRE];
379void ClassifyRefs::VisitDeclStmt(
const DeclStmt *DS) {
380 for (
auto *DI : DS->
decls()) {
381 auto *VD = dyn_cast<VarDecl>(DI);
384 Classification[DRE] = SelfInit;
388void ClassifyRefs::VisitBinaryOperator(
const BinaryOperator *BO) {
395 classify(BO->
getLHS(), Use);
397 classify(BO->
getLHS(), Ignore);
400void ClassifyRefs::VisitUnaryOperator(
const UnaryOperator *UO) {
407void ClassifyRefs::VisitOMPExecutableDirective(
408 const OMPExecutableDirective *ED) {
409 for (Stmt *S : OMPExecutableDirective::used_clauses_children(ED->clauses()))
420 return FTD->getTemplatedDecl()->hasTrivialBody();
421 return FD->hasTrivialBody();
426void ClassifyRefs::VisitCallExpr(
const CallExpr *CE) {
431 classify(CE->
getArg(0), Use);
440 for (
const Expr *Argument : CE->
arguments()) {
441 if (Argument->isGLValue()) {
442 if (Argument->getType().isConstQualified())
443 classify(Argument, isTrivialBody ? Ignore : ConstRefUse);
446 const auto *UO = dyn_cast<UnaryOperator>(Ex);
448 classify(UO->
getSubExpr(), isTrivialBody ? Ignore : ConstPtrUse);
453void ClassifyRefs::VisitCastExpr(
const 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 ConstStmtVisitor<TransferFunctions> {
473 CFGBlockValues &vals;
475 const CFGBlock *block;
476 AnalysisDeclContext ∾
477 const ClassifyRefs &classification;
478 ObjCNoReturn objCNoRet;
479 UninitVariablesHandler &handler;
482 TransferFunctions(CFGBlockValues &vals,
const CFG &cfg,
483 const CFGBlock *block, AnalysisDeclContext &ac,
484 const ClassifyRefs &classification,
485 UninitVariablesHandler &handler)
486 : vals(vals), cfg(cfg), block(block), ac(ac),
487 classification(classification), objCNoRet(ac.getASTContext()),
490 void reportUse(
const Expr *ex,
const VarDecl *vd);
491 void reportConstRefUse(
const Expr *ex,
const VarDecl *vd);
492 void reportConstPtrUse(
const Expr *ex,
const VarDecl *vd);
494 void VisitBinaryOperator(
const BinaryOperator *bo);
495 void VisitBlockExpr(
const BlockExpr *be);
496 void VisitCallExpr(
const CallExpr *ce);
497 void VisitDeclRefExpr(
const DeclRefExpr *dr);
498 void VisitDeclStmt(
const DeclStmt *ds);
499 void VisitGCCAsmStmt(
const GCCAsmStmt *as);
500 void VisitObjCForCollectionStmt(
const ObjCForCollectionStmt *FS);
501 void VisitObjCMessageExpr(
const ObjCMessageExpr *ME);
502 void VisitOMPExecutableDirective(
const OMPExecutableDirective *ED);
508 FindVarResult
findVar(
const Expr *ex) {
512 UninitUse getUninitUse(
const Expr *ex,
const VarDecl *vd,
Value v) {
565 SmallVector<const CFGBlock*, 32> Queue;
567 Queue.push_back(block);
572 while (!Queue.empty()) {
573 const CFGBlock *B = Queue.pop_back_val();
577 Use.setUninitAfterCall();
581 const CFGBlock *Pred = *I;
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) {
624 const Stmt *Term =
Block->getTerminatorStmt();
625 if (SuccsVisited[BlockID] && SuccsVisited[BlockID] <
Block->succ_size() &&
631 E =
Block->succ_end(); I != E; ++I) {
632 const CFGBlock *Succ = *I;
639 const Stmt *Label = Succ->
getLabel();
643 UninitUse::Branch Branch;
646 Use.addUninitBranch(Branch);
648 UninitUse::Branch 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();
688void TransferFunctions::VisitObjCForCollectionStmt(
689 const ObjCForCollectionStmt *FS) {
691 if (
const auto *DS = dyn_cast<DeclStmt>(FS->
getElement())) {
698void TransferFunctions::VisitOMPExecutableDirective(
699 const OMPExecutableDirective *ED) {
701 OMPExecutableDirective::used_clauses_children(ED->clauses())) {
702 assert(S &&
"Expected non-null used-in-clause child.");
705 if (!ED->isStandaloneDirective())
706 Visit(ED->getStructuredBlock());
709void TransferFunctions::VisitBlockExpr(
const BlockExpr *be) {
711 for (
const auto &I : bd->
captures()) {
712 const VarDecl *vd = I.getVariable();
723void TransferFunctions::VisitCallExpr(
const CallExpr *ce) {
725 if (
Callee->hasAttr<ReturnsTwiceAttr>()) {
733 else if (
Callee->hasAttr<AnalyzerNoReturnAttr>()) {
741 vals.setAllScratchValues(
Unknown);
746void TransferFunctions::VisitDeclRefExpr(
const DeclRefExpr *dr) {
747 switch (classification.get(dr)) {
748 case ClassifyRefs::Ignore:
750 case ClassifyRefs::Use:
753 case ClassifyRefs::Init:
756 case ClassifyRefs::SelfInit:
759 case ClassifyRefs::ConstRefUse:
762 case ClassifyRefs::ConstPtrUse:
768void TransferFunctions::VisitBinaryOperator(
const BinaryOperator *BO) {
771 if (
const VarDecl *VD = Var.getDecl())
776void TransferFunctions::VisitDeclStmt(
const DeclStmt *DS) {
777 for (
const Decl *DI : DS->
decls()) {
778 const auto *VD = dyn_cast<VarDecl>(DI);
792 }
else if (VD->getInit()) {
812void TransferFunctions::VisitGCCAsmStmt(
const GCCAsmStmt *as) {
818 for (
const Expr *O : as->
outputs()) {
823 while (
const auto *UO = dyn_cast<UnaryOperator>(Ex))
829 if (
const VarDecl *VD =
findVar(Ex).getDecl())
835void TransferFunctions::VisitObjCMessageExpr(
const ObjCMessageExpr *ME) {
839 vals.setAllScratchValues(
Unknown);
849 const ClassifyRefs &classification,
850 llvm::BitVector &wasAnalyzed,
857 E = block->
pred_end(); I != E; ++I) {
862 vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
867 TransferFunctions tf(vals, cfg, block, ac, classification, handler);
868 for (
const auto &I : *block) {
869 if (std::optional<CFGStmt> cs = I.getAs<
CFGStmt>())
870 tf.Visit(
const_cast<Stmt *
>(cs->getStmt()));
873 if (
auto *as = dyn_cast_or_null<GCCAsmStmt>(terminator.
getStmt()))
876 return vals.updateValueVectorWithScratch(block);
885struct PruneBlocksHandler :
public UninitVariablesHandler {
887 llvm::BitVector hadUse;
890 bool hadAnyUse =
false;
893 unsigned currentBlock = 0;
895 PruneBlocksHandler(
unsigned numBlocks) : hadUse(numBlocks,
false) {}
897 ~PruneBlocksHandler()
override =
default;
899 void handleUseOfUninitVariable(
const VarDecl *vd,
900 const UninitUse &use)
override {
901 hadUse[currentBlock] =
true;
908 void handleSelfInit(
const VarDecl *vd)
override {
909 hadUse[currentBlock] =
true;
922 CFGBlockValues vals(cfg);
923 vals.computeSetOfDeclarations(dc);
924 if (vals.hasNoDeclarations())
930 ClassifyRefs classification(ac);
935 ValueVector &vec = vals.getValueVector(&entry);
936 const unsigned n = vals.getNumEntries();
937 for (
unsigned j = 0; j < n; ++j) {
953 bool changed =
runOnBlock(block, cfg, ac, vals,
954 classification, wasAnalyzed, PBH);
956 if (changed || !previouslyVisited[block->
getBlockID()])
958 previouslyVisited[block->
getBlockID()] =
true;
965 for (
const auto *block : cfg)
967 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 const DeclRefExpr * getSelfInitExpr(const VarDecl *VD)
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 bool hasTrivialBody(const CallExpr *CE)
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 recordIsNotEmpty(const RecordDecl *RD)
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
static bool isCompoundAssignmentOp(Opcode Opc)
ArrayRef< Capture > captures() const
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
CastKind getCastKind() const
const CFGBlock * dequeue()
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.
const Decl * getSingleDecl() const
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.
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
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
Expr * getSubExpr() const
static bool isIncrementDecrementOp(Opcode Op)
@ 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.
bool isa(CodeGen::Address addr)
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)
unsigned NumVariablesAnalyzed