Thread safety analysis: Unwrap __builtin_expect in getTrylockCallExpr

Summary:
When people are really sure they'll get the lock they sometimes use
__builtin_expect. It's also used by some assertion implementations.
Asserting that try-lock succeeded is basically the same as asserting
that the lock is not held by anyone else (and acquiring it).

Reviewers: aaron.ballman, delesley

Reviewed By: aaron.ballman

Subscribers: kristina, cfe-commits

Differential Revision: https://reviews.llvm.org/D52398

llvm-svn: 343681
This commit is contained in:
Aaron Puchert 2018-10-03 11:58:19 +00:00
parent d5a39553ff
commit 7146b0032f
2 changed files with 20 additions and 1 deletions

View File

@ -33,6 +33,7 @@
#include "clang/Analysis/Analyses/ThreadSafetyUtil.h" #include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h" #include "clang/Analysis/CFG.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LLVM.h" #include "clang/Basic/LLVM.h"
#include "clang/Basic/OperatorKinds.h" #include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceLocation.h"
@ -1388,8 +1389,11 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
if (!Cond) if (!Cond)
return nullptr; return nullptr;
if (const auto *CallExp = dyn_cast<CallExpr>(Cond)) if (const auto *CallExp = dyn_cast<CallExpr>(Cond)) {
if (CallExp->getBuiltinCallee() == Builtin::BI__builtin_expect)
return getTrylockCallExpr(CallExp->getArg(0), C, Negate);
return CallExp; return CallExp;
}
else if (const auto *PE = dyn_cast<ParenExpr>(Cond)) else if (const auto *PE = dyn_cast<ParenExpr>(Cond))
return getTrylockCallExpr(PE->getSubExpr(), C, Negate); return getTrylockCallExpr(PE->getSubExpr(), C, Negate);
else if (const auto *CE = dyn_cast<ImplicitCastExpr>(Cond)) else if (const auto *CE = dyn_cast<ImplicitCastExpr>(Cond))

View File

@ -1754,6 +1754,13 @@ struct TestTryLock {
mu.Unlock(); mu.Unlock();
} }
void foo2_builtin_expect() {
if (__builtin_expect(!mu.TryLock(), false))
return;
a = 2;
mu.Unlock();
}
void foo3() { void foo3() {
bool b = mu.TryLock(); bool b = mu.TryLock();
if (b) { if (b) {
@ -1762,6 +1769,14 @@ struct TestTryLock {
} }
} }
void foo3_builtin_expect() {
bool b = mu.TryLock();
if (__builtin_expect(b, true)) {
a = 3;
mu.Unlock();
}
}
void foo4() { void foo4() {
bool b = mu.TryLock(); bool b = mu.TryLock();
if (!b) return; if (!b) return;