10b57cec5SDimitry Andric //===- ThreadSafetyCommon.h -------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Parts of thread safety analysis that are not specific to thread safety
100b57cec5SDimitry Andric // itself have been factored into classes here, where they can be potentially
110b57cec5SDimitry Andric // used by other analyses.  Currently these include:
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric // * Generalize clang CFG visitors.
140b57cec5SDimitry Andric // * Conversion of the clang CFG to SSA form.
150b57cec5SDimitry Andric // * Translation of clang Exprs to TIL SExprs
160b57cec5SDimitry Andric //
170b57cec5SDimitry Andric // UNDER CONSTRUCTION.  USE AT YOUR OWN RISK.
180b57cec5SDimitry Andric //
190b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
220b57cec5SDimitry Andric #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #include "clang/AST/Decl.h"
250b57cec5SDimitry Andric #include "clang/Analysis/Analyses/PostOrderCFGView.h"
260b57cec5SDimitry Andric #include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
270b57cec5SDimitry Andric #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
280b57cec5SDimitry Andric #include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
290b57cec5SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h"
300b57cec5SDimitry Andric #include "clang/Analysis/CFG.h"
310b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
320b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
3381ad6265SDimitry Andric #include "llvm/ADT/PointerIntPair.h"
34bdd1243dSDimitry Andric #include "llvm/ADT/PointerUnion.h"
350b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
360b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
370b57cec5SDimitry Andric #include <sstream>
380b57cec5SDimitry Andric #include <string>
390b57cec5SDimitry Andric #include <utility>
400b57cec5SDimitry Andric #include <vector>
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric namespace clang {
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric class AbstractConditionalOperator;
450b57cec5SDimitry Andric class ArraySubscriptExpr;
460b57cec5SDimitry Andric class BinaryOperator;
470b57cec5SDimitry Andric class CallExpr;
480b57cec5SDimitry Andric class CastExpr;
490b57cec5SDimitry Andric class CXXDestructorDecl;
500b57cec5SDimitry Andric class CXXMemberCallExpr;
510b57cec5SDimitry Andric class CXXOperatorCallExpr;
520b57cec5SDimitry Andric class CXXThisExpr;
530b57cec5SDimitry Andric class DeclRefExpr;
540b57cec5SDimitry Andric class DeclStmt;
550b57cec5SDimitry Andric class Expr;
560b57cec5SDimitry Andric class MemberExpr;
570b57cec5SDimitry Andric class Stmt;
580b57cec5SDimitry Andric class UnaryOperator;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric namespace threadSafety {
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric // Various helper functions on til::SExpr
630b57cec5SDimitry Andric namespace sx {
640b57cec5SDimitry Andric 
equals(const til::SExpr * E1,const til::SExpr * E2)650b57cec5SDimitry Andric inline bool equals(const til::SExpr *E1, const til::SExpr *E2) {
660b57cec5SDimitry Andric   return til::EqualsComparator::compareExprs(E1, E2);
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
matches(const til::SExpr * E1,const til::SExpr * E2)690b57cec5SDimitry Andric inline bool matches(const til::SExpr *E1, const til::SExpr *E2) {
700b57cec5SDimitry Andric   // We treat a top-level wildcard as the "univsersal" lock.
710b57cec5SDimitry Andric   // It matches everything for the purpose of checking locks, but not
720b57cec5SDimitry Andric   // for unlocking them.
730b57cec5SDimitry Andric   if (isa<til::Wildcard>(E1))
740b57cec5SDimitry Andric     return isa<til::Wildcard>(E2);
750b57cec5SDimitry Andric   if (isa<til::Wildcard>(E2))
760b57cec5SDimitry Andric     return isa<til::Wildcard>(E1);
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   return til::MatchComparator::compareExprs(E1, E2);
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
partiallyMatches(const til::SExpr * E1,const til::SExpr * E2)810b57cec5SDimitry Andric inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) {
820b57cec5SDimitry Andric   const auto *PE1 = dyn_cast_or_null<til::Project>(E1);
830b57cec5SDimitry Andric   if (!PE1)
840b57cec5SDimitry Andric     return false;
850b57cec5SDimitry Andric   const auto *PE2 = dyn_cast_or_null<til::Project>(E2);
860b57cec5SDimitry Andric   if (!PE2)
870b57cec5SDimitry Andric     return false;
880b57cec5SDimitry Andric   return PE1->clangDecl() == PE2->clangDecl();
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
toString(const til::SExpr * E)910b57cec5SDimitry Andric inline std::string toString(const til::SExpr *E) {
920b57cec5SDimitry Andric   std::stringstream ss;
930b57cec5SDimitry Andric   til::StdPrinter::print(E, ss);
940b57cec5SDimitry Andric   return ss.str();
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric }  // namespace sx
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric // This class defines the interface of a clang CFG Visitor.
1000b57cec5SDimitry Andric // CFGWalker will invoke the following methods.
1010b57cec5SDimitry Andric // Note that methods are not virtual; the visitor is templatized.
1020b57cec5SDimitry Andric class CFGVisitor {
1030b57cec5SDimitry Andric   // Enter the CFG for Decl D, and perform any initial setup operations.
enterCFG(CFG * Cfg,const NamedDecl * D,const CFGBlock * First)1040b57cec5SDimitry Andric   void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   // Enter a CFGBlock.
enterCFGBlock(const CFGBlock * B)1070b57cec5SDimitry Andric   void enterCFGBlock(const CFGBlock *B) {}
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   // Returns true if this visitor implements handlePredecessor
visitPredecessors()1100b57cec5SDimitry Andric   bool visitPredecessors() { return true; }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // Process a predecessor edge.
handlePredecessor(const CFGBlock * Pred)1130b57cec5SDimitry Andric   void handlePredecessor(const CFGBlock *Pred) {}
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   // Process a successor back edge to a previously visited block.
handlePredecessorBackEdge(const CFGBlock * Pred)1160b57cec5SDimitry Andric   void handlePredecessorBackEdge(const CFGBlock *Pred) {}
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   // Called just before processing statements.
enterCFGBlockBody(const CFGBlock * B)1190b57cec5SDimitry Andric   void enterCFGBlockBody(const CFGBlock *B) {}
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   // Process an ordinary statement.
handleStatement(const Stmt * S)1220b57cec5SDimitry Andric   void handleStatement(const Stmt *S) {}
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   // Process a destructor call
handleDestructorCall(const VarDecl * VD,const CXXDestructorDecl * DD)1250b57cec5SDimitry Andric   void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   // Called after all statements have been handled.
exitCFGBlockBody(const CFGBlock * B)1280b57cec5SDimitry Andric   void exitCFGBlockBody(const CFGBlock *B) {}
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   // Return true
visitSuccessors()1310b57cec5SDimitry Andric   bool visitSuccessors() { return true; }
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   // Process a successor edge.
handleSuccessor(const CFGBlock * Succ)1340b57cec5SDimitry Andric   void handleSuccessor(const CFGBlock *Succ) {}
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   // Process a successor back edge to a previously visited block.
handleSuccessorBackEdge(const CFGBlock * Succ)1370b57cec5SDimitry Andric   void handleSuccessorBackEdge(const CFGBlock *Succ) {}
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   // Leave a CFGBlock.
exitCFGBlock(const CFGBlock * B)1400b57cec5SDimitry Andric   void exitCFGBlock(const CFGBlock *B) {}
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   // Leave the CFG, and perform any final cleanup operations.
exitCFG(const CFGBlock * Last)1430b57cec5SDimitry Andric   void exitCFG(const CFGBlock *Last) {}
1440b57cec5SDimitry Andric };
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric // Walks the clang CFG, and invokes methods on a given CFGVisitor.
1470b57cec5SDimitry Andric class CFGWalker {
1480b57cec5SDimitry Andric public:
1490b57cec5SDimitry Andric   CFGWalker() = default;
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   // Initialize the CFGWalker.  This setup only needs to be done once, even
1520b57cec5SDimitry Andric   // if there are multiple passes over the CFG.
init(AnalysisDeclContext & AC)1530b57cec5SDimitry Andric   bool init(AnalysisDeclContext &AC) {
1540b57cec5SDimitry Andric     ACtx = &AC;
1550b57cec5SDimitry Andric     CFGraph = AC.getCFG();
1560b57cec5SDimitry Andric     if (!CFGraph)
1570b57cec5SDimitry Andric       return false;
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric     // Ignore anonymous functions.
1600eae32dcSDimitry Andric     if (!isa_and_nonnull<NamedDecl>(AC.getDecl()))
1610b57cec5SDimitry Andric       return false;
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric     SortedGraph = AC.getAnalysis<PostOrderCFGView>();
1640b57cec5SDimitry Andric     if (!SortedGraph)
1650b57cec5SDimitry Andric       return false;
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric     return true;
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   // Traverse the CFG, calling methods on V as appropriate.
1710b57cec5SDimitry Andric   template <class Visitor>
walk(Visitor & V)1720b57cec5SDimitry Andric   void walk(Visitor &V) {
1730b57cec5SDimitry Andric     PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric     V.enterCFG(CFGraph, getDecl(), &CFGraph->getEntry());
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric     for (const auto *CurrBlock : *SortedGraph) {
1780b57cec5SDimitry Andric       VisitedBlocks.insert(CurrBlock);
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric       V.enterCFGBlock(CurrBlock);
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric       // Process predecessors, handling back edges last
1830b57cec5SDimitry Andric       if (V.visitPredecessors()) {
1840b57cec5SDimitry Andric         SmallVector<CFGBlock*, 4> BackEdges;
1850b57cec5SDimitry Andric         // Process successors
1860b57cec5SDimitry Andric         for (CFGBlock::const_pred_iterator SI = CurrBlock->pred_begin(),
1870b57cec5SDimitry Andric                                            SE = CurrBlock->pred_end();
1880b57cec5SDimitry Andric              SI != SE; ++SI) {
1890b57cec5SDimitry Andric           if (*SI == nullptr)
1900b57cec5SDimitry Andric             continue;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric           if (!VisitedBlocks.alreadySet(*SI)) {
1930b57cec5SDimitry Andric             BackEdges.push_back(*SI);
1940b57cec5SDimitry Andric             continue;
1950b57cec5SDimitry Andric           }
1960b57cec5SDimitry Andric           V.handlePredecessor(*SI);
1970b57cec5SDimitry Andric         }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric         for (auto *Blk : BackEdges)
2000b57cec5SDimitry Andric           V.handlePredecessorBackEdge(Blk);
2010b57cec5SDimitry Andric       }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric       V.enterCFGBlockBody(CurrBlock);
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric       // Process statements
2060b57cec5SDimitry Andric       for (const auto &BI : *CurrBlock) {
2070b57cec5SDimitry Andric         switch (BI.getKind()) {
2080b57cec5SDimitry Andric         case CFGElement::Statement:
2090b57cec5SDimitry Andric           V.handleStatement(BI.castAs<CFGStmt>().getStmt());
2100b57cec5SDimitry Andric           break;
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric         case CFGElement::AutomaticObjectDtor: {
2130b57cec5SDimitry Andric           CFGAutomaticObjDtor AD = BI.castAs<CFGAutomaticObjDtor>();
2140b57cec5SDimitry Andric           auto *DD = const_cast<CXXDestructorDecl *>(
2150b57cec5SDimitry Andric               AD.getDestructorDecl(ACtx->getASTContext()));
2160b57cec5SDimitry Andric           auto *VD = const_cast<VarDecl *>(AD.getVarDecl());
2170b57cec5SDimitry Andric           V.handleDestructorCall(VD, DD);
2180b57cec5SDimitry Andric           break;
2190b57cec5SDimitry Andric         }
2200b57cec5SDimitry Andric         default:
2210b57cec5SDimitry Andric           break;
2220b57cec5SDimitry Andric         }
2230b57cec5SDimitry Andric       }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric       V.exitCFGBlockBody(CurrBlock);
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric       // Process successors, handling back edges first.
2280b57cec5SDimitry Andric       if (V.visitSuccessors()) {
2290b57cec5SDimitry Andric         SmallVector<CFGBlock*, 8> ForwardEdges;
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric         // Process successors
2320b57cec5SDimitry Andric         for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
2330b57cec5SDimitry Andric                                            SE = CurrBlock->succ_end();
2340b57cec5SDimitry Andric              SI != SE; ++SI) {
2350b57cec5SDimitry Andric           if (*SI == nullptr)
2360b57cec5SDimitry Andric             continue;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric           if (!VisitedBlocks.alreadySet(*SI)) {
2390b57cec5SDimitry Andric             ForwardEdges.push_back(*SI);
2400b57cec5SDimitry Andric             continue;
2410b57cec5SDimitry Andric           }
2420b57cec5SDimitry Andric           V.handleSuccessorBackEdge(*SI);
2430b57cec5SDimitry Andric         }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric         for (auto *Blk : ForwardEdges)
2460b57cec5SDimitry Andric           V.handleSuccessor(Blk);
2470b57cec5SDimitry Andric       }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric       V.exitCFGBlock(CurrBlock);
2500b57cec5SDimitry Andric     }
2510b57cec5SDimitry Andric     V.exitCFG(&CFGraph->getExit());
2520b57cec5SDimitry Andric   }
2530b57cec5SDimitry Andric 
getGraph()2540b57cec5SDimitry Andric   const CFG *getGraph() const { return CFGraph; }
getGraph()2550b57cec5SDimitry Andric   CFG *getGraph() { return CFGraph; }
2560b57cec5SDimitry Andric 
getDecl()2570b57cec5SDimitry Andric   const NamedDecl *getDecl() const {
2580b57cec5SDimitry Andric     return dyn_cast<NamedDecl>(ACtx->getDecl());
2590b57cec5SDimitry Andric   }
2600b57cec5SDimitry Andric 
getSortedGraph()2610b57cec5SDimitry Andric   const PostOrderCFGView *getSortedGraph() const { return SortedGraph; }
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric private:
2640b57cec5SDimitry Andric   CFG *CFGraph = nullptr;
2650b57cec5SDimitry Andric   AnalysisDeclContext *ACtx = nullptr;
2660b57cec5SDimitry Andric   PostOrderCFGView *SortedGraph = nullptr;
2670b57cec5SDimitry Andric };
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric // TODO: move this back into ThreadSafety.cpp
2700b57cec5SDimitry Andric // This is specific to thread safety.  It is here because
2710b57cec5SDimitry Andric // translateAttrExpr needs it, but that should be moved too.
2720b57cec5SDimitry Andric class CapabilityExpr {
2730b57cec5SDimitry Andric private:
27481ad6265SDimitry Andric   /// The capability expression and whether it's negated.
27581ad6265SDimitry Andric   llvm::PointerIntPair<const til::SExpr *, 1, bool> CapExpr;
2760b57cec5SDimitry Andric 
27781ad6265SDimitry Andric   /// The kind of capability as specified by @ref CapabilityAttr::getName.
27881ad6265SDimitry Andric   StringRef CapKind;
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric public:
CapabilityExpr()28181ad6265SDimitry Andric   CapabilityExpr() : CapExpr(nullptr, false) {}
CapabilityExpr(const til::SExpr * E,StringRef Kind,bool Neg)28281ad6265SDimitry Andric   CapabilityExpr(const til::SExpr *E, StringRef Kind, bool Neg)
28381ad6265SDimitry Andric       : CapExpr(E, Neg), CapKind(Kind) {}
2840b57cec5SDimitry Andric 
28581ad6265SDimitry Andric   // Don't allow implicitly-constructed StringRefs since we'll capture them.
28681ad6265SDimitry Andric   template <typename T> CapabilityExpr(const til::SExpr *, T, bool) = delete;
28781ad6265SDimitry Andric 
sexpr()28881ad6265SDimitry Andric   const til::SExpr *sexpr() const { return CapExpr.getPointer(); }
getKind()28981ad6265SDimitry Andric   StringRef getKind() const { return CapKind; }
negative()29081ad6265SDimitry Andric   bool negative() const { return CapExpr.getInt(); }
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   CapabilityExpr operator!() const {
29381ad6265SDimitry Andric     return CapabilityExpr(CapExpr.getPointer(), CapKind, !CapExpr.getInt());
2940b57cec5SDimitry Andric   }
2950b57cec5SDimitry Andric 
equals(const CapabilityExpr & other)2960b57cec5SDimitry Andric   bool equals(const CapabilityExpr &other) const {
29781ad6265SDimitry Andric     return (negative() == other.negative()) &&
29881ad6265SDimitry Andric            sx::equals(sexpr(), other.sexpr());
2990b57cec5SDimitry Andric   }
3000b57cec5SDimitry Andric 
matches(const CapabilityExpr & other)3010b57cec5SDimitry Andric   bool matches(const CapabilityExpr &other) const {
30281ad6265SDimitry Andric     return (negative() == other.negative()) &&
30381ad6265SDimitry Andric            sx::matches(sexpr(), other.sexpr());
3040b57cec5SDimitry Andric   }
3050b57cec5SDimitry Andric 
matchesUniv(const CapabilityExpr & CapE)3060b57cec5SDimitry Andric   bool matchesUniv(const CapabilityExpr &CapE) const {
3070b57cec5SDimitry Andric     return isUniversal() || matches(CapE);
3080b57cec5SDimitry Andric   }
3090b57cec5SDimitry Andric 
partiallyMatches(const CapabilityExpr & other)3100b57cec5SDimitry Andric   bool partiallyMatches(const CapabilityExpr &other) const {
31181ad6265SDimitry Andric     return (negative() == other.negative()) &&
31281ad6265SDimitry Andric            sx::partiallyMatches(sexpr(), other.sexpr());
3130b57cec5SDimitry Andric   }
3140b57cec5SDimitry Andric 
valueDecl()3150b57cec5SDimitry Andric   const ValueDecl* valueDecl() const {
31681ad6265SDimitry Andric     if (negative() || sexpr() == nullptr)
3170b57cec5SDimitry Andric       return nullptr;
31881ad6265SDimitry Andric     if (const auto *P = dyn_cast<til::Project>(sexpr()))
3190b57cec5SDimitry Andric       return P->clangDecl();
32081ad6265SDimitry Andric     if (const auto *P = dyn_cast<til::LiteralPtr>(sexpr()))
3210b57cec5SDimitry Andric       return P->clangDecl();
3220b57cec5SDimitry Andric     return nullptr;
3230b57cec5SDimitry Andric   }
3240b57cec5SDimitry Andric 
toString()3250b57cec5SDimitry Andric   std::string toString() const {
32681ad6265SDimitry Andric     if (negative())
32781ad6265SDimitry Andric       return "!" + sx::toString(sexpr());
32881ad6265SDimitry Andric     return sx::toString(sexpr());
3290b57cec5SDimitry Andric   }
3300b57cec5SDimitry Andric 
shouldIgnore()33181ad6265SDimitry Andric   bool shouldIgnore() const { return sexpr() == nullptr; }
3320b57cec5SDimitry Andric 
isInvalid()3330b57cec5SDimitry Andric   bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); }
3340b57cec5SDimitry Andric 
isUniversal()3350b57cec5SDimitry Andric   bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); }
3360b57cec5SDimitry Andric };
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric // Translate clang::Expr to til::SExpr.
3390b57cec5SDimitry Andric class SExprBuilder {
3400b57cec5SDimitry Andric public:
3410b57cec5SDimitry Andric   /// Encapsulates the lexical context of a function call.  The lexical
3420b57cec5SDimitry Andric   /// context includes the arguments to the call, including the implicit object
3430b57cec5SDimitry Andric   /// argument.  When an attribute containing a mutex expression is attached to
3440b57cec5SDimitry Andric   /// a method, the expression may refer to formal parameters of the method.
3450b57cec5SDimitry Andric   /// Actual arguments must be substituted for formal parameters to derive
3460b57cec5SDimitry Andric   /// the appropriate mutex expression in the lexical context where the function
3470b57cec5SDimitry Andric   /// is called.  PrevCtx holds the context in which the arguments themselves
3480b57cec5SDimitry Andric   /// should be evaluated; multiple calling contexts can be chained together
3490b57cec5SDimitry Andric   /// by the lock_returned attribute.
3500b57cec5SDimitry Andric   struct CallingContext {
3510b57cec5SDimitry Andric     // The previous context; or 0 if none.
3520b57cec5SDimitry Andric     CallingContext  *Prev;
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric     // The decl to which the attr is attached.
3550b57cec5SDimitry Andric     const NamedDecl *AttrDecl;
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric     // Implicit object argument -- e.g. 'this'
358bdd1243dSDimitry Andric     llvm::PointerUnion<const Expr *, til::SExpr *> SelfArg = nullptr;
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric     // Number of funArgs
3610b57cec5SDimitry Andric     unsigned NumArgs = 0;
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric     // Function arguments
3645f757f3fSDimitry Andric     llvm::PointerUnion<const Expr *const *, til::SExpr *> FunArgs = nullptr;
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric     // is Self referred to with -> or .?
3670b57cec5SDimitry Andric     bool SelfArrow = false;
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric     CallingContext(CallingContext *P, const NamedDecl *D = nullptr)
PrevCallingContext3700b57cec5SDimitry Andric         : Prev(P), AttrDecl(D) {}
3710b57cec5SDimitry Andric   };
3720b57cec5SDimitry Andric 
SExprBuilder(til::MemRegionRef A)3730b57cec5SDimitry Andric   SExprBuilder(til::MemRegionRef A) : Arena(A) {
3740b57cec5SDimitry Andric     // FIXME: we don't always have a self-variable.
3750b57cec5SDimitry Andric     SelfVar = new (Arena) til::Variable(nullptr);
3760b57cec5SDimitry Andric     SelfVar->setKind(til::Variable::VK_SFun);
3770b57cec5SDimitry Andric   }
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric   // Translate a clang expression in an attribute to a til::SExpr.
3800b57cec5SDimitry Andric   // Constructs the context from D, DeclExp, and SelfDecl.
3810b57cec5SDimitry Andric   CapabilityExpr translateAttrExpr(const Expr *AttrExp, const NamedDecl *D,
382bdd1243dSDimitry Andric                                    const Expr *DeclExp,
383bdd1243dSDimitry Andric                                    til::SExpr *Self = nullptr);
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   CapabilityExpr translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx);
3860b57cec5SDimitry Andric 
387bdd1243dSDimitry Andric   // Translate a variable reference.
388bdd1243dSDimitry Andric   til::LiteralPtr *createVariable(const VarDecl *VD);
389bdd1243dSDimitry Andric 
390bdd1243dSDimitry Andric   // Create placeholder for this: we don't know the VarDecl on construction yet.
391bdd1243dSDimitry Andric   std::pair<til::LiteralPtr *, StringRef>
392bdd1243dSDimitry Andric   createThisPlaceholder(const Expr *Exp);
393bdd1243dSDimitry Andric 
3940b57cec5SDimitry Andric   // Translate a clang statement or expression to a TIL expression.
3950b57cec5SDimitry Andric   // Also performs substitution of variables; Ctx provides the context.
3960b57cec5SDimitry Andric   // Dispatches on the type of S.
3970b57cec5SDimitry Andric   til::SExpr *translate(const Stmt *S, CallingContext *Ctx);
3980b57cec5SDimitry Andric   til::SCFG  *buildCFG(CFGWalker &Walker);
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   til::SExpr *lookupStmt(const Stmt *S);
4010b57cec5SDimitry Andric 
lookupBlock(const CFGBlock * B)4020b57cec5SDimitry Andric   til::BasicBlock *lookupBlock(const CFGBlock *B) {
4030b57cec5SDimitry Andric     return BlockMap[B->getBlockID()];
4040b57cec5SDimitry Andric   }
4050b57cec5SDimitry Andric 
getCFG()4060b57cec5SDimitry Andric   const til::SCFG *getCFG() const { return Scfg; }
getCFG()4070b57cec5SDimitry Andric   til::SCFG *getCFG() { return Scfg; }
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric private:
4100b57cec5SDimitry Andric   // We implement the CFGVisitor API
4110b57cec5SDimitry Andric   friend class CFGWalker;
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric   til::SExpr *translateDeclRefExpr(const DeclRefExpr *DRE,
4140b57cec5SDimitry Andric                                    CallingContext *Ctx) ;
4150b57cec5SDimitry Andric   til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx);
4160b57cec5SDimitry Andric   til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx);
4170b57cec5SDimitry Andric   til::SExpr *translateObjCIVarRefExpr(const ObjCIvarRefExpr *IVRE,
4180b57cec5SDimitry Andric                                        CallingContext *Ctx);
4190b57cec5SDimitry Andric   til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx,
4200b57cec5SDimitry Andric                                 const Expr *SelfE = nullptr);
4210b57cec5SDimitry Andric   til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME,
4220b57cec5SDimitry Andric                                          CallingContext *Ctx);
4230b57cec5SDimitry Andric   til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE,
4240b57cec5SDimitry Andric                                            CallingContext *Ctx);
4250b57cec5SDimitry Andric   til::SExpr *translateUnaryOperator(const UnaryOperator *UO,
4260b57cec5SDimitry Andric                                      CallingContext *Ctx);
4270b57cec5SDimitry Andric   til::SExpr *translateBinOp(til::TIL_BinaryOpcode Op,
4280b57cec5SDimitry Andric                              const BinaryOperator *BO,
4290b57cec5SDimitry Andric                              CallingContext *Ctx, bool Reverse = false);
4300b57cec5SDimitry Andric   til::SExpr *translateBinAssign(til::TIL_BinaryOpcode Op,
4310b57cec5SDimitry Andric                                  const BinaryOperator *BO,
4320b57cec5SDimitry Andric                                  CallingContext *Ctx, bool Assign = false);
4330b57cec5SDimitry Andric   til::SExpr *translateBinaryOperator(const BinaryOperator *BO,
4340b57cec5SDimitry Andric                                       CallingContext *Ctx);
4350b57cec5SDimitry Andric   til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx);
4360b57cec5SDimitry Andric   til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E,
4370b57cec5SDimitry Andric                                           CallingContext *Ctx);
4380b57cec5SDimitry Andric   til::SExpr *translateAbstractConditionalOperator(
4390b57cec5SDimitry Andric       const AbstractConditionalOperator *C, CallingContext *Ctx);
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric   til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx);
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric   // Map from statements in the clang CFG to SExprs in the til::SCFG.
4440b57cec5SDimitry Andric   using StatementMap = llvm::DenseMap<const Stmt *, til::SExpr *>;
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric   // Map from clang local variables to indices in a LVarDefinitionMap.
4470b57cec5SDimitry Andric   using LVarIndexMap = llvm::DenseMap<const ValueDecl *, unsigned>;
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric   // Map from local variable indices to SSA variables (or constants).
4500b57cec5SDimitry Andric   using NameVarPair = std::pair<const ValueDecl *, til::SExpr *>;
4510b57cec5SDimitry Andric   using LVarDefinitionMap = CopyOnWriteVector<NameVarPair>;
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric   struct BlockInfo {
4540b57cec5SDimitry Andric     LVarDefinitionMap ExitMap;
4550b57cec5SDimitry Andric     bool HasBackEdges = false;
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric     // Successors yet to be processed
4580b57cec5SDimitry Andric     unsigned UnprocessedSuccessors = 0;
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric     // Predecessors already processed
4610b57cec5SDimitry Andric     unsigned ProcessedPredecessors = 0;
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric     BlockInfo() = default;
4640b57cec5SDimitry Andric     BlockInfo(BlockInfo &&) = default;
4650b57cec5SDimitry Andric     BlockInfo &operator=(BlockInfo &&) = default;
4660b57cec5SDimitry Andric   };
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric   void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First);
4690b57cec5SDimitry Andric   void enterCFGBlock(const CFGBlock *B);
visitPredecessors()4700b57cec5SDimitry Andric   bool visitPredecessors() { return true; }
4710b57cec5SDimitry Andric   void handlePredecessor(const CFGBlock *Pred);
4720b57cec5SDimitry Andric   void handlePredecessorBackEdge(const CFGBlock *Pred);
4730b57cec5SDimitry Andric   void enterCFGBlockBody(const CFGBlock *B);
4740b57cec5SDimitry Andric   void handleStatement(const Stmt *S);
4750b57cec5SDimitry Andric   void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD);
4760b57cec5SDimitry Andric   void exitCFGBlockBody(const CFGBlock *B);
visitSuccessors()4770b57cec5SDimitry Andric   bool visitSuccessors() { return true; }
4780b57cec5SDimitry Andric   void handleSuccessor(const CFGBlock *Succ);
4790b57cec5SDimitry Andric   void handleSuccessorBackEdge(const CFGBlock *Succ);
4800b57cec5SDimitry Andric   void exitCFGBlock(const CFGBlock *B);
4810b57cec5SDimitry Andric   void exitCFG(const CFGBlock *Last);
4820b57cec5SDimitry Andric 
insertStmt(const Stmt * S,til::SExpr * E)4830b57cec5SDimitry Andric   void insertStmt(const Stmt *S, til::SExpr *E) {
4840b57cec5SDimitry Andric     SMap.insert(std::make_pair(S, E));
4850b57cec5SDimitry Andric   }
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric   til::SExpr *addStatement(til::SExpr *E, const Stmt *S,
4880b57cec5SDimitry Andric                            const ValueDecl *VD = nullptr);
4890b57cec5SDimitry Andric   til::SExpr *lookupVarDecl(const ValueDecl *VD);
4900b57cec5SDimitry Andric   til::SExpr *addVarDecl(const ValueDecl *VD, til::SExpr *E);
4910b57cec5SDimitry Andric   til::SExpr *updateVarDecl(const ValueDecl *VD, til::SExpr *E);
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric   void makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E);
4940b57cec5SDimitry Andric   void mergeEntryMap(LVarDefinitionMap Map);
4950b57cec5SDimitry Andric   void mergeEntryMapBackEdge();
4960b57cec5SDimitry Andric   void mergePhiNodesBackEdge(const CFGBlock *Blk);
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric private:
4990b57cec5SDimitry Andric   // Set to true when parsing capability expressions, which get translated
5000b57cec5SDimitry Andric   // inaccurately in order to hack around smart pointers etc.
5010b57cec5SDimitry Andric   static const bool CapabilityExprMode = true;
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric   til::MemRegionRef Arena;
5040b57cec5SDimitry Andric 
5050b57cec5SDimitry Andric   // Variable to use for 'this'.  May be null.
5060b57cec5SDimitry Andric   til::Variable *SelfVar = nullptr;
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric   til::SCFG *Scfg = nullptr;
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric   // Map from Stmt to TIL Variables
5110b57cec5SDimitry Andric   StatementMap SMap;
5120b57cec5SDimitry Andric 
5130b57cec5SDimitry Andric   // Indices of clang local vars.
5140b57cec5SDimitry Andric   LVarIndexMap LVarIdxMap;
5150b57cec5SDimitry Andric 
5160b57cec5SDimitry Andric   // Map from clang to til BBs.
5170b57cec5SDimitry Andric   std::vector<til::BasicBlock *> BlockMap;
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   // Extra information per BB. Indexed by clang BlockID.
5200b57cec5SDimitry Andric   std::vector<BlockInfo> BBInfo;
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric   LVarDefinitionMap CurrentLVarMap;
5230b57cec5SDimitry Andric   std::vector<til::Phi *> CurrentArguments;
5240b57cec5SDimitry Andric   std::vector<til::SExpr *> CurrentInstructions;
5250b57cec5SDimitry Andric   std::vector<til::Phi *> IncompleteArgs;
5260b57cec5SDimitry Andric   til::BasicBlock *CurrentBB = nullptr;
5270b57cec5SDimitry Andric   BlockInfo *CurrentBlockInfo = nullptr;
5280b57cec5SDimitry Andric };
5290b57cec5SDimitry Andric 
5300b57cec5SDimitry Andric // Dump an SCFG to llvm::errs().
5310b57cec5SDimitry Andric void printSCFG(CFGWalker &Walker);
5320b57cec5SDimitry Andric 
5330b57cec5SDimitry Andric } // namespace threadSafety
5340b57cec5SDimitry Andric } // namespace clang
5350b57cec5SDimitry Andric 
53604eeddc0SDimitry Andric #endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
537