summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis/BodyFarm.cpp
diff options
context:
space:
mode:
authorDevin Coughlin <dcoughlin@apple.com>2017-11-06 22:12:19 +0000
committerDevin Coughlin <dcoughlin@apple.com>2017-11-06 22:12:19 +0000
commit046833e5fbebe5f243820c664b58d74f0169ae37 (patch)
tree3aedbf28a963696e916c60694c222f923a834818 /clang/lib/Analysis/BodyFarm.cpp
parentba84ca9efb78b066aef196bddfee3c20bed1043a (diff)
downloadbcm5719-llvm-046833e5fbebe5f243820c664b58d74f0169ae37.tar.gz
bcm5719-llvm-046833e5fbebe5f243820c664b58d74f0169ae37.zip
[analyzer] Model correct dispatch_once() 'done' value in BodyFarm
The analyzer's BodyFarm models dispatch_once() by comparing the passed-in predicate against a known 'done' value. If the predicate does not have that value, the model updates the predicate to have that value and executes the passed in block. Unfortunately, the current model uses the wrong 'done' value: 1 instead of ~0. This interferes with libdispatch's static inline function _dispatch_once(), which enables a fast path if the block has already been executed. That function uses __builtin_assume() to tell the compiler that the done flag is set to ~0 on exit. When r302880 added modeling of __builtin_assume(), this caused the analyzer to assume 1 == ~0. This in turn caused the analyzer to never explore any code after a call to dispatch_once(). This patch regains the missing coverage by updating BodyFarm to use the correct 'done' value. rdar://problem/34413048 Differential Revision: https://reviews.llvm.org/D39691 llvm-svn: 317516
Diffstat (limited to 'clang/lib/Analysis/BodyFarm.cpp')
-rw-r--r--clang/lib/Analysis/BodyFarm.cpp37
1 files changed, 16 insertions, 21 deletions
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index 3e62ae5fe63..e5d3c5ce5bc 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -96,8 +96,8 @@ public:
/// Create a Return statement.
ReturnStmt *makeReturn(const Expr *RetVal);
- /// Create an integer literal.
- IntegerLiteral *makeIntegerLiteral(uint64_t value);
+ /// Create an integer literal expression of the given type.
+ IntegerLiteral *makeIntegerLiteral(uint64_t Value, QualType Ty);
/// Create a member expression.
MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
@@ -206,11 +206,9 @@ ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
nullptr);
}
-IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t value) {
- return IntegerLiteral::Create(C,
- llvm::APInt(
- /*numBits=*/C.getTypeSize(C.IntTy), value),
- /*QualType=*/C.IntTy, SourceLocation());
+IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) {
+ llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value);
+ return IntegerLiteral::Create(C, APValue, Ty, SourceLocation());
}
MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
@@ -447,7 +445,8 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
// Create assignment.
BinaryOperator *FlagAssignment = M.makeAssignment(
- Deref, M.makeIntegralCast(M.makeIntegerLiteral(1), DerefType), DerefType);
+ Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType),
+ DerefType);
IfStmt *Out = new (C)
IfStmt(C, SourceLocation(),
@@ -486,8 +485,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
// sets it, and calls the block. Basically, an AST dump of:
//
// void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
- // if (!*predicate) {
- // *predicate = 1;
+ // if (*predicate != ~0l) {
+ // *predicate = ~0l;
// block();
// }
// }
@@ -504,7 +503,9 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
/*SourceLocation=*/SourceLocation());
// (2) Create the assignment to the predicate.
- IntegerLiteral *IL = M.makeIntegerLiteral(1);
+ Expr *DoneValue =
+ new (C) UnaryOperator(M.makeIntegerLiteral(0, C.LongTy), UO_Not, C.LongTy,
+ VK_RValue, OK_Ordinary, SourceLocation());
BinaryOperator *B =
M.makeAssignment(
@@ -512,7 +513,7 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
M.makeLvalueToRvalue(
M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
PredicateTy),
- M.makeIntegralCast(IL, PredicateTy),
+ M.makeIntegralCast(DoneValue, PredicateTy),
PredicateTy);
// (3) Create the compound statement.
@@ -528,20 +529,14 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
PredicateQPtrTy),
PredicateTy),
PredicateTy);
-
- UnaryOperator *UO = new (C) UnaryOperator(
- /* input=*/ LValToRval,
- /* opc=*/ UO_LNot,
- /* QualType=*/ C.IntTy,
- /* ExprValueKind=*/ VK_RValue,
- /* ExprObjectKind=*/ OK_Ordinary, SourceLocation());
-
+
+ Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE);
// (5) Create the 'if' statement.
IfStmt *If = new (C) IfStmt(C, SourceLocation(),
/* IsConstexpr=*/ false,
/* init=*/ nullptr,
/* var=*/ nullptr,
- /* cond=*/ UO,
+ /* cond=*/ GuardCondition,
/* then=*/ CS);
return If;
}
OpenPOWER on IntegriCloud