r206676 - Thread Safety Analysis: Update SSA pass to handle loops.
DeLesley Hutchins
delesley at google.com
Fri Apr 18 17:35:54 PDT 2014
Author: delesley
Date: Fri Apr 18 19:35:54 2014
New Revision: 206676
URL: http://llvm.org/viewvc/llvm-project?rev=206676&view=rev
Log:
Thread Safety Analysis: Update SSA pass to handle loops.
Modified:
cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h?rev=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyCommon.h Fri Apr 18 19:35:54 2014
@@ -117,8 +117,9 @@ public:
V.enterCFGBlock(CurrBlock);
- // Process predecessors
+ // Process predecessors, handling back edges last
if (V.visitPredecessors()) {
+ SmallVector<CFGBlock*, 4> BackEdges;
// Process successors
for (CFGBlock::const_pred_iterator SI = CurrBlock->pred_begin(),
SE = CurrBlock->pred_end();
@@ -127,11 +128,14 @@ public:
continue;
if (!VisitedBlocks.alreadySet(*SI)) {
- V.handlePredecessorBackEdge(*SI);
+ BackEdges.push_back(*SI);
continue;
}
V.handlePredecessor(*SI);
}
+
+ for (auto *Blk : BackEdges)
+ V.handlePredecessorBackEdge(Blk);
}
V.enterCFGBlockBody(CurrBlock);
@@ -158,8 +162,10 @@ public:
V.exitCFGBlockBody(CurrBlock);
- // Process successors
+ // Process successors, handling back edges first.
if (V.visitSuccessors()) {
+ SmallVector<CFGBlock*, 8> ForwardEdges;
+
// Process successors
for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
SE = CurrBlock->succ_end();
@@ -167,12 +173,15 @@ public:
if (*SI == nullptr)
continue;
- if (VisitedBlocks.alreadySet(*SI)) {
- V.handleSuccessorBackEdge(*SI);
+ if (!VisitedBlocks.alreadySet(*SI)) {
+ ForwardEdges.push_back(*SI);
continue;
}
- V.handleSuccessor(*SI);
+ V.handleSuccessorBackEdge(*SI);
}
+
+ for (auto *Blk : ForwardEdges)
+ V.handleSuccessor(Blk);
}
V.exitCFGBlock(CurrBlock);
@@ -197,8 +206,6 @@ private:
// 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
@@ -226,10 +233,9 @@ public:
SExprBuilder(til::MemRegionRef A)
: Arena(A), SelfVar(nullptr), Scfg(nullptr), CallCtx(nullptr),
- CurrentBB(nullptr), CurrentBlockID(0), CurrentVarID(0),
- CurrentArgIndex(0) {
+ CurrentBB(nullptr), CurrentBlockInfo(nullptr) {
// FIXME: we don't always have a self-variable.
- SelfVar = new (Arena)til::Variable(til::Variable::VK_SFun);
+ SelfVar = new (Arena) til::Variable(til::Variable::VK_SFun);
}
// Translate a clang statement or expression to a TIL expression.
@@ -239,6 +245,11 @@ public:
til::SCFG *buildCFG(CFGWalker &Walker);
til::SExpr *lookupStmt(const Stmt *S);
+
+ til::BasicBlock *lookupBlock(const CFGBlock *B) {
+ return BlockMap[B->getBlockID()];
+ }
+
const til::SCFG *getCFG() const { return Scfg; }
til::SCFG *getCFF() { return Scfg; }
@@ -266,30 +277,41 @@ private:
til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx);
- // Used for looking the index of a name.
- typedef llvm::DenseMap<const ValueDecl *, unsigned> NameIndexMap;
+ // Map from statements in the clang CFG to SExprs in the til::SCFG.
+ typedef llvm::DenseMap<const Stmt*, til::SExpr*> StatementMap;
+
+ // Map from clang local variables to indices in a LVarDefinitionMap.
+ typedef llvm::DenseMap<const ValueDecl *, unsigned> LVarIndexMap;
- // Used for looking up the current SSA variable for a name, by index.
- typedef CopyOnWriteVector<std::pair<const ValueDecl *, til::SExpr *>>
- NameVarMap;
+ // Map from local variable indices to SSA variables (or constants).
+ typedef std::pair<const ValueDecl *, til::SExpr *> NameVarPair;
+ typedef CopyOnWriteVector<NameVarPair> LVarDefinitionMap;
struct BlockInfo {
- NameVarMap ExitMap;
+ LVarDefinitionMap ExitMap;
bool HasBackEdges;
- unsigned SuccessorsToProcess;
- BlockInfo() : HasBackEdges(false), SuccessorsToProcess(0) {}
+ unsigned UnprocessedSuccessors; // Successors yet to be processed
+ unsigned ProcessedPredecessors; // Predecessors already processed
+
+ BlockInfo()
+ : HasBackEdges(false), UnprocessedSuccessors(0),
+ ProcessedPredecessors(0) {}
BlockInfo(BlockInfo &&RHS)
- : ExitMap(std::move(RHS.ExitMap)), HasBackEdges(RHS.HasBackEdges),
- SuccessorsToProcess(RHS.SuccessorsToProcess) {}
+ : ExitMap(std::move(RHS.ExitMap)),
+ HasBackEdges(RHS.HasBackEdges),
+ UnprocessedSuccessors(RHS.UnprocessedSuccessors),
+ ProcessedPredecessors(RHS.ProcessedPredecessors) {}
BlockInfo &operator=(BlockInfo &&RHS) {
if (this != &RHS) {
ExitMap = std::move(RHS.ExitMap);
HasBackEdges = RHS.HasBackEdges;
- SuccessorsToProcess = RHS.SuccessorsToProcess;
+ UnprocessedSuccessors = RHS.UnprocessedSuccessors;
+ ProcessedPredecessors = RHS.ProcessedPredecessors;
}
return *this;
}
+
private:
BlockInfo(const BlockInfo &) LLVM_DELETED_FUNCTION;
void operator=(const BlockInfo &) LLVM_DELETED_FUNCTION;
@@ -313,31 +335,38 @@ private:
void exitCFGBlock(const CFGBlock *B);
void exitCFG(const CFGBlock *Last);
- void insertStmt(const Stmt *S, til::Variable *V);
+ void insertStmt(const Stmt *S, til::SExpr *E) {
+ SMap.insert(std::make_pair(S, E));
+ }
+ til::SExpr *getCurrentLVarDefinition(const ValueDecl *VD);
+
til::SExpr *addStatement(til::SExpr *E, const Stmt *S, const ValueDecl *VD=0);
til::SExpr *lookupVarDecl(const ValueDecl *VD);
til::SExpr *addVarDecl(const ValueDecl *VD, til::SExpr *E);
til::SExpr *updateVarDecl(const ValueDecl *VD, til::SExpr *E);
- void mergeEntryMap(NameVarMap Map);
+ void makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E);
+ void mergeEntryMap(LVarDefinitionMap Map);
+ void mergeEntryMapBackEdge();
+ void mergePhiNodesBackEdge(const CFGBlock *Blk);
+private:
til::MemRegionRef Arena;
til::Variable *SelfVar; // Variable to use for 'this'. May be null.
til::SCFG *Scfg;
StatementMap SMap; // Map from Stmt to TIL Variables
- NameIndexMap IdxMap; // Indices of clang local vars.
+ LVarIndexMap LVarIdxMap; // Indices of clang local vars.
std::vector<til::BasicBlock *> BlockMap; // Map from clang to til BBs.
std::vector<BlockInfo> BBInfo; // Extra information per BB.
// Indexed by clang BlockID.
SExprBuilder::CallingContext *CallCtx; // Root calling context
- NameVarMap CurrentNameMap;
+ LVarDefinitionMap CurrentLVarMap;
+ std::vector<til::Variable*> CurrentArguments;
+ std::vector<til::Variable*> CurrentInstructions;
til::BasicBlock *CurrentBB;
BlockInfo *CurrentBlockInfo;
- unsigned CurrentBlockID;
- unsigned CurrentVarID;
- unsigned CurrentArgIndex;
};
Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h?rev=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h Fri Apr 18 19:35:54 2014
@@ -952,7 +952,8 @@ public:
static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; }
SCFG(MemRegionRef A, unsigned Nblocks)
- : SExpr(COP_SCFG), Blocks(A, Nblocks), Entry(nullptr), Exit(nullptr) {}
+ : SExpr(COP_SCFG), Blocks(A, Nblocks),
+ Entry(nullptr), Exit(nullptr) {}
SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba
: SExpr(COP_SCFG), Blocks(std::move(Ba)), Entry(nullptr), Exit(nullptr) {
// TODO: set entry and exit!
@@ -972,7 +973,7 @@ public:
const BasicBlock *exit() const { return Exit; }
BasicBlock *exit() { return Exit; }
- void add(BasicBlock *BB) { Blocks.push_back(BB); }
+ void add(BasicBlock *BB);
void setEntry(BasicBlock *BB) { Entry = BB; }
void setExit(BasicBlock *BB) { Exit = BB; }
@@ -1001,12 +1002,12 @@ public:
BasicBlock(MemRegionRef A, unsigned Nargs, unsigned Nins,
SExpr *Term = nullptr)
- : BlockID(0), Parent(nullptr), NumPredecessors(0),
+ : BlockID(0), NumVars(0), NumPredecessors(0), Parent(nullptr),
Args(A, Nargs), Instrs(A, Nins), Terminator(Term) {}
BasicBlock(const BasicBlock &B, VarArray &&As, VarArray &&Is, SExpr *T)
- : BlockID(0), Parent(nullptr), NumPredecessors(B.NumPredecessors),
- Args(std::move(As)), Instrs(std::move(Is)), Terminator(T)
- {}
+ : BlockID(0), NumVars(B.NumVars), NumPredecessors(B.NumPredecessors),
+ Parent(nullptr), Args(std::move(As)), Instrs(std::move(Is)),
+ Terminator(T) {}
unsigned blockID() const { return BlockID; }
unsigned numPredecessors() const { return NumPredecessors; }
@@ -1027,8 +1028,15 @@ public:
void setParent(BasicBlock *P) { Parent = P; }
void setNumPredecessors(unsigned NP) { NumPredecessors = NP; }
void setTerminator(SExpr *E) { Terminator.reset(E); }
- void addArgument(Variable *V) { Args.push_back(V); }
- void addInstr(Variable *V) { Args.push_back(V); }
+
+ void addArgument(Variable *V) {
+ V->setID(BlockID, NumVars++);
+ Args.push_back(V);
+ }
+ void addInstruction(Variable *V) {
+ V->setID(BlockID, NumVars++);
+ Instrs.push_back(V);
+ }
template <class V> BasicBlock *traverse(V &Visitor) {
typename V::template Container<Variable*> Nas(Visitor, Args.size());
@@ -1064,14 +1072,23 @@ private:
friend class SCFG;
unsigned BlockID;
+ unsigned NumVars;
+ unsigned NumPredecessors; // Number of blocks which jump to this one.
+
BasicBlock *Parent; // The parent block is the enclosing lexical scope.
// The parent dominates this block.
- unsigned NumPredecessors; // Number of blocks which jump to this one.
VarArray Args; // Phi nodes. One argument per predecessor.
VarArray Instrs;
SExprRef Terminator;
};
+
+inline void SCFG::add(BasicBlock *BB) {
+ BB->setBlockID(Blocks.size());
+ Blocks.push_back(BB);
+}
+
+
template <class V>
typename V::R_SExpr SCFG::traverse(V &Visitor) {
Visitor.enterCFG(*this);
@@ -1084,6 +1101,7 @@ typename V::R_SExpr SCFG::traverse(V &Vi
return Visitor.reduceSCFG(*this, Bbs);
}
+
class Phi : public SExpr {
public:
// TODO: change to SExprRef
@@ -1098,6 +1116,15 @@ public:
const ValArray &values() const { return Values; }
ValArray &values() { return Values; }
+ // Incomplete phi nodes are constructed during SSA conversion, and
+ // may not be necessary.
+ bool incomplete() const { return Flags == 1; }
+
+ void setIncomplete(bool b) {
+ if (b) Flags = 1;
+ else Flags = 0;
+ }
+
template <class V> typename V::R_SExpr traverse(V &Visitor) {
typename V::template Container<typename V::R_SExpr> Nvs(Visitor,
Values.size());
Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h?rev=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h Fri Apr 18 19:35:54 2014
@@ -510,7 +510,7 @@ protected:
}
void printLiteralPtr(LiteralPtr *E, StreamType &SS) {
- SS << E->clangDecl()->getName();
+ SS << E->clangDecl()->getNameAsString();
}
void printVariable(Variable *E, StreamType &SS) {
Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h?rev=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyUtil.h Fri Apr 18 19:35:54 2014
@@ -80,7 +80,7 @@ public:
SimpleArray(T *Dat, size_t Cp, size_t Sz = 0)
: Data(Dat), Size(Sz), Capacity(Cp) {}
SimpleArray(MemRegionRef A, size_t Cp)
- : Data(A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {}
+ : Data(Cp == 0 ? nullptr : A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {}
SimpleArray(SimpleArray<T> &&A)
: Data(A.Data), Size(A.Size), Capacity(A.Capacity) {
A.Data = nullptr;
@@ -100,11 +100,14 @@ public:
return *this;
}
- T *resize(size_t Ncp, MemRegionRef A) {
+ void reserve(size_t Ncp, MemRegionRef A) {
+ if (Ncp < Capacity)
+ return;
T *Odata = Data;
Data = A.allocateT<T>(Ncp);
+ Capacity = Ncp;
memcpy(Data, Odata, sizeof(T) * Size);
- return Odata;
+ return;
}
typedef T *iterator;
@@ -134,7 +137,7 @@ public:
}
void setValues(unsigned Sz, const T& C) {
- assert(Sz < Capacity);
+ assert(Sz <= Capacity);
Size = Sz;
for (unsigned i = 0; i < Sz; ++i) {
Data[i] = C;
Modified: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=206676&r1=206675&r2=206676&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Fri Apr 18 19:35:54 2014
@@ -46,10 +46,6 @@ til::SExpr *SExprBuilder::lookupStmt(con
return nullptr;
}
-void SExprBuilder::insertStmt(const Stmt *S, til::Variable *V) {
- SMap.insert(std::make_pair(S, V));
-}
-
til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
Walker.walk(*this);
@@ -354,6 +350,7 @@ SExprBuilder::translateDeclStmt(const De
}
+
// 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.
@@ -366,8 +363,7 @@ til::SExpr *SExprBuilder::addStatement(t
return E;
til::Variable *V = new (Arena) til::Variable(E, VD);
- V->setID(CurrentBlockID, CurrentVarID++);
- CurrentBB->addInstr(V);
+ CurrentInstructions.push_back(V);
if (S)
insertStmt(S, V);
return V;
@@ -376,9 +372,11 @@ til::SExpr *SExprBuilder::addStatement(t
// 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;
+ auto It = LVarIdxMap.find(VD);
+ if (It != LVarIdxMap.end()) {
+ assert(CurrentLVarMap[It->second].first == VD);
+ return CurrentLVarMap[It->second].second;
+ }
return nullptr;
}
@@ -396,9 +394,9 @@ inline void maybeUpdateVD(til::SExpr *E,
// 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));
+ LVarIdxMap.insert(std::make_pair(VD, CurrentLVarMap.size()));
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.push_back(std::make_pair(VD, E));
return E;
}
@@ -406,76 +404,151 @@ til::SExpr *SExprBuilder::addVarDecl(con
// 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()) {
+ auto It = LVarIdxMap.find(VD);
+ if (It == LVarIdxMap.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;
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.elem(It->second).second = E;
return E;
}
-// Merge values from Map into the current entry map.
-void SExprBuilder::mergeEntryMap(NameVarMap Map) {
+// Return true if the given expression represents a possibly unnecessary
+// variable: i.e. a variable that references a Phi node that may be removed.
+inline bool isIncompleteVar(til::SExpr *E) {
+ if (!E)
+ return true; // Null values are used on unknown backedges.
+ if (til::Variable *V = dyn_cast<til::Variable>(E)) {
+ if (til::Phi *Ph = dyn_cast<til::Phi>(V->definition()))
+ return Ph->incomplete();
+ }
+ return false;
+}
+
+
+// Make a Phi node in the current block for the i^th variable in CurrentVarMap.
+// If E != null, sets Phi[CurrentBlockInfo->ArgIndex] = E.
+// If E == null, this is a backedge and will be set later.
+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()) {
+ // 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());
+ assert(Ph && "Expecting Phi node.");
+ if (E)
+ Ph->values()[ArgIndex] = E;
+ if (!Ph->incomplete() && isIncompleteVar(E))
+ Ph->setIncomplete(true);
+ return;
+ }
+
+ // Make a new phi node: phi(..., E)
+ // All phi args up to the current index are set to the current value.
+ til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);
+ Ph->values().setValues(NPreds, nullptr);
+ for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)
+ Ph->values()[PIdx] = CurrentLVarMap[i].second;
+ if (E)
+ Ph->values()[ArgIndex] = E;
+ if (isIncompleteVar(E))
+ Ph->setIncomplete(true);
+
+ // Add Phi node to current block, and update CurrentLVarMap[i]
+ auto *Var = new (Arena) til::Variable(Ph, CurrentLVarMap[i].first);
+ CurrentArguments.push_back(Var);
+
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.elem(i).second = Var;
+}
+
+
+// Merge values from Map into the current variable map.
+// This will construct Phi nodes in the current basic block as necessary.
+void SExprBuilder::mergeEntryMap(LVarDefinitionMap Map) {
assert(CurrentBlockInfo && "Not processing a block!");
- if (!CurrentNameMap.valid()) {
+ if (!CurrentLVarMap.valid()) {
// Steal Map, using copy-on-write.
- CurrentNameMap = std::move(Map);
+ CurrentLVarMap = std::move(Map);
return;
}
- if (CurrentNameMap.sameAs(Map))
+ if (CurrentLVarMap.sameAs(Map))
return; // Easy merge: maps from different predecessors are unchanged.
- unsigned ESz = CurrentNameMap.size();
+ unsigned NPreds = CurrentBB->numPredecessors();
+ unsigned ESz = CurrentLVarMap.size();
unsigned MSz = Map.size();
- unsigned Sz = std::max(ESz, MSz);
- bool W = CurrentNameMap.writable();
+ unsigned Sz = std::min(ESz, MSz);
+
for (unsigned i=0; i<Sz; ++i) {
- if (CurrentNameMap[i].first != Map[i].first) {
- if (!W)
- CurrentNameMap.makeWritable();
- CurrentNameMap.downsize(i);
+ if (CurrentLVarMap[i].first != Map[i].first) {
+ // We've reached the end of variables in common.
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.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 (CurrentLVarMap[i].second != Map[i].second)
+ makePhiNodeVar(i, NPreds, Map[i].second);
}
if (ESz > MSz) {
- if (!W)
- CurrentNameMap.makeWritable();
- CurrentNameMap.downsize(Map.size());
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.downsize(Map.size());
+ }
+}
+
+
+// Merge a back edge into the current variable map.
+// This will create phi nodes for all variables in the variable map.
+void SExprBuilder::mergeEntryMapBackEdge() {
+ // We don't have definitions for variables on the backedge, because we
+ // haven't gotten that far in the CFG. Thus, when encountering a back edge,
+ // we conservatively create Phi nodes for all variables. Unnecessary Phi
+ // nodes will be marked as incomplete, and stripped out at the end.
+ //
+ // An Phi node is unnecessary if it only refers to itself and one other
+ // variable, e.g. x = Phi(y, y, x) can be reduced to x = y.
+
+ assert(CurrentBlockInfo && "Not processing a block!");
+
+ if (CurrentBlockInfo->HasBackEdges)
+ return;
+ CurrentBlockInfo->HasBackEdges = true;
+
+ CurrentLVarMap.makeWritable();
+ unsigned Sz = CurrentLVarMap.size();
+ unsigned NPreds = CurrentBB->numPredecessors();
+
+ for (unsigned i=0; i < Sz; ++i) {
+ makePhiNodeVar(i, NPreds, nullptr);
+ }
+}
+
+
+// Update the phi nodes that were initially created for a back edge
+// once the variable definitions have been computed.
+// I.e., merge the current variable map into the phi nodes for Blk.
+void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {
+ til::BasicBlock *BB = lookupBlock(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());
+ 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());
+ assert(E && "Couldn't find local variable for Phi node.");
+
+ Ph->values()[ArgIndex] = E;
}
}
@@ -488,53 +561,60 @@ void SExprBuilder::enterCFG(CFG *Cfg, co
Scfg = new (Arena) til::SCFG(Arena, NBlocks);
// allocate all basic blocks immediately, to handle forward references.
- BlockMap.reserve(NBlocks);
BBInfo.resize(NBlocks);
+ BlockMap.resize(NBlocks, nullptr);
+ // create map from clang blockID to til::BasicBlocks
for (auto *B : *Cfg) {
auto *BB = new (Arena) til::BasicBlock(Arena, 0, B->size());
- BlockMap.push_back(BB);
+ BlockMap[B->getBlockID()] = 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;
+ CurrentArguments.clear();
+ CurrentInstructions.clear();
- assert(!CurrentNameMap.valid() && "CurrentNameMap already initialized.");
+ // CurrentLVarMap is moved to ExitMap on block exit.
+ assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");
}
void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {
- // Compute CurrentNameMap on entry from ExitMaps of predecessors
+ // Compute CurrentLVarMap on entry from ExitMaps of predecessors
BlockInfo *PredInfo = &BBInfo[Pred->getBlockID()];
- assert(PredInfo->SuccessorsToProcess > 0);
+ assert(PredInfo->UnprocessedSuccessors > 0);
- if (--PredInfo->SuccessorsToProcess == 0)
+ if (--PredInfo->UnprocessedSuccessors == 0)
mergeEntryMap(std::move(PredInfo->ExitMap));
else
mergeEntryMap(PredInfo->ExitMap.clone());
- ++CurrentArgIndex;
+ ++CurrentBlockInfo->ProcessedPredecessors;
}
void SExprBuilder::handlePredecessorBackEdge(const CFGBlock *Pred) {
- CurrentBlockInfo->HasBackEdges = true;
+ mergeEntryMapBackEdge();
}
-void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) { }
+void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {
+ // The merge*() methods have created arguments.
+ // Push those arguments onto the basic block.
+ CurrentBB->arguments().reserve(
+ static_cast<unsigned>(CurrentArguments.size()), Arena);
+ for (auto *V : CurrentArguments)
+ CurrentBB->addArgument(V);
+}
void SExprBuilder::handleStatement(const Stmt *S) {
@@ -555,19 +635,25 @@ void SExprBuilder::handleDestructorCall(
void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
+ CurrentBB->instructions().reserve(
+ static_cast<unsigned>(CurrentInstructions.size()), Arena);
+ for (auto *V : CurrentInstructions)
+ CurrentBB->addInstruction(V);
+
+ // Create an appropriate terminator
unsigned N = B->succ_size();
auto It = B->succ_begin();
if (N == 1) {
- til::BasicBlock *BB = *It ? BlockMap[(*It)->getBlockID()] : nullptr;
+ til::BasicBlock *BB = *It ? lookupBlock(*It) : 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;
+ til::BasicBlock *BB1 = *It ? lookupBlock(*It) : nullptr;
++It;
- til::BasicBlock *BB2 = *It ? BlockMap[(*It)->getBlockID()] : nullptr;
+ til::BasicBlock *BB2 = *It ? lookupBlock(*It) : nullptr;
// TODO: set conditional, set index
til::SExpr *Tm = new (Arena) til::Branch(C, BB1, BB2);
CurrentBB->setTerminator(Tm);
@@ -576,28 +662,26 @@ void SExprBuilder::exitCFGBlockBody(cons
void SExprBuilder::handleSuccessor(const CFGBlock *Succ) {
- ++CurrentBlockInfo->SuccessorsToProcess;
+ ++CurrentBlockInfo->UnprocessedSuccessors;
}
void SExprBuilder::handleSuccessorBackEdge(const CFGBlock *Succ) {
-
+ mergePhiNodesBackEdge(Succ);
+ ++BBInfo[Succ->getBlockID()].ProcessedPredecessors;
}
void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
- CurrentBlockInfo->ExitMap = std::move(CurrentNameMap);
- CurrentBlockID++;
+ CurrentBlockInfo->ExitMap = std::move(CurrentLVarMap);
CurrentBB = nullptr;
CurrentBlockInfo = nullptr;
}
void SExprBuilder::exitCFG(const CFGBlock *Last) {
- CurrentBlockID = 0;
- CurrentVarID = 0;
- CurrentArgIndex = 0;
- delete CallCtx;
+ CurrentArguments.clear();
+ CurrentInstructions.clear();
}
More information about the cfe-commits
mailing list