diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp | 335 |
1 files changed, 267 insertions, 68 deletions
diff --git a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp index da88b78..563e059 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafetyCommon.cpp +++ b/contrib/llvm/tools/clang/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 |