Expand Up
@@ -28,6 +28,8 @@
#include " llvm/ADT/SmallVector.h"
#include " llvm/ADT/StringRef.h"
#include < algorithm>
#include < climits>
#include < vector>
Expand All
@@ -38,23 +40,30 @@ typedef SExprBuilder::CallingContext CallingContext;
til::SExpr *SExprBuilder::lookupStmt (const Stmt *S) {
if (!SMap)
return nullptr ;
auto It = SMap->find (S);
if (It != SMap->end ())
auto It = SMap.find (S);
if (It != SMap.end ())
return It->second ;
return nullptr ;
}
void SExprBuilder::insertStmt (const Stmt *S, til::Variable *V) {
SMap->insert (std::make_pair (S, V));
SMap.insert (std::make_pair (S, V));
}
til::SCFG *SExprBuilder::buildCFG (CFGWalker &Walker) {
Walker.walk (*this );
return Scfg;
}
// 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) {
if (!S)
return nullptr ;
// 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))
Expand Down
Expand Up
@@ -105,6 +114,9 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
case Stmt::StringLiteralClass:
case Stmt::ObjCStringLiteralClass:
return new (Arena) til::Literal (cast<Expr>(S));
case Stmt::DeclStmtClass:
return translateDeclStmt (cast<DeclStmt>(S), Ctx);
default :
break ;
}
Expand Down
Expand Up
@@ -209,6 +221,7 @@ til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
return new (Arena) til::Undefined (UO);
}
til::SExpr *SExprBuilder::translateBinaryOperator (const BinaryOperator *BO,
CallingContext *Ctx) {
switch (BO->getOpcode ()) {
Expand Down
Expand Up
@@ -238,10 +251,17 @@ til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
til::BinaryOp (BO->getOpcode (), translate (BO->getLHS (), Ctx),
translate (BO->getRHS (), Ctx));
case BO_Assign:
return new (Arena)
til::Store (translate (BO->getLHS (), Ctx), translate (BO->getRHS (), Ctx));
case BO_Assign: {
const Expr *LHS = BO->getLHS ();
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHS)) {
const Expr *RHS = BO->getRHS ();
til::SExpr *E1 = translate (RHS, Ctx);
return updateVarDecl (DRE->getDecl (), E1 );
}
til::SExpr *E0 = translate (LHS, Ctx);
til::SExpr *E1 = translate (BO->getRHS (), Ctx);
return new (Arena) til::Store (E0 , E1 );
}
case BO_MulAssign:
case BO_DivAssign:
case BO_RemAssign:
Expand All
@@ -265,145 +285,332 @@ til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *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:
case CK_LValueToRValue: {
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr ())) {
til::SExpr *E0 = lookupVarDecl (DRE->getDecl ());
if (E0 )
return E0 ;
}
til::SExpr *E0 = translate (CE->getSubExpr (), Ctx);
return new (Arena) til::Load (E0 );
}
case CK_NoOp:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
case CK_ArrayToPointerDecay:
case CK_FunctionToPointerDecay:
case CK_FunctionToPointerDecay: {
til::SExpr *E0 = translate (CE->getSubExpr (), Ctx);
return E0 ;
default :
}
default : {
til::SExpr *E0 = translate (CE->getSubExpr (), Ctx);
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);
}
til::SExpr *
SExprBuilder::translateDeclStmt (const DeclStmt *S, CallingContext *Ctx) {
DeclGroupRef DGrp = S->getDeclGroup ();
for (DeclGroupRef::iterator I = DGrp.begin (), E = DGrp.end (); I != E; ++I) {
if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
Expr *E = VD->getInit ();
til::SExpr* SE = translate (E, Ctx);
// Add local variables with trivial type to the variable map
QualType T = VD->getType ();
if (T.isTrivialType (VD->getASTContext ())) {
return addVarDecl (VD, SE);
}
else {
// TODO: add alloca
}
}
}
return nullptr ;
}
// Build a complete SCFG from a clang CFG.
class SCFGBuilder {
class BBInfo {
};
// If (E) is non-trivial, then add it to the current basic block, and
// update the statement map so that S refers to E. Returns a new variable
// that refers to E.
// 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))
return E;
void addStatement (til::SExpr* E, const Stmt *S) {
if (!E)
return ;
if (til::ThreadSafetyTIL::isTrivial (E))
return ;
til::Variable *V = new (Arena) til::Variable (E, VD);
V->setID (CurrentBlockID, CurrentVarID++);
CurrentBB->addInstr (V);
if (S)
insertStmt (S, V);
return V;
}
til::Variable *V = new (Arena) til::Variable (til::Variable::VK_Let, E);
V->setID (CurrentBlockID, CurrentVarID++);
CurrentBB->addInstr (V);
if (S)
BuildEx.insertStmt (S, V);
}
public:
// Enter the CFG for Decl D, and perform any initial setup operations.
void enterCFG (CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {
Scfg = new (Arena) til::SCFG (Arena, Cfg->getNumBlockIDs ());
CallCtx = new SExprBuilder::CallingContext (D);
}
// Returns the current value of VD, if known, and nullptr otherwise.
til::SExpr *SExprBuilder::lookupVarDecl (const ValueDecl *VD) {
auto It = IdxMap.find (VD);
if (It != IdxMap.end ())
return CurrentNameMap[It->second ].second ;
return nullptr ;
}
// Enter a CFGBlock.
void enterCFGBlock (const CFGBlock *B) {
CurrentBB = new (Arena) til::BasicBlock (Arena, 0 , B->size ());
CurrentBB->setBlockID (CurrentBlockID);
CurrentVarID = 0 ;
Scfg->add (CurrentBB);
// if E is a til::Variable, update its clangDecl.
inline void maybeUpdateVD (til::SExpr *E, const ValueDecl *VD) {
if (!E)
return ;
if (til::Variable *V = dyn_cast<til::Variable>(E)) {
if (!V->clangDecl ())
V->setClangDecl (VD);
}
}
// Adds a new variable declaration.
til::SExpr *SExprBuilder::addVarDecl (const ValueDecl *VD, til::SExpr *E) {
maybeUpdateVD (E, VD);
IdxMap.insert (std::make_pair (VD, CurrentNameMap.size ()));
CurrentNameMap.makeWritable ();
CurrentNameMap.push_back (std::make_pair (VD, E));
return E;
}
// Process an ordinary statement.
void handleStatement (const Stmt *S) {
til::SExpr *E = BuildEx.translate (S, CallCtx);
addStatement (E, S);
// Updates a current variable declaration. (E.g. by assignment)
til::SExpr *SExprBuilder::updateVarDecl (const ValueDecl *VD, til::SExpr *E) {
maybeUpdateVD (E, VD);
auto It = IdxMap.find (VD);
if (It == IdxMap.end ()) {
til::SExpr *Ptr = new (Arena) til::LiteralPtr (VD);
til::SExpr *St = new (Arena) til::Store (Ptr , E);
return St;
}
CurrentNameMap.makeWritable ();
CurrentNameMap.elem (It->second ).second = E;
return E;
}
// Process a destructor call
void handleDestructorCall (const VarDecl *VD, const CXXDestructorDecl *DD) {
til::SExpr *Sf = new (Arena) til::LiteralPtr (VD);
til::SExpr *Dr = new (Arena) til::LiteralPtr (DD);
til::SExpr *Ap = new (Arena) til::Apply (Dr, Sf);
til::SExpr *E = new (Arena) til::Call (Ap);
addStatement (E, nullptr );
// Merge values from Map into the current entry map.
void SExprBuilder::mergeEntryMap (NameVarMap Map) {
assert (CurrentBlockInfo && " Not processing a block!" );
if (!CurrentNameMap.valid ()) {
// Steal Map, using copy-on-write.
CurrentNameMap = std::move (Map);
return ;
}
if (CurrentNameMap.sameAs (Map))
return ; // Easy merge: maps from different predecessors are unchanged.
unsigned ESz = CurrentNameMap.size ();
unsigned MSz = Map.size ();
unsigned Sz = std::max (ESz, MSz);
bool W = CurrentNameMap.writable ();
for (unsigned i=0 ; i<Sz; ++i) {
if (CurrentNameMap[i].first != Map[i].first ) {
if (!W)
CurrentNameMap.makeWritable ();
CurrentNameMap.downsize (i);
break ;
}
if (CurrentNameMap[i].second != Map[i].second ) {
til::Variable *V =
dyn_cast<til::Variable>(CurrentNameMap[i].second );
if (V && V->getBlockID () == CurrentBB->blockID ()) {
// We already have a Phi node, so add the new variable.
til::Phi *Ph = dyn_cast<til::Phi>(V->definition ());
assert (Ph && " Expecting Phi node." );
Ph->values ()[CurrentArgIndex] = Map[i].second ;
}
else {
if (!W)
CurrentNameMap.makeWritable ();
unsigned NPreds = CurrentBB->numPredecessors ();
assert (CurrentArgIndex > 0 && CurrentArgIndex < NPreds);
// Make a new phi node. All phi args up to the current index must
// be the same, and equal to the current NameMap value.
auto *Ph = new (Arena) til::Phi (Arena, NPreds);
Ph->values ().setValues (NPreds, nullptr );
for (unsigned PIdx = 0 ; PIdx < CurrentArgIndex; ++PIdx)
Ph->values ()[PIdx] = CurrentNameMap[i].second ;
Ph->values ()[CurrentArgIndex] = Map[i].second ;
// Add phi node to current basic block.
auto *Var = new (Arena) til::Variable (Ph, CurrentNameMap[i].first );
Var->setID (CurrentBlockID, CurrentVarID++);
CurrentBB->addArgument (Var);
CurrentNameMap.elem (i).second = Var;
}
}
}
if (ESz > MSz) {
if (!W)
CurrentNameMap.makeWritable ();
CurrentNameMap.downsize (Map.size ());
}
}
// Process a successor edge.
void handleSuccessor (const CFGBlock *Succ) {}
// Process a successor back edge to a previously visited block.
void handleSuccessorBackEdge (const CFGBlock *Succ) {}
void SExprBuilder::enterCFG (CFG *Cfg, const NamedDecl *D,
const CFGBlock *First) {
// Perform initial setup operations.
unsigned NBlocks = Cfg->getNumBlockIDs ();
Scfg = new (Arena) til::SCFG (Arena, NBlocks);
// Leave a CFGBlock.
void exitCFGBlock (const CFGBlock *B) {
CurrentBlockID++;
CurrentBB = 0 ;
// allocate all basic blocks immediately, to handle forward references.
BlockMap.reserve (NBlocks);
BBInfo.resize (NBlocks);
for (auto *B : *Cfg) {
auto *BB = new (Arena) til::BasicBlock (Arena, 0 , B->size ());
BlockMap.push_back (BB);
}
CallCtx = new SExprBuilder::CallingContext (D);
}
void SExprBuilder::enterCFGBlock (const CFGBlock *B) {
// Intialize TIL basic block and add it to the CFG.
CurrentBB = BlockMap[B->getBlockID ()];
CurrentBB->setBlockID (CurrentBlockID);
CurrentBB->setNumPredecessors (B->pred_size ());
Scfg->add (CurrentBB);
CurrentBlockInfo = &BBInfo[B->getBlockID ()];
CurrentVarID = 0 ;
CurrentArgIndex = 0 ;
assert (!CurrentNameMap.valid () && " CurrentNameMap already initialized." );
}
void SExprBuilder::handlePredecessor (const CFGBlock *Pred) {
// Compute CurrentNameMap on entry from ExitMaps of predecessors
BlockInfo *PredInfo = &BBInfo[Pred->getBlockID ()];
assert (PredInfo->SuccessorsToProcess > 0 );
if (--PredInfo->SuccessorsToProcess == 0 )
mergeEntryMap (std::move (PredInfo->ExitMap ));
else
mergeEntryMap (PredInfo->ExitMap .clone ());
++CurrentArgIndex;
}
void SExprBuilder::handlePredecessorBackEdge (const CFGBlock *Pred) {
CurrentBlockInfo->HasBackEdges = true ;
}
// Leave the CFG, and perform any final cleanup operations.
void exitCFG (const CFGBlock *Last) {
delete CallCtx;
CallCtx = nullptr ;
void SExprBuilder::enterCFGBlockBody (const CFGBlock *B) { }
void SExprBuilder::handleStatement (const Stmt *S) {
til::SExpr *E = translate (S, CallCtx);
addStatement (E, S);
}
void SExprBuilder::handleDestructorCall (const VarDecl *VD,
const CXXDestructorDecl *DD) {
til::SExpr *Sf = new (Arena) til::LiteralPtr (VD);
til::SExpr *Dr = new (Arena) til::LiteralPtr (DD);
til::SExpr *Ap = new (Arena) til::Apply (Dr, Sf);
til::SExpr *E = new (Arena) til::Call (Ap);
addStatement (E, nullptr );
}
void SExprBuilder::exitCFGBlockBody (const CFGBlock *B) {
unsigned N = B->succ_size ();
auto It = B->succ_begin ();
if (N == 1 ) {
til::BasicBlock *BB = *It ? BlockMap[(*It)->getBlockID ()] : nullptr ;
// TODO: set index
til::SExpr *Tm = new (Arena) til::Goto (BB, 0 );
CurrentBB->setTerminator (Tm);
}
else if (N == 2 ) {
til::SExpr *C = translate (B->getTerminatorCondition (true ), CallCtx);
til::BasicBlock *BB1 = *It ? BlockMap[(*It)->getBlockID ()] : nullptr ;
++It;
til::BasicBlock *BB2 = *It ? BlockMap[(*It)->getBlockID ()] : nullptr ;
// TODO: set conditional, set index
til::SExpr *Tm = new (Arena) til::Branch (C, BB1, BB2);
CurrentBB->setTerminator (Tm);
}
}
SCFGBuilder (til::MemRegionRef A)
: Arena(A), Scfg(nullptr ), CurrentBB(nullptr ), CurrentBlockID(0 ),
CurrentVarID (0 ), CallCtx(nullptr ),
SMap(new SExprBuilder::StatementMap()), BuildEx(A, SMap) {}
~SCFGBuilder () { delete SMap; }
til::SCFG *getCFG () const { return Scfg; }
void SExprBuilder::handleSuccessor (const CFGBlock *Succ) {
++CurrentBlockInfo->SuccessorsToProcess ;
}
private:
til::MemRegionRef Arena;
til::SCFG *Scfg;
til::BasicBlock *CurrentBB;
unsigned CurrentBlockID;
unsigned CurrentVarID;
SExprBuilder::CallingContext *CallCtx;
SExprBuilder::StatementMap *SMap;
SExprBuilder BuildEx;
};
void SExprBuilder::handleSuccessorBackEdge (const CFGBlock *Succ) {
}
void SExprBuilder::exitCFGBlock (const CFGBlock *B) {
CurrentBlockInfo->ExitMap = std::move (CurrentNameMap);
CurrentBlockID++;
CurrentBB = nullptr ;
CurrentBlockInfo = nullptr ;
}
void SExprBuilder::exitCFG (const CFGBlock *Last) {
CurrentBlockID = 0 ;
CurrentVarID = 0 ;
CurrentArgIndex = 0 ;
}
class LLVMPrinter :
public til::PrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
class LLVMPrinter : public til ::PrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
};
void printSCFG (CFGWalker &walker ) {
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 ());
SExprBuilder builder (Arena);
til::SCFG *Cfg = builder.buildCFG (Walker);
LLVMPrinter::print (Cfg, llvm::errs ());
}
Expand Down