]> granicus.if.org Git - clang/commitdiff
Thread safety analysis: Unwrap __builtin_expect in getTrylockCallExpr
authorAaron Puchert <aaronpuchert@alice-dsl.net>
Wed, 3 Oct 2018 11:58:19 +0000 (11:58 +0000)
committerAaron Puchert <aaronpuchert@alice-dsl.net>
Wed, 3 Oct 2018 11:58:19 +0000 (11:58 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@343681 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/ThreadSafety.cpp
test/SemaCXX/warn-thread-safety-analysis.cpp

index 65904fd360038cf2f0e280b70d28af67d3a6e17e..be1f8b8eebe39bfb905530f9587b4201c3277a0b 100644 (file)
@@ -33,6 +33,7 @@
 #include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
 #include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Analysis/CFG.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/Basic/SourceLocation.h"
@@ -1388,8 +1389,11 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
   if (!Cond)
     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;
+  }
   else if (const auto *PE = dyn_cast<ParenExpr>(Cond))
     return getTrylockCallExpr(PE->getSubExpr(), C, Negate);
   else if (const auto *CE = dyn_cast<ImplicitCastExpr>(Cond))
index 057fd17608fe733cc3ae294902d23a92f447c958..ce3c6b9fcc0095575d27da3156aeeaf42305b4c5 100644 (file)
@@ -1754,6 +1754,13 @@ struct TestTryLock {
     mu.Unlock();
   }
 
+  void foo2_builtin_expect() {
+    if (__builtin_expect(!mu.TryLock(), false))
+      return;
+    a = 2;
+    mu.Unlock();
+  }
+
   void foo3() {
     bool b = mu.TryLock();
     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() {
     bool b = mu.TryLock();
     if (!b) return;