35#include "llvm/Support/Casting.h"
39#define DEBUG_TYPE "dataflow"
46 if (
Block ==
nullptr) {
50 if (!ACFG.isBlockReachable(*
Block))
52 if (
Block->getBlockID() == CurBlockID)
54 const auto &State = BlockToState[
Block->getBlockID()];
67 if (LHSValue == RHSValue && LHSValue)
75 if (
auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue))
76 if (
auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue))
77 return Env.
makeIff(*LHSBool, *RHSBool);
79 if (
auto *LHSPtr = dyn_cast_or_null<PointerValue>(LHSValue))
80 if (
auto *RHSPtr = dyn_cast_or_null<PointerValue>(RHSValue))
84 if (&LHSPtr->getPointeeLoc() == &RHSPtr->getPointeeLoc())
91 if (
auto *Top = llvm::dyn_cast<TopBoolValue>(&
V)) {
107 auto *B = dyn_cast_or_null<BoolValue>(Val);
112 if (&UnpackedVal == Val)
147 TransferVisitor(
const StmtToEnvMap &StmtToEnv, Environment &Env,
148 Environment::ValueModel &Model)
149 : StmtToEnv(StmtToEnv), Env(Env), Model(Model) {}
151 void VisitBinaryOperator(
const BinaryOperator *S) {
152 const Expr *LHS = S->getLHS();
153 assert(LHS !=
nullptr);
155 const Expr *RHS = S->getRHS();
156 assert(RHS !=
nullptr);
161 if (S->isAssignmentOp()) {
162 auto *LHSLoc = Env.getStorageLocation(*LHS);
163 if (LHSLoc ==
nullptr)
167 Env.setStorageLocation(*S, *LHSLoc);
172 S->isCompoundAssignmentOp() ?
nullptr : Env.getValue(*RHS);
173 if (RHSVal ==
nullptr) {
176 RHSVal = Env.createValue(LHS->getType());
177 if (RHSVal ==
nullptr) {
181 Env.clearValue(*LHSLoc);
187 Env.setValue(*LHSLoc, *RHSVal);
191 switch (S->getOpcode()) {
194 BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
195 BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
197 if (S->getOpcode() == BO_LAnd)
198 Env.setValue(*S, Env.makeAnd(LHSVal, RHSVal));
200 Env.setValue(*S, Env.makeOr(LHSVal, RHSVal));
206 Env.setValue(*S, S->getOpcode() == BO_EQ ? LHSEqRHSValue
207 : Env.makeNot(LHSEqRHSValue));
219 void VisitDeclRefExpr(
const DeclRefExpr *S) {
220 const ValueDecl *VD = S->getDecl();
221 assert(VD !=
nullptr);
235 auto *DeclLoc = Env.getStorageLocation(*VD);
236 if (DeclLoc ==
nullptr)
239 Env.setStorageLocation(*S, *DeclLoc);
242 void VisitDeclStmt(
const DeclStmt *S) {
250 void ProcessVarDecl(
const VarDecl &D) {
252 if (D.hasGlobalStorage())
258 if (D.getType()->isReferenceType() && Env.getStorageLocation(D) !=
nullptr)
261 assert(Env.getStorageLocation(D) ==
nullptr);
263 Env.setStorageLocation(D, Env.createObject(D));
268 if (
const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) {
274 for (
const auto *B : Decomp->bindings()) {
275 if (
auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) {
276 auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase());
282 VisitDeclRefExpr(DE);
285 if (
auto *Loc = Env.getStorageLocation(*ME))
286 Env.setStorageLocation(*B, *Loc);
287 }
else if (
auto *VD = B->getHoldingVar()) {
295 auto *VDLoc = Env.getStorageLocation(*VD);
296 assert(VDLoc !=
nullptr);
297 Env.setStorageLocation(*B, *VDLoc);
303 void VisitCastExpr(
const CastExpr *S) {
304 const Expr *SubExpr = S->getSubExpr();
305 assert(SubExpr !=
nullptr);
307 switch (S->getCastKind()) {
308 case CK_IntegralToBoolean: {
312 if (
auto *SubExprVal =
313 dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr)))
314 Env.setValue(*S, *SubExprVal);
318 Env.setValue(*S, Env.makeAtomicBoolValue());
322 case CK_LValueToRValue: {
326 if (SubExprVal ==
nullptr)
329 Env.setValue(*S, *SubExprVal);
333 case CK_BaseToDerived: {
338 RecordStorageLocation *Loc =
nullptr;
339 if (S->getType()->isPointerType()) {
340 auto *PV = Env.get<PointerValue>(*SubExpr);
345 assert(S->getType()->isRecordType());
346 if (SubExpr->isGLValue()) {
347 Loc = Env.get<RecordStorageLocation>(*SubExpr);
349 Loc = &Env.getResultObjectLocation(*SubExpr);
358 QualType Derived = S->getType().getNonReferenceType();
359 if (Derived->isPointerType()) {
360 Derived = Derived->getPointeeType();
365 for (
const FieldDecl *Field :
366 Env.getDataflowAnalysisContext().getModeledFields(Derived)) {
367 assert(Field !=
nullptr);
368 QualType FieldType =
Field->getType();
369 if (FieldType->isReferenceType()) {
370 Loc->addChild(*Field,
nullptr);
372 Loc->addChild(*Field, &Env.createStorageLocation(FieldType));
375 for (
const auto &Entry :
376 Env.getDataflowAnalysisContext().getSyntheticFields(Derived)) {
377 Loc->addSyntheticField(Entry.getKey(),
378 Env.createStorageLocation(Entry.getValue()));
381 Env.initializeFieldsWithValues(*Loc, Derived);
386 case CK_IntegralCast:
392 case CK_UncheckedDerivedToBase:
393 case CK_DerivedToBase:
394 case CK_ConstructorConversion:
395 case CK_UserDefinedConversion:
403 case CK_NullToPointer: {
404 auto &NullPointerVal =
405 Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());
406 Env.setValue(*S, NullPointerVal);
409 case CK_NullToMemberPointer:
413 case CK_FunctionToPointerDecay: {
414 StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr);
415 if (PointeeLoc ==
nullptr)
418 Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc));
421 case CK_BuiltinFnToFnPtr:
432 void VisitUnaryOperator(
const UnaryOperator *S) {
433 const Expr *SubExpr = S->getSubExpr();
434 assert(SubExpr !=
nullptr);
436 switch (S->getOpcode()) {
438 const auto *SubExprVal = Env.get<PointerValue>(*SubExpr);
439 if (SubExprVal ==
nullptr)
442 Env.setStorageLocation(*S, SubExprVal->getPointeeLoc());
447 if (S->getType()->isMemberPointerType())
450 if (StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr))
451 Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc));
455 auto *SubExprVal = dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr));
456 if (SubExprVal ==
nullptr)
459 Env.setValue(*S, Env.makeNot(*SubExprVal));
469 if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr()))
470 Env.clearValue(*Loc);
478 if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr()))
479 Env.clearValue(*Loc);
486 void VisitCXXThisExpr(
const CXXThisExpr *S) {
487 auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
488 if (ThisPointeeLoc ==
nullptr)
493 Env.setValue(*S, Env.create<PointerValue>(*ThisPointeeLoc));
496 void VisitCXXNewExpr(
const CXXNewExpr *S) {
497 if (
Value *Val = Env.createValue(S->getType()))
498 Env.setValue(*S, *Val);
501 void VisitCXXDeleteExpr(
const CXXDeleteExpr *S) {
508 void VisitReturnStmt(
const ReturnStmt *S) {
509 if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts)
512 auto *
Ret = S->getRetValue();
516 if (
Ret->isPRValue()) {
517 if (
Ret->getType()->isRecordType())
520 auto *Val = Env.getValue(*Ret);
525 Env.setReturnValue(Val);
527 auto *Loc = Env.getStorageLocation(*Ret);
532 Env.setReturnStorageLocation(Loc);
536 void VisitMemberExpr(
const MemberExpr *S) {
537 ValueDecl *
Member = S->getMemberDecl();
538 assert(
Member !=
nullptr);
541 if (
Member->isFunctionOrFunctionTemplate())
548 if (
auto *D = dyn_cast<VarDecl>(
Member)) {
549 if (D->hasGlobalStorage()) {
550 auto *VarDeclLoc = Env.getStorageLocation(*D);
551 if (VarDeclLoc ==
nullptr)
554 Env.setStorageLocation(*S, *VarDeclLoc);
560 if (BaseLoc ==
nullptr)
563 auto *MemberLoc = BaseLoc->getChild(*
Member);
564 if (MemberLoc ==
nullptr)
566 Env.setStorageLocation(*S, *MemberLoc);
569 void VisitCXXDefaultArgExpr(
const CXXDefaultArgExpr *S) {
570 const Expr *ArgExpr = S->getExpr();
571 assert(ArgExpr !=
nullptr);
574 if (S->isPRValue() && S->getType()->isRecordType()) {
575 auto &Loc = Env.getResultObjectLocation(*S);
576 Env.initializeFieldsWithValues(Loc);
580 void VisitCXXDefaultInitExpr(
const CXXDefaultInitExpr *S) {
581 const Expr *InitExpr = S->getExpr();
582 assert(InitExpr !=
nullptr);
587 if (S->getType()->isRecordType() && S->isPRValue())
593 void VisitCXXConstructExpr(
const CXXConstructExpr *S) {
594 const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
595 assert(ConstructorDecl !=
nullptr);
600 if (!S->getType()->isRecordType()) {
601 transferInlineCall(S, ConstructorDecl);
605 RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);
607 if (ConstructorDecl->isCopyOrMoveConstructor()) {
610 assert(S->getNumArgs() != 0);
612 const Expr *Arg = S->getArg(0);
613 assert(Arg !=
nullptr);
615 auto *ArgLoc = Env.get<RecordStorageLocation>(*Arg);
616 if (ArgLoc ==
nullptr)
634 Env.initializeFieldsWithValues(Loc, S->getType());
636 transferInlineCall(S, ConstructorDecl);
639 void VisitCXXOperatorCallExpr(
const CXXOperatorCallExpr *S) {
640 if (S->getOperator() == OO_Equal) {
641 assert(S->getNumArgs() == 2);
643 const Expr *Arg0 = S->getArg(0);
644 assert(Arg0 !=
nullptr);
646 const Expr *Arg1 = S->getArg(1);
647 assert(Arg1 !=
nullptr);
651 dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee());
654 if (!
Method->isCopyAssignmentOperator() &&
655 !
Method->isMoveAssignmentOperator())
658 RecordStorageLocation *LocSrc =
nullptr;
659 if (Arg1->isPRValue()) {
660 LocSrc = &Env.getResultObjectLocation(*Arg1);
662 LocSrc = Env.get<RecordStorageLocation>(*Arg1);
664 auto *LocDst = Env.get<RecordStorageLocation>(*Arg0);
666 if (LocSrc ==
nullptr || LocDst ==
nullptr)
674 copyRecord(*LocSrc, *LocDst, Env, Arg0->getType());
679 if (S->getType().getCanonicalType().getUnqualifiedType() !=
680 LocDst->getType().getCanonicalType().getUnqualifiedType()) {
681 auto ReturnDecl = S->getType()->getAsCXXRecordDecl();
682 auto DstDecl = LocDst->getType()->getAsCXXRecordDecl();
683 if (ReturnDecl ==
nullptr || DstDecl ==
nullptr)
685 if (!DstDecl->isDerivedFrom(ReturnDecl))
690 Env.setStorageLocation(*S, *LocDst);
692 copyRecord(*LocDst, Env.getResultObjectLocation(*S), Env);
702 void VisitCXXRewrittenBinaryOperator(
const CXXRewrittenBinaryOperator *RBO) {
706 void VisitCallExpr(
const CallExpr *S) {
710 if (S->isCallToStdMove()) {
711 assert(S->getNumArgs() == 1);
713 const Expr *Arg = S->getArg(0);
714 assert(Arg !=
nullptr);
716 auto *ArgLoc = Env.getStorageLocation(*Arg);
717 if (ArgLoc ==
nullptr)
720 Env.setStorageLocation(*S, *ArgLoc);
721 }
else if (S->getDirectCallee() !=
nullptr &&
722 S->getDirectCallee()->getBuiltinID() ==
723 Builtin::BI__builtin_expect) {
724 assert(S->getNumArgs() > 0);
725 assert(S->getArg(0) !=
nullptr);
726 auto *ArgVal = Env.getValue(*S->getArg(0));
727 if (ArgVal ==
nullptr)
729 Env.setValue(*S, *ArgVal);
730 }
else if (
const FunctionDecl *F = S->getDirectCallee()) {
731 transferInlineCall(S, F);
735 if (S->getType()->isRecordType() && S->isPRValue()) {
736 RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);
737 Env.initializeFieldsWithValues(Loc);
742 void VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *S) {
743 const Expr *SubExpr = S->getSubExpr();
744 assert(SubExpr !=
nullptr);
746 StorageLocation &Loc = Env.createStorageLocation(*S);
747 Env.setStorageLocation(*S, Loc);
749 if (SubExpr->getType()->isRecordType())
754 if (
Value *SubExprVal = Env.getValue(*SubExpr))
755 Env.setValue(Loc, *SubExprVal);
758 void VisitCXXBindTemporaryExpr(
const CXXBindTemporaryExpr *S) {
759 const Expr *SubExpr = S->getSubExpr();
760 assert(SubExpr !=
nullptr);
765 void VisitConditionalOperator(
const ConditionalOperator *S) {
766 const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr());
767 const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr());
769 if (TrueEnv ==
nullptr || FalseEnv ==
nullptr) {
777 if (S->isGLValue()) {
778 StorageLocation *TrueLoc = TrueEnv->getStorageLocation(*S->getTrueExpr());
779 StorageLocation *FalseLoc =
780 FalseEnv->getStorageLocation(*S->getFalseExpr());
781 if (TrueLoc == FalseLoc && TrueLoc !=
nullptr) {
782 Env.setStorageLocation(*S, *TrueLoc);
783 }
else if (!S->getType()->isRecordType()) {
796 S->getType(), TrueEnv->getValue(*S->getTrueExpr()), *TrueEnv,
797 FalseEnv->getValue(*S->getFalseExpr()), *FalseEnv, Env,
799 StorageLocation &Loc = Env.createStorageLocation(*S);
800 Env.setStorageLocation(*S, Loc);
801 Env.setValue(Loc, *Val);
804 }
else if (!S->getType()->isRecordType()) {
821 S->getType(), TrueEnv->getValue(*S->getTrueExpr()), *TrueEnv,
822 FalseEnv->getValue(*S->getFalseExpr()), *FalseEnv, Env, Model))
823 Env.setValue(*S, *Val);
827 void VisitInitListExpr(
const InitListExpr *S) {
828 QualType
Type = S->getType();
830 if (!
Type->isRecordType()) {
833 if (!
Type->isArrayType() && S->getNumInits() == 1)
839 if (S->isSemanticForm() && S->isTransparent())
842 RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);
849 RecordInitListHelper InitListHelper(S);
851 for (
auto [Field,
Init] : InitListHelper.field_inits()) {
852 if (
Field->getType()->isRecordType())
854 if (
Field->getType()->isReferenceType()) {
855 assert(
Field->getType().getCanonicalType()->getPointeeType() ==
856 Init->getType().getCanonicalType());
857 Loc.setChild(*Field, &Env.createObject(
Field->getType(),
Init));
860 assert(
Field->getType().getCanonicalType().getUnqualifiedType() ==
861 Init->getType().getCanonicalType().getUnqualifiedType());
862 StorageLocation *FieldLoc = Loc.getChild(*Field);
864 assert(FieldLoc !=
nullptr);
867 Init->getType()->isPointerType())
869 &Env.getOrCreateNullPointerValue(
Init->getType()->getPointeeType());
871 Val = Env.createValue(
Field->getType());
873 Env.setValue(*FieldLoc, *Val);
876 for (
const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) {
877 QualType FieldType = FieldLoc->getType();
878 if (FieldType->isRecordType()) {
881 if (
Value *Val = Env.createValue(FieldType))
882 Env.setValue(*FieldLoc, *Val);
889 void VisitCXXBoolLiteralExpr(
const CXXBoolLiteralExpr *S) {
890 Env.setValue(*S, Env.getBoolLiteralValue(S->getValue()));
893 void VisitIntegerLiteral(
const IntegerLiteral *S) {
894 Env.setValue(*S, Env.getIntLiteralValue(S->getValue()));
897 void VisitParenExpr(
const ParenExpr *S) {
901 auto *SubExpr = S->getSubExpr();
902 assert(SubExpr !=
nullptr);
906 void VisitExprWithCleanups(
const ExprWithCleanups *S) {
910 auto *SubExpr = S->getSubExpr();
911 assert(SubExpr !=
nullptr);
917 BoolValue &getLogicOperatorSubExprValue(
const Expr &SubExpr) {
921 if (
const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr))
923 dyn_cast_or_null<BoolValue>(SubExprEnv->getValue(SubExpr)))
931 if (Env.getValue(SubExpr) ==
nullptr)
933 if (
auto *Val = dyn_cast_or_null<BoolValue>(Env.getValue(SubExpr)))
938 return Env.makeAtomicBoolValue();
943 template <
typename E>
944 void transferInlineCall(
const E *S,
const FunctionDecl *F) {
945 const auto &Options = Env.getDataflowAnalysisContext().getOptions();
946 if (!(Options.ContextSensitiveOpts &&
947 Env.canDescend(Options.ContextSensitiveOpts->Depth, F)))
950 const AdornedCFG *ACFG = Env.getDataflowAnalysisContext().getAdornedCFG(F);
958 auto ExitBlock = ACFG->getCFG().getExit().getBlockID();
960 auto CalleeEnv = Env.pushCall(S);
965 auto Analysis = NoopAnalysis(ACFG->getDecl().getASTContext(),
966 DataflowAnalysisOptions{Options});
968 auto BlockToOutputState =
970 assert(BlockToOutputState);
971 assert(ExitBlock < BlockToOutputState->size());
973 auto &ExitState = (*BlockToOutputState)[ExitBlock];
976 Env.popCall(S, ExitState->Env);
979 const StmtToEnvMap &StmtToEnv;
981 Environment::ValueModel &Model;
988 TransferVisitor(StmtToEnv, Env, Model).Visit(&S);
Defines enum values for all the target-independent builtin functions.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines an enumeration for C++ overloaded operators.
C Language Family Type Representation.
Represents a single basic block in a source-level CFG.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
This represents one expression.
Stmt - This represents one statement.
bool isNullPtrType() const
bool isRecordType() const
BoolValue & makeBoolValue(const Formula &)
Creates a BoolValue wrapping a particular formula.
Supplements Environment with non-standard comparison and join operations.
Holds the state of the program (store and heap) at a given program point.
BoolValue & makeIff(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value represents LHS <=> RHS.
StorageLocation * getStorageLocation(const ValueDecl &D) const
Returns the storage location assigned to D in the environment, or null if D isn't assigned a storage ...
BoolValue & makeAtomicBoolValue() const
Returns an atomic boolean value.
Value * getValue(const StorageLocation &Loc) const
Returns the value assigned to Loc in the environment or null if Loc isn't assigned a value in the env...
BoolValue & getBoolLiteralValue(bool Value) const
Returns a symbolic boolean value that models a boolean literal equal to Value
DataflowAnalysisContext & getDataflowAnalysisContext() const
Returns the DataflowAnalysisContext used by the environment.
static Value * joinValues(QualType Ty, Value *Val1, const Environment &Env1, Value *Val2, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
Returns a value that approximates both Val1 and Val2, or null if no such value can be produced.
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc)
Assigns Loc as the storage location of D in the environment.
void setValue(const StorageLocation &Loc, Value &Val)
Assigns Val as the value of Loc in the environment.
Maps statements to the environments of basic blocks that contain them.
const Environment * getEnvironment(const Stmt &S) const
Returns the environment of the basic block that contains S.
Base class for all values computed by abstract interpretation.
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, Environment::ValueModel &Model)
Evaluates S and updates Env accordingly.
static void propagateValueOrStorageLocation(const Expr &From, const Expr &To, Environment &Env)
static void propagateStorageLocation(const Expr &From, const Expr &To, Environment &Env)
void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, Environment &Env, QualType TypeToCopy=QualType())
Copies a record (struct, class, or union) from Src to Dst.
static void propagateValue(const Expr &From, const Expr &To, Environment &Env)
static Value * maybeUnpackLValueExpr(const Expr &E, Environment &Env)
static BoolValue & unpackValue(BoolValue &V, Environment &Env)
static BoolValue & evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, Environment &Env)
RecordStorageLocation * getBaseObjectLocation(const MemberExpr &ME, const Environment &Env)
Returns the storage location for the base object of a MemberExpr, or null if none is defined in the e...
llvm::Expected< std::vector< std::optional< DataflowAnalysisState< typename AnalysisT::Lattice > > > > runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis, const Environment &InitEnv, CFGEltCallbacks< AnalysisT > PostAnalysisCallbacks={}, std::int32_t MaxBlockVisits=kDefaultMaxBlockVisits)
Performs dataflow analysis and returns a mapping from basic block IDs to dataflow analysis states tha...
PRESERVE_NONE bool Ret(InterpState &S, CodePtr &PC)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Type
The name was classified as a type.
U cast(CodeGen::Address addr)