aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/ThreadSafetyCommon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis/ThreadSafetyCommon.cpp')
-rw-r--r--lib/Analysis/ThreadSafetyCommon.cpp335
1 files changed, 267 insertions, 68 deletions
diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp
index da88b78126fa..563e0590aacb 100644
--- a/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/lib/Analysis/ThreadSafetyCommon.cpp
@@ -28,7 +28,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-
#include <algorithm>
#include <climits>
#include <vector>
@@ -63,11 +62,9 @@ std::string getSourceLiteralString(const clang::Expr *CE) {
namespace til {
// Return true if E is a variable that points to an incomplete Phi node.
-static bool isIncompleteVar(const SExpr *E) {
- if (const auto *V = dyn_cast<Variable>(E)) {
- if (const auto *Ph = dyn_cast<Phi>(V->definition()))
- return Ph->status() == Phi::PH_Incomplete;
- }
+static bool isIncompletePhi(const SExpr *E) {
+ if (const auto *Ph = dyn_cast<Phi>(E))
+ return Ph->status() == Phi::PH_Incomplete;
return false;
}
@@ -91,6 +88,124 @@ til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
}
+
+inline bool isCalleeArrow(const Expr *E) {
+ const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts());
+ return ME ? ME->isArrow() : false;
+}
+
+
+/// \brief Translate a clang expression in an attribute to a til::SExpr.
+/// Constructs the context from D, DeclExp, and SelfDecl.
+///
+/// \param AttrExp The expression to translate.
+/// \param D The declaration to which the attribute is attached.
+/// \param DeclExp An expression involving the Decl to which the attribute
+/// is attached. E.g. the call to a function.
+CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
+ const NamedDecl *D,
+ const Expr *DeclExp,
+ VarDecl *SelfDecl) {
+ // If we are processing a raw attribute expression, with no substitutions.
+ if (!DeclExp)
+ return translateAttrExpr(AttrExp, nullptr);
+
+ CallingContext Ctx(nullptr, D);
+
+ // Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
+ // for formal parameters when we call buildMutexID later.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
+ Ctx.SelfArg = ME->getBase();
+ Ctx.SelfArrow = ME->isArrow();
+ } else if (const CXXMemberCallExpr *CE =
+ dyn_cast<CXXMemberCallExpr>(DeclExp)) {
+ Ctx.SelfArg = CE->getImplicitObjectArgument();
+ Ctx.SelfArrow = isCalleeArrow(CE->getCallee());
+ Ctx.NumArgs = CE->getNumArgs();
+ Ctx.FunArgs = CE->getArgs();
+ } else if (const CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
+ Ctx.NumArgs = CE->getNumArgs();
+ Ctx.FunArgs = CE->getArgs();
+ } else if (const CXXConstructExpr *CE =
+ dyn_cast<CXXConstructExpr>(DeclExp)) {
+ Ctx.SelfArg = nullptr; // Will be set below
+ Ctx.NumArgs = CE->getNumArgs();
+ Ctx.FunArgs = CE->getArgs();
+ } else if (D && isa<CXXDestructorDecl>(D)) {
+ // There's no such thing as a "destructor call" in the AST.
+ Ctx.SelfArg = DeclExp;
+ }
+
+ // Hack to handle constructors, where self cannot be recovered from
+ // the expression.
+ if (SelfDecl && !Ctx.SelfArg) {
+ DeclRefExpr SelfDRE(SelfDecl, false, SelfDecl->getType(), VK_LValue,
+ SelfDecl->getLocation());
+ Ctx.SelfArg = &SelfDRE;
+
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (!AttrExp)
+ return translateAttrExpr(Ctx.SelfArg, nullptr);
+ else // For most attributes.
+ return translateAttrExpr(AttrExp, &Ctx);
+ }
+
+ // If the attribute has no arguments, then assume the argument is "this".
+ if (!AttrExp)
+ return translateAttrExpr(Ctx.SelfArg, nullptr);
+ else // For most attributes.
+ return translateAttrExpr(AttrExp, &Ctx);
+}
+
+
+/// \brief Translate a clang expression in an attribute to a til::SExpr.
+// This assumes a CallingContext has already been created.
+CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
+ CallingContext *Ctx) {
+ if (!AttrExp)
+ return CapabilityExpr(nullptr, false);
+
+ if (auto* SLit = dyn_cast<StringLiteral>(AttrExp)) {
+ if (SLit->getString() == StringRef("*"))
+ // The "*" expr is a universal lock, which essentially turns off
+ // checks until it is removed from the lockset.
+ return CapabilityExpr(new (Arena) til::Wildcard(), false);
+ else
+ // Ignore other string literals for now.
+ return CapabilityExpr(nullptr, false);
+ }
+
+ bool Neg = false;
+ if (auto *OE = dyn_cast<CXXOperatorCallExpr>(AttrExp)) {
+ if (OE->getOperator() == OO_Exclaim) {
+ Neg = true;
+ AttrExp = OE->getArg(0);
+ }
+ }
+ else if (auto *UO = dyn_cast<UnaryOperator>(AttrExp)) {
+ if (UO->getOpcode() == UO_LNot) {
+ Neg = true;
+ AttrExp = UO->getSubExpr();
+ }
+ }
+
+ til::SExpr *E = translate(AttrExp, Ctx);
+
+ // Trap mutex expressions like nullptr, or 0.
+ // Any literal value is nonsense.
+ if (!E || isa<til::Literal>(E))
+ return CapabilityExpr(nullptr, false);
+
+ // Hack to deal with smart pointers -- strip off top-level pointer casts.
+ if (auto *CE = dyn_cast_or_null<til::Cast>(E)) {
+ if (CE->castOpcode() == til::CAST_objToPtr)
+ return CapabilityExpr(CE->expr(), Neg);
+ }
+ return CapabilityExpr(E, Neg);
+}
+
+
+
// Translate a clang statement or expression to a TIL expression.
// Also performs substitution of variables; Ctx provides the context.
// Dispatches on the type of S.
@@ -125,9 +240,10 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
case Stmt::ArraySubscriptExprClass:
return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
case Stmt::ConditionalOperatorClass:
- return translateConditionalOperator(cast<ConditionalOperator>(S), Ctx);
+ return translateAbstractConditionalOperator(
+ cast<ConditionalOperator>(S), Ctx);
case Stmt::BinaryConditionalOperatorClass:
- return translateBinaryConditionalOperator(
+ return translateAbstractConditionalOperator(
cast<BinaryConditionalOperator>(S), Ctx);
// We treat these as no-ops
@@ -162,6 +278,7 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
}
+
til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
CallingContext *Ctx) {
const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
@@ -197,17 +314,75 @@ til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
}
+const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) {
+ if (auto *V = dyn_cast<til::Variable>(E))
+ return V->clangDecl();
+ if (auto *Ph = dyn_cast<til::Phi>(E))
+ return Ph->clangDecl();
+ if (auto *P = dyn_cast<til::Project>(E))
+ return P->clangDecl();
+ if (auto *L = dyn_cast<til::LiteralPtr>(E))
+ return L->clangDecl();
+ return 0;
+}
+
+bool hasCppPointerType(const til::SExpr *E) {
+ auto *VD = getValueDeclFromSExpr(E);
+ if (VD && VD->getType()->isPointerType())
+ return true;
+ if (auto *C = dyn_cast<til::Cast>(E))
+ return C->castOpcode() == til::CAST_objToPtr;
+
+ return false;
+}
+
+
+// Grab the very first declaration of virtual method D
+const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) {
+ while (true) {
+ D = D->getCanonicalDecl();
+ CXXMethodDecl::method_iterator I = D->begin_overridden_methods(),
+ E = D->end_overridden_methods();
+ if (I == E)
+ return D; // Method does not override anything
+ D = *I; // FIXME: this does not work with multiple inheritance.
+ }
+ return nullptr;
+}
+
til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
CallingContext *Ctx) {
- til::SExpr *E = translate(ME->getBase(), Ctx);
- E = new (Arena) til::SApply(E);
- return new (Arena) til::Project(E, ME->getMemberDecl());
+ til::SExpr *BE = translate(ME->getBase(), Ctx);
+ til::SExpr *E = new (Arena) til::SApply(BE);
+
+ const ValueDecl *D = ME->getMemberDecl();
+ if (auto *VD = dyn_cast<CXXMethodDecl>(D))
+ D = getFirstVirtualDecl(VD);
+
+ til::Project *P = new (Arena) til::Project(E, D);
+ if (hasCppPointerType(BE))
+ P->setArrow(true);
+ return P;
}
til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
- CallingContext *Ctx) {
- // TODO -- Lock returned
+ CallingContext *Ctx,
+ const Expr *SelfE) {
+ if (CapabilityExprMode) {
+ // Handle LOCK_RETURNED
+ const FunctionDecl *FD = CE->getDirectCallee()->getMostRecentDecl();
+ if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
+ CallingContext LRCallCtx(Ctx);
+ LRCallCtx.AttrDecl = CE->getDirectCallee();
+ LRCallCtx.SelfArg = SelfE;
+ LRCallCtx.NumArgs = CE->getNumArgs();
+ LRCallCtx.FunArgs = CE->getArgs();
+ return const_cast<til::SExpr*>(
+ translateAttrExpr(At->getArg(), &LRCallCtx).sexpr());
+ }
+ }
+
til::SExpr *E = translate(CE->getCallee(), Ctx);
for (const auto *Arg : CE->arguments()) {
til::SExpr *A = translate(Arg, Ctx);
@@ -219,12 +394,31 @@ til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
const CXXMemberCallExpr *ME, CallingContext *Ctx) {
- return translateCallExpr(cast<CallExpr>(ME), Ctx);
+ if (CapabilityExprMode) {
+ // Ignore calls to get() on smart pointers.
+ if (ME->getMethodDecl()->getNameAsString() == "get" &&
+ ME->getNumArgs() == 0) {
+ auto *E = translate(ME->getImplicitObjectArgument(), Ctx);
+ return new (Arena) til::Cast(til::CAST_objToPtr, E);
+ // return E;
+ }
+ }
+ return translateCallExpr(cast<CallExpr>(ME), Ctx,
+ ME->getImplicitObjectArgument());
}
til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
+ if (CapabilityExprMode) {
+ // Ignore operator * and operator -> on smart pointers.
+ OverloadedOperatorKind k = OCE->getOperator();
+ if (k == OO_Star || k == OO_Arrow) {
+ auto *E = translate(OCE->getArg(0), Ctx);
+ return new (Arena) til::Cast(til::CAST_objToPtr, E);
+ // return E;
+ }
+ }
return translateCallExpr(cast<CallExpr>(OCE), Ctx);
}
@@ -238,8 +432,23 @@ til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
case UO_PreDec:
return new (Arena) til::Undefined(UO);
+ case UO_AddrOf: {
+ if (CapabilityExprMode) {
+ // interpret &Graph::mu_ as an existential.
+ if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr())) {
+ if (DRE->getDecl()->isCXXInstanceMember()) {
+ // This is a pointer-to-member expression, e.g. &MyClass::mu_.
+ // We interpret this syntax specially, as a wildcard.
+ auto *W = new (Arena) til::Wildcard();
+ return new (Arena) til::Project(W, DRE->getDecl());
+ }
+ }
+ }
+ // otherwise, & is a no-op
+ return translate(UO->getSubExpr(), Ctx);
+ }
+
// We treat these as no-ops
- case UO_AddrOf:
case UO_Deref:
case UO_Plus:
return translate(UO->getSubExpr(), Ctx);
@@ -360,7 +569,9 @@ til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
return E0;
}
til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
- return new (Arena) til::Load(E0);
+ return E0;
+ // FIXME!! -- get Load working properly
+ // return new (Arena) til::Load(E0);
}
case CK_NoOp:
case CK_DerivedToBase:
@@ -373,6 +584,8 @@ til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
default: {
// FIXME: handle different kinds of casts.
til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ if (CapabilityExprMode)
+ return E0;
return new (Arena) til::Cast(til::CAST_none, E0);
}
}
@@ -389,15 +602,12 @@ SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
til::SExpr *
-SExprBuilder::translateConditionalOperator(const ConditionalOperator *C,
- CallingContext *Ctx) {
- return new (Arena) til::Undefined(C);
-}
-
-
-til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
- const BinaryConditionalOperator *C, CallingContext *Ctx) {
- return new (Arena) til::Undefined(C);
+SExprBuilder::translateAbstractConditionalOperator(
+ const AbstractConditionalOperator *CO, CallingContext *Ctx) {
+ auto *C = translate(CO->getCond(), Ctx);
+ auto *T = translate(CO->getTrueExpr(), Ctx);
+ auto *E = translate(CO->getFalseExpr(), Ctx);
+ return new (Arena) til::IfThenElse(C, T, E);
}
@@ -430,16 +640,14 @@ SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
// If E is trivial returns E.
til::SExpr *SExprBuilder::addStatement(til::SExpr* E, const Stmt *S,
const ValueDecl *VD) {
- if (!E)
- return nullptr;
- if (til::ThreadSafetyTIL::isTrivial(E))
+ if (!E || !CurrentBB || E->block() || til::ThreadSafetyTIL::isTrivial(E))
return E;
-
- til::Variable *V = new (Arena) til::Variable(E, VD);
- CurrentInstructions.push_back(V);
+ if (VD)
+ E = new (Arena) til::Variable(E, VD);
+ CurrentInstructions.push_back(E);
if (S)
- insertStmt(S, V);
- return V;
+ insertStmt(S, E);
+ return E;
}
@@ -496,11 +704,11 @@ void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
unsigned ArgIndex = CurrentBlockInfo->ProcessedPredecessors;
assert(ArgIndex > 0 && ArgIndex < NPreds);
- til::Variable *V = dyn_cast<til::Variable>(CurrentLVarMap[i].second);
- if (V && V->getBlockID() == CurrentBB->blockID()) {
+ til::SExpr *CurrE = CurrentLVarMap[i].second;
+ if (CurrE->block() == CurrentBB) {
// We already have a Phi node in the current block,
// so just add the new variable to the Phi node.
- til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+ til::Phi *Ph = dyn_cast<til::Phi>(CurrE);
assert(Ph && "Expecting Phi node.");
if (E)
Ph->values()[ArgIndex] = E;
@@ -509,27 +717,26 @@ void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
// Make a new phi node: phi(..., E)
// All phi args up to the current index are set to the current value.
- til::SExpr *CurrE = CurrentLVarMap[i].second;
til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);
Ph->values().setValues(NPreds, nullptr);
for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)
Ph->values()[PIdx] = CurrE;
if (E)
Ph->values()[ArgIndex] = E;
+ Ph->setClangDecl(CurrentLVarMap[i].first);
// If E is from a back-edge, or either E or CurrE are incomplete, then
// mark this node as incomplete; we may need to remove it later.
- if (!E || isIncompleteVar(E) || isIncompleteVar(CurrE)) {
+ if (!E || isIncompletePhi(E) || isIncompletePhi(CurrE)) {
Ph->setStatus(til::Phi::PH_Incomplete);
}
// Add Phi node to current block, and update CurrentLVarMap[i]
- auto *Var = new (Arena) til::Variable(Ph, CurrentLVarMap[i].first);
- CurrentArguments.push_back(Var);
+ CurrentArguments.push_back(Ph);
if (Ph->status() == til::Phi::PH_Incomplete)
- IncompleteArgs.push_back(Var);
+ IncompleteArgs.push_back(Ph);
CurrentLVarMap.makeWritable();
- CurrentLVarMap.elem(i).second = Var;
+ CurrentLVarMap.elem(i).second = Ph;
}
@@ -603,15 +810,13 @@ void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {
unsigned ArgIndex = BBInfo[Blk->getBlockID()].ProcessedPredecessors;
assert(ArgIndex > 0 && ArgIndex < BB->numPredecessors());
- for (til::Variable *V : BB->arguments()) {
- til::Phi *Ph = dyn_cast_or_null<til::Phi>(V->definition());
+ for (til::SExpr *PE : BB->arguments()) {
+ til::Phi *Ph = dyn_cast_or_null<til::Phi>(PE);
assert(Ph && "Expecting Phi Node.");
assert(Ph->values()[ArgIndex] == nullptr && "Wrong index for back edge.");
- assert(V->clangDecl() && "No local variable for Phi node.");
- til::SExpr *E = lookupVarDecl(V->clangDecl());
+ til::SExpr *E = lookupVarDecl(Ph->clangDecl());
assert(E && "Couldn't find local variable for Phi node.");
-
Ph->values()[ArgIndex] = E;
}
}
@@ -631,7 +836,6 @@ void SExprBuilder::enterCFG(CFG *Cfg, const NamedDecl *D,
BB->reserveInstructions(B->size());
BlockMap[B->getBlockID()] = BB;
}
- CallCtx.reset(new SExprBuilder::CallingContext(D));
CurrentBB = lookupBlock(&Cfg->getEntry());
auto Parms = isa<ObjCMethodDecl>(D) ? cast<ObjCMethodDecl>(D)->parameters()
@@ -691,13 +895,13 @@ void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {
// Push those arguments onto the basic block.
CurrentBB->arguments().reserve(
static_cast<unsigned>(CurrentArguments.size()), Arena);
- for (auto *V : CurrentArguments)
- CurrentBB->addArgument(V);
+ for (auto *A : CurrentArguments)
+ CurrentBB->addArgument(A);
}
void SExprBuilder::handleStatement(const Stmt *S) {
- til::SExpr *E = translate(S, CallCtx.get());
+ til::SExpr *E = translate(S, nullptr);
addStatement(E, S);
}
@@ -726,17 +930,16 @@ void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
til::BasicBlock *BB = *It ? lookupBlock(*It) : nullptr;
// TODO: set index
unsigned Idx = BB ? BB->findPredecessorIndex(CurrentBB) : 0;
- til::SExpr *Tm = new (Arena) til::Goto(BB, Idx);
+ auto *Tm = new (Arena) til::Goto(BB, Idx);
CurrentBB->setTerminator(Tm);
}
else if (N == 2) {
- til::SExpr *C = translate(B->getTerminatorCondition(true), CallCtx.get());
+ til::SExpr *C = translate(B->getTerminatorCondition(true), nullptr);
til::BasicBlock *BB1 = *It ? lookupBlock(*It) : nullptr;
++It;
til::BasicBlock *BB2 = *It ? lookupBlock(*It) : nullptr;
- unsigned Idx1 = BB1 ? BB1->findPredecessorIndex(CurrentBB) : 0;
- unsigned Idx2 = BB2 ? BB2->findPredecessorIndex(CurrentBB) : 0;
- til::SExpr *Tm = new (Arena) til::Branch(C, BB1, BB2, Idx1, Idx2);
+ // FIXME: make sure these arent' critical edges.
+ auto *Tm = new (Arena) til::Branch(C, BB1, BB2);
CurrentBB->setTerminator(Tm);
}
}
@@ -763,10 +966,9 @@ void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
void SExprBuilder::exitCFG(const CFGBlock *Last) {
- for (auto *V : IncompleteArgs) {
- til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
- if (Ph && Ph->status() == til::Phi::PH_Incomplete)
- simplifyIncompleteArg(V, Ph);
+ for (auto *Ph : IncompleteArgs) {
+ if (Ph->status() == til::Phi::PH_Incomplete)
+ simplifyIncompleteArg(Ph);
}
CurrentArguments.clear();
@@ -775,18 +977,15 @@ void SExprBuilder::exitCFG(const CFGBlock *Last) {
}
-
-class TILPrinter : public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {};
-
-
+/*
void printSCFG(CFGWalker &Walker) {
llvm::BumpPtrAllocator Bpa;
til::MemRegionRef Arena(&Bpa);
- SExprBuilder builder(Arena);
- til::SCFG *Cfg = builder.buildCFG(Walker);
- TILPrinter::print(Cfg, llvm::errs());
+ SExprBuilder SxBuilder(Arena);
+ til::SCFG *Scfg = SxBuilder.buildCFG(Walker);
+ TILPrinter::print(Scfg, llvm::errs());
}
-
+*/
} // end namespace threadSafety