forked from OSchip/llvm-project
Thread Safety Analysis: update to internal SExpr handling.
This patch is the first part of a significant refactoring that seeks to restore sanity to way thread safety analysis deals with capability expressions. The current patch merely provides an outline of the structure of the new system. It's not yet connected to the actual analysis, so there's no change in functionality. llvm-svn: 205728
This commit is contained in:
parent
bf94e6e14d
commit
b2213910de
|
@ -0,0 +1,244 @@
|
|||
//===- ThreadSafetyCommon.h ------------------------------------*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Parts of thread safety analysis that are not specific to thread safety
|
||||
// itself have been factored into classes here, where they can be potentially
|
||||
// used by other analyses. Currently these include:
|
||||
//
|
||||
// * Generalize clang CFG visitors.
|
||||
// * Conversion of the clang CFG to SSA form.
|
||||
// * Translation of clang Exprs to TIL SExprs
|
||||
//
|
||||
// UNDER CONSTRUCTION. USE AT YOUR OWN RISK.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/CFGStmtMap.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace clang {
|
||||
namespace threadSafety {
|
||||
|
||||
|
||||
// Simple Visitor class for traversing a clang CFG.
|
||||
class CFGVisitor {
|
||||
public:
|
||||
// Enter the CFG for Decl D, and perform any initial setup operations.
|
||||
void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
|
||||
|
||||
// Enter a CFGBlock.
|
||||
void enterCFGBlock(const CFGBlock *B) {}
|
||||
|
||||
// Process an ordinary statement.
|
||||
void handleStatement(const Stmt *S) {}
|
||||
|
||||
// Process a destructor call
|
||||
void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
|
||||
|
||||
// Process a successor edge.
|
||||
void handleSuccessor(const CFGBlock *Succ) {}
|
||||
|
||||
// Process a successor back edge to a previously visited block.
|
||||
void handleSuccessorBackEdge(const CFGBlock *Succ) {}
|
||||
|
||||
// Leave a CFGBlock.
|
||||
void exitCFGBlock(const CFGBlock *B) {}
|
||||
|
||||
// Leave the CFG, and perform any final cleanup operations.
|
||||
void exitCFG(const CFGBlock *Last) {}
|
||||
};
|
||||
|
||||
|
||||
// Walks the clang CFG, and invokes methods on a given CFGVisitor.
|
||||
class CFGWalker {
|
||||
public:
|
||||
CFGWalker() : CFGraph(0), FDecl(0), ACtx(0), SortedGraph(0) {}
|
||||
|
||||
~CFGWalker() { }
|
||||
|
||||
// Initialize the CFGWalker. This setup only needs to be done once, even
|
||||
// if there are multiple passes over the CFG.
|
||||
bool init(AnalysisDeclContext &AC) {
|
||||
ACtx = &AC;
|
||||
CFGraph = AC.getCFG();
|
||||
if (!CFGraph)
|
||||
return false;
|
||||
|
||||
FDecl = dyn_cast_or_null<NamedDecl>(AC.getDecl());
|
||||
if (!FDecl) // ignore anonymous functions
|
||||
return false;
|
||||
|
||||
SortedGraph = AC.getAnalysis<PostOrderCFGView>();
|
||||
if (!SortedGraph)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Traverse the CFG, calling methods on V as appropriate.
|
||||
template <class Visitor>
|
||||
void walk(Visitor &V) {
|
||||
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
|
||||
|
||||
V.enterCFG(CFGraph, FDecl, &CFGraph->getEntry());
|
||||
|
||||
for (const CFGBlock* CurrBlock : *SortedGraph) {
|
||||
VisitedBlocks.insert(CurrBlock);
|
||||
|
||||
V.enterCFGBlock(CurrBlock);
|
||||
|
||||
// Process statements
|
||||
for (CFGBlock::const_iterator BI = CurrBlock->begin(),
|
||||
BE = CurrBlock->end();
|
||||
BI != BE; ++BI) {
|
||||
switch (BI->getKind()) {
|
||||
case CFGElement::Statement: {
|
||||
V.handleStatement(BI->castAs<CFGStmt>().getStmt());
|
||||
break;
|
||||
}
|
||||
case CFGElement::AutomaticObjectDtor: {
|
||||
CFGAutomaticObjDtor AD = BI->castAs<CFGAutomaticObjDtor>();
|
||||
CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>(
|
||||
AD.getDestructorDecl(ACtx->getASTContext()));
|
||||
VarDecl *VD = const_cast<VarDecl*>(AD.getVarDecl());
|
||||
V.handleDestructorCall(VD, DD);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Process successors
|
||||
for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
|
||||
SE = CurrBlock->succ_end();
|
||||
SI != SE; ++SI) {
|
||||
if (*SI == 0)
|
||||
continue;
|
||||
|
||||
if (VisitedBlocks.alreadySet(*SI)) {
|
||||
V.handleSuccessorBackEdge(*SI);
|
||||
continue;
|
||||
}
|
||||
V.handleSuccessor(*SI);
|
||||
}
|
||||
|
||||
V.exitCFGBlock(CurrBlock);
|
||||
}
|
||||
V.exitCFG(&CFGraph->getExit());
|
||||
}
|
||||
|
||||
public:
|
||||
CFG *CFGraph;
|
||||
const NamedDecl *FDecl;
|
||||
AnalysisDeclContext *ACtx;
|
||||
PostOrderCFGView *SortedGraph;
|
||||
};
|
||||
|
||||
|
||||
// Translate clang::Expr to til::SExpr.
|
||||
class SExprBuilder {
|
||||
public:
|
||||
typedef llvm::DenseMap<const Stmt*, til::Variable*> StatementMap;
|
||||
|
||||
/// \brief Encapsulates the lexical context of a function call. The lexical
|
||||
/// context includes the arguments to the call, including the implicit object
|
||||
/// argument. When an attribute containing a mutex expression is attached to
|
||||
/// a method, the expression may refer to formal parameters of the method.
|
||||
/// Actual arguments must be substituted for formal parameters to derive
|
||||
/// the appropriate mutex expression in the lexical context where the function
|
||||
/// is called. PrevCtx holds the context in which the arguments themselves
|
||||
/// should be evaluated; multiple calling contexts can be chained together
|
||||
/// by the lock_returned attribute.
|
||||
struct CallingContext {
|
||||
const NamedDecl *AttrDecl; // The decl to which the attr is attached.
|
||||
const Expr *SelfArg; // Implicit object argument -- e.g. 'this'
|
||||
unsigned NumArgs; // Number of funArgs
|
||||
const Expr *const *FunArgs; // Function arguments
|
||||
CallingContext *Prev; // The previous context; or 0 if none.
|
||||
bool SelfArrow; // is Self referred to with -> or .?
|
||||
|
||||
CallingContext(const NamedDecl *D = 0, const Expr *S = 0, unsigned N = 0,
|
||||
const Expr *const *A = 0, CallingContext *P = 0)
|
||||
: AttrDecl(D), SelfArg(S), NumArgs(N), FunArgs(A), Prev(P),
|
||||
SelfArrow(false)
|
||||
{}
|
||||
};
|
||||
|
||||
til::SExpr *lookupStmt(const Stmt *S);
|
||||
void insertStmt(const Stmt *S, til::Variable *V);
|
||||
|
||||
// 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.
|
||||
til::SExpr *translate(const Stmt *S, CallingContext *Ctx);
|
||||
|
||||
|
||||
til::SExpr *translateDeclRefExpr(const DeclRefExpr *DRE,
|
||||
CallingContext *Ctx) ;
|
||||
til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx);
|
||||
til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx);
|
||||
til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx);
|
||||
til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME,
|
||||
CallingContext *Ctx);
|
||||
til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE,
|
||||
CallingContext *Ctx);
|
||||
til::SExpr *translateUnaryOperator(const UnaryOperator *UO,
|
||||
CallingContext *Ctx);
|
||||
til::SExpr *translateBinaryOperator(const BinaryOperator *BO,
|
||||
CallingContext *Ctx);
|
||||
til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx);
|
||||
til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
CallingContext *Ctx);
|
||||
til::SExpr *translateConditionalOperator(const ConditionalOperator *C,
|
||||
CallingContext *Ctx);
|
||||
til::SExpr *translateBinaryConditionalOperator(
|
||||
const BinaryConditionalOperator *C, CallingContext *Ctx);
|
||||
|
||||
|
||||
SExprBuilder(til::MemRegionRef A, StatementMap *SM = 0)
|
||||
: Arena(A), SMap(SM), SelfVar(0) {
|
||||
// FIXME: we don't always have a self-variable.
|
||||
SelfVar = new (Arena) til::Variable(til::Variable::VK_SFun);
|
||||
}
|
||||
|
||||
protected:
|
||||
til::MemRegionRef Arena;
|
||||
StatementMap *SMap; // Map from Stmt to TIL Variables
|
||||
til::Variable *SelfVar; // Variable to use for 'this'
|
||||
};
|
||||
|
||||
|
||||
// Dump an SCFG to llvm::errs().
|
||||
void printSCFG(CFGWalker &walker);
|
||||
|
||||
|
||||
} // end namespace threadSafety
|
||||
|
||||
} // end namespace clang
|
|
@ -0,0 +1,44 @@
|
|||
//===- ThreadSafetyTIL.h ---------------------------------------*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the list of core opcodes for the Thread Safety
|
||||
// Typed Intermediate language. Please see ThreadSafetyTIL.h for more
|
||||
// information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
TIL_OPCODE_DEF(Future)
|
||||
TIL_OPCODE_DEF(Undefined)
|
||||
TIL_OPCODE_DEF(Wildcard)
|
||||
|
||||
TIL_OPCODE_DEF(Literal)
|
||||
TIL_OPCODE_DEF(LiteralPtr)
|
||||
TIL_OPCODE_DEF(Variable)
|
||||
TIL_OPCODE_DEF(Function)
|
||||
TIL_OPCODE_DEF(SFunction)
|
||||
TIL_OPCODE_DEF(Code)
|
||||
|
||||
TIL_OPCODE_DEF(Apply)
|
||||
TIL_OPCODE_DEF(SApply)
|
||||
TIL_OPCODE_DEF(Project)
|
||||
|
||||
TIL_OPCODE_DEF(Call)
|
||||
TIL_OPCODE_DEF(Alloc)
|
||||
TIL_OPCODE_DEF(Load)
|
||||
TIL_OPCODE_DEF(Store)
|
||||
|
||||
TIL_OPCODE_DEF(UnaryOp)
|
||||
TIL_OPCODE_DEF(BinaryOp)
|
||||
TIL_OPCODE_DEF(Cast)
|
||||
|
||||
TIL_OPCODE_DEF(SCFG)
|
||||
TIL_OPCODE_DEF(Phi)
|
||||
TIL_OPCODE_DEF(Goto)
|
||||
TIL_OPCODE_DEF(Branch)
|
File diff suppressed because it is too large
Load Diff
|
@ -22,6 +22,7 @@ add_clang_library(clangAnalysis
|
|||
PseudoConstantAnalysis.cpp
|
||||
ReachableCode.cpp
|
||||
ScanfFormatString.cpp
|
||||
ThreadSafetyCommon.cpp
|
||||
ThreadSafety.cpp
|
||||
UninitializedValues.cpp
|
||||
|
||||
|
|
|
@ -10,18 +10,20 @@
|
|||
// A intra-procedural analysis for thread safety (e.g. deadlocks and race
|
||||
// conditions), based off of an annotation system.
|
||||
//
|
||||
// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking
|
||||
// See http://clang.llvm.org/docs/ThreadSafetyAnalysis.html
|
||||
// for more information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/Analyses/ThreadSafety.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafety.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/CFGStmtMap.h"
|
||||
|
@ -2362,16 +2364,21 @@ inline bool neverReturns(const CFGBlock* B) {
|
|||
/// at the end of each block, and issue warnings for thread safety violations.
|
||||
/// Each block in the CFG is traversed exactly once.
|
||||
void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
|
||||
CFG *CFGraph = AC.getCFG();
|
||||
if (!CFGraph) return;
|
||||
const NamedDecl *D = dyn_cast_or_null<NamedDecl>(AC.getDecl());
|
||||
// TODO: this whole function needs be rewritten as a visitor for CFGWalker.
|
||||
// For now, we just use the walker to set things up.
|
||||
threadSafety::CFGWalker walker;
|
||||
if (!walker.init(AC))
|
||||
return;
|
||||
|
||||
// AC.dumpCFG(true);
|
||||
// threadSafety::printSCFG(walker);
|
||||
|
||||
CFG *CFGraph = walker.CFGraph;
|
||||
const NamedDecl *D = walker.FDecl;
|
||||
|
||||
if (!D)
|
||||
return; // Ignore anonymous functions for now.
|
||||
if (D->hasAttr<NoThreadSafetyAnalysisAttr>())
|
||||
return;
|
||||
|
||||
// FIXME: Do something a bit more intelligent inside constructor and
|
||||
// destructor code. Constructors and destructors must assume unique access
|
||||
// to 'this', so checks on member variable access is disabled, but we should
|
||||
|
@ -2387,7 +2394,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
|
|||
// We need to explore the CFG via a "topological" ordering.
|
||||
// That way, we will be guaranteed to have information about required
|
||||
// predecessor locksets when exploring a new block.
|
||||
PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
|
||||
PostOrderCFGView *SortedGraph = walker.SortedGraph;
|
||||
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
|
||||
|
||||
// Mark entry block as reachable
|
||||
|
|
|
@ -0,0 +1,407 @@
|
|||
//===- ThreadSafetyCommon.cpp ----------------------------------*- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Implementation of the interfaces declared in ThreadSafetyCommon.h
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/CFGStmtMap.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace clang {
|
||||
namespace threadSafety {
|
||||
|
||||
typedef SExprBuilder::CallingContext CallingContext;
|
||||
|
||||
|
||||
til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
|
||||
if (!SMap)
|
||||
return 0;
|
||||
auto It = SMap->find(S);
|
||||
if (It != SMap->end())
|
||||
return It->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SExprBuilder::insertStmt(const Stmt *S, til::Variable *V) {
|
||||
SMap->insert(std::make_pair(S, V));
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
|
||||
// Check if S has already been translated and cached.
|
||||
// This handles the lookup of SSA names for DeclRefExprs here.
|
||||
if (til::SExpr *E = lookupStmt(S))
|
||||
return E;
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
case Stmt::DeclRefExprClass:
|
||||
return translateDeclRefExpr(cast<DeclRefExpr>(S), Ctx);
|
||||
case Stmt::CXXThisExprClass:
|
||||
return translateCXXThisExpr(cast<CXXThisExpr>(S), Ctx);
|
||||
case Stmt::MemberExprClass:
|
||||
return translateMemberExpr(cast<MemberExpr>(S), Ctx);
|
||||
case Stmt::CallExprClass:
|
||||
return translateCallExpr(cast<CallExpr>(S), Ctx);
|
||||
case Stmt::CXXMemberCallExprClass:
|
||||
return translateCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), Ctx);
|
||||
case Stmt::CXXOperatorCallExprClass:
|
||||
return translateCXXOperatorCallExpr(cast<CXXOperatorCallExpr>(S), Ctx);
|
||||
case Stmt::UnaryOperatorClass:
|
||||
return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);
|
||||
case Stmt::BinaryOperatorClass:
|
||||
return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
|
||||
|
||||
case Stmt::ArraySubscriptExprClass:
|
||||
return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
|
||||
case Stmt::ConditionalOperatorClass:
|
||||
return translateConditionalOperator(cast<ConditionalOperator>(S), Ctx);
|
||||
case Stmt::BinaryConditionalOperatorClass:
|
||||
return translateBinaryConditionalOperator(
|
||||
cast<BinaryConditionalOperator>(S), Ctx);
|
||||
|
||||
// We treat these as no-ops
|
||||
case Stmt::ParenExprClass:
|
||||
return translate(cast<ParenExpr>(S)->getSubExpr(), Ctx);
|
||||
case Stmt::ExprWithCleanupsClass:
|
||||
return translate(cast<ExprWithCleanups>(S)->getSubExpr(), Ctx);
|
||||
case Stmt::CXXBindTemporaryExprClass:
|
||||
return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);
|
||||
|
||||
// Collect all literals
|
||||
case Stmt::CharacterLiteralClass:
|
||||
case Stmt::CXXNullPtrLiteralExprClass:
|
||||
case Stmt::GNUNullExprClass:
|
||||
case Stmt::CXXBoolLiteralExprClass:
|
||||
case Stmt::FloatingLiteralClass:
|
||||
case Stmt::ImaginaryLiteralClass:
|
||||
case Stmt::IntegerLiteralClass:
|
||||
case Stmt::StringLiteralClass:
|
||||
case Stmt::ObjCStringLiteralClass:
|
||||
return new (Arena) til::Literal(cast<Expr>(S));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (const CastExpr *CE = dyn_cast<CastExpr>(S))
|
||||
return translateCastExpr(CE, Ctx);
|
||||
|
||||
return new (Arena) til::Undefined(S);
|
||||
}
|
||||
|
||||
|
||||
til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
|
||||
CallingContext *Ctx) {
|
||||
const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
|
||||
|
||||
// Function parameters require substitution and/or renaming.
|
||||
if (const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(VD)) {
|
||||
const FunctionDecl *FD =
|
||||
cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
|
||||
unsigned I = PV->getFunctionScopeIndex();
|
||||
|
||||
if (Ctx && Ctx->FunArgs && FD == Ctx->AttrDecl->getCanonicalDecl()) {
|
||||
// Substitute call arguments for references to function parameters
|
||||
assert(I < Ctx->NumArgs);
|
||||
return translate(Ctx->FunArgs[I], Ctx->Prev);
|
||||
}
|
||||
// Map the param back to the param of the original function declaration
|
||||
// for consistent comparisons.
|
||||
VD = FD->getParamDecl(I);
|
||||
}
|
||||
|
||||
// For non-local variables, treat it as a referenced to a named object.
|
||||
return new (Arena) til::LiteralPtr(VD);
|
||||
}
|
||||
|
||||
|
||||
til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
|
||||
CallingContext *Ctx) {
|
||||
// Substitute for 'this'
|
||||
if (Ctx && Ctx->SelfArg)
|
||||
return translate(Ctx->SelfArg, Ctx->Prev);
|
||||
assert(SelfVar && "We have no variable for 'this'!");
|
||||
return SelfVar;
|
||||
}
|
||||
|
||||
|
||||
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 *SExprBuilder::translateCallExpr(const CallExpr *CE,
|
||||
CallingContext *Ctx) {
|
||||
// TODO -- Lock returned
|
||||
til::SExpr *E = translate(CE->getCallee(), Ctx);
|
||||
for (unsigned I = 0, N = CE->getNumArgs(); I < N; ++I) {
|
||||
til::SExpr *A = translate(CE->getArg(I), Ctx);
|
||||
E = new (Arena) til::Apply(E, A);
|
||||
}
|
||||
return new (Arena) til::Call(E, CE);
|
||||
}
|
||||
|
||||
|
||||
til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
|
||||
const CXXMemberCallExpr *ME, CallingContext *Ctx) {
|
||||
return translateCallExpr(cast<CallExpr>(ME), Ctx);
|
||||
}
|
||||
|
||||
|
||||
til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
|
||||
const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
|
||||
return translateCallExpr(cast<CallExpr>(OCE), Ctx);
|
||||
}
|
||||
|
||||
|
||||
til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
|
||||
CallingContext *Ctx) {
|
||||
switch (UO->getOpcode()) {
|
||||
case UO_PostInc:
|
||||
case UO_PostDec:
|
||||
case UO_PreInc:
|
||||
case UO_PreDec:
|
||||
return new (Arena) til::Undefined(UO);
|
||||
|
||||
// We treat these as no-ops
|
||||
case UO_AddrOf:
|
||||
case UO_Deref:
|
||||
case UO_Plus:
|
||||
return translate(UO->getSubExpr(), Ctx);
|
||||
|
||||
case UO_Minus:
|
||||
case UO_Not:
|
||||
case UO_LNot:
|
||||
case UO_Real:
|
||||
case UO_Imag:
|
||||
case UO_Extension: {
|
||||
til::SExpr *E0 = translate(UO->getSubExpr(), Ctx);
|
||||
return new (Arena) til::UnaryOp(UO->getOpcode(), E0);
|
||||
}
|
||||
}
|
||||
return new (Arena) til::Undefined(UO);
|
||||
}
|
||||
|
||||
til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
|
||||
CallingContext *Ctx) {
|
||||
switch (BO->getOpcode()) {
|
||||
case BO_PtrMemD:
|
||||
case BO_PtrMemI:
|
||||
return new (Arena) til::Undefined(BO);
|
||||
|
||||
case BO_Mul:
|
||||
case BO_Div:
|
||||
case BO_Rem:
|
||||
case BO_Add:
|
||||
case BO_Sub:
|
||||
case BO_Shl:
|
||||
case BO_Shr:
|
||||
case BO_LT:
|
||||
case BO_GT:
|
||||
case BO_LE:
|
||||
case BO_GE:
|
||||
case BO_EQ:
|
||||
case BO_NE:
|
||||
case BO_And:
|
||||
case BO_Xor:
|
||||
case BO_Or:
|
||||
case BO_LAnd:
|
||||
case BO_LOr: {
|
||||
til::SExpr *E0 = translate(BO->getLHS(), Ctx);
|
||||
til::SExpr *E1 = translate(BO->getRHS(), Ctx);
|
||||
return new (Arena) til::BinaryOp(BO->getOpcode(), E0, E1);
|
||||
}
|
||||
case BO_Assign: {
|
||||
til::SExpr *E0 = translate(BO->getLHS(), Ctx);
|
||||
til::SExpr *E1 = translate(BO->getRHS(), Ctx);
|
||||
return new (Arena) til::Store(E0, E1);
|
||||
}
|
||||
case BO_MulAssign:
|
||||
case BO_DivAssign:
|
||||
case BO_RemAssign:
|
||||
case BO_AddAssign:
|
||||
case BO_SubAssign:
|
||||
case BO_ShlAssign:
|
||||
case BO_ShrAssign:
|
||||
case BO_AndAssign:
|
||||
case BO_XorAssign:
|
||||
case BO_OrAssign:
|
||||
return new (Arena) til::Undefined(BO);
|
||||
|
||||
case BO_Comma:
|
||||
// TODO: handle LHS
|
||||
return translate(BO->getRHS(), Ctx);
|
||||
}
|
||||
|
||||
return new (Arena) til::Undefined(BO);
|
||||
}
|
||||
|
||||
|
||||
til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
|
||||
CallingContext *Ctx) {
|
||||
til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
|
||||
|
||||
clang::CastKind K = CE->getCastKind();
|
||||
switch (K) {
|
||||
case CK_LValueToRValue:
|
||||
return new (Arena) til::Load(E0);
|
||||
|
||||
case CK_NoOp:
|
||||
case CK_DerivedToBase:
|
||||
case CK_UncheckedDerivedToBase:
|
||||
case CK_ArrayToPointerDecay:
|
||||
case CK_FunctionToPointerDecay:
|
||||
return E0;
|
||||
|
||||
default:
|
||||
return new (Arena) til::Cast(K, E0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
til::SExpr *SExprBuilder::translateArraySubscriptExpr(
|
||||
const ArraySubscriptExpr *E, CallingContext *Ctx) {
|
||||
return new (Arena) til::Undefined(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);
|
||||
}
|
||||
|
||||
|
||||
// Build a complete SCFG from a clang CFG.
|
||||
class SCFGBuilder : public CFGVisitor {
|
||||
public:
|
||||
// return true if E should be included in the SCFG
|
||||
bool includeExpr(til::SExpr* E) {
|
||||
if (!E)
|
||||
return false;
|
||||
if (E->opcode() == til::COP_Variable)
|
||||
return false;
|
||||
if (E->opcode() == til::COP_LiteralPtr)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Enter the CFG for Decl D, and perform any initial setup operations.
|
||||
void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {
|
||||
Scfg = new til::SCFG(Arena, Cfg->getNumBlockIDs());
|
||||
CallCtx = new SExprBuilder::CallingContext(D);
|
||||
}
|
||||
|
||||
// Enter a CFGBlock.
|
||||
void enterCFGBlock(const CFGBlock *B) {
|
||||
CurrentBB = new til::BasicBlock(Arena, 0, B->size());
|
||||
CurrentBB->setBlockID(CurrentBlockID);
|
||||
CurrentVarID = 0;
|
||||
Scfg->add(CurrentBB);
|
||||
}
|
||||
|
||||
// Process an ordinary statement.
|
||||
void handleStatement(const Stmt *S) {
|
||||
til::SExpr *E = BuildEx.translate(S, CallCtx);
|
||||
if (includeExpr(E)) {
|
||||
til::Variable *V = new til::Variable(til::Variable::VK_Let, E);
|
||||
V->setID(CurrentBlockID, CurrentVarID++);
|
||||
CurrentBB->addInstr(V);
|
||||
BuildEx.insertStmt(S, V);
|
||||
}
|
||||
}
|
||||
|
||||
// Process a destructor call
|
||||
void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
|
||||
|
||||
// Process a successor edge.
|
||||
void handleSuccessor(const CFGBlock *Succ) {}
|
||||
|
||||
// Process a successor back edge to a previously visited block.
|
||||
void handleSuccessorBackEdge(const CFGBlock *Succ) {}
|
||||
|
||||
// Leave a CFGBlock.
|
||||
void exitCFGBlock(const CFGBlock *B) {
|
||||
CurrentBlockID++;
|
||||
CurrentBB = 0;
|
||||
}
|
||||
|
||||
// Leave the CFG, and perform any final cleanup operations.
|
||||
void exitCFG(const CFGBlock *Last) {}
|
||||
|
||||
SCFGBuilder(til::MemRegionRef A)
|
||||
: Arena(A), Scfg(0), CurrentBB(0), CurrentBlockID(0),
|
||||
BuildEx(A, new SExprBuilder::StatementMap())
|
||||
{ }
|
||||
|
||||
til::SCFG *getCFG() const { return Scfg; }
|
||||
|
||||
private:
|
||||
til::MemRegionRef Arena;
|
||||
til::SCFG *Scfg;
|
||||
til::BasicBlock *CurrentBB;
|
||||
unsigned CurrentBlockID;
|
||||
unsigned CurrentVarID;
|
||||
|
||||
SExprBuilder BuildEx;
|
||||
SExprBuilder::CallingContext *CallCtx;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LLVMPrinter :
|
||||
public til::TILPrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
|
||||
};
|
||||
|
||||
|
||||
void printSCFG(CFGWalker &walker) {
|
||||
llvm::BumpPtrAllocator Bpa;
|
||||
til::MemRegionRef Arena(&Bpa);
|
||||
SCFGBuilder builder(Arena);
|
||||
// CFGVisitor visitor;
|
||||
walker.walk(builder);
|
||||
LLVMPrinter::print(builder.getCFG(), llvm::errs());
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace threadSafety
|
||||
|
||||
} // end namespace clang
|
Loading…
Reference in New Issue