Thread Safety Analysis: Update SSA pass to handle loops.
llvm-svn: 206676
This commit is contained in:
@@ -46,10 +46,6 @@ til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
|
||||
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 DeclStmt *S, CallingContext *Ctx) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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(til::SExpr* E, const Stmt *S,
|
||||
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(til::SExpr* E, const Stmt *S,
|
||||
|
||||
// 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, const ValueDecl *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));
|
||||
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(const ValueDecl *VD, til::SExpr *E) {
|
||||
// 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) {
|
||||
assert(CurrentBlockInfo && "Not processing a block!");
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (!CurrentNameMap.valid()) {
|
||||
// Steal Map, using copy-on-write.
|
||||
CurrentNameMap = std::move(Map);
|
||||
|
||||
// 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;
|
||||
}
|
||||
if (CurrentNameMap.sameAs(Map))
|
||||
|
||||
// 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 (!CurrentLVarMap.valid()) {
|
||||
// Steal Map, using copy-on-write.
|
||||
CurrentLVarMap = std::move(Map);
|
||||
return;
|
||||
}
|
||||
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, const NamedDecl *D,
|
||||
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(const VarDecl *VD,
|
||||
|
||||
|
||||
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(const CFGBlock *B) {
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user