From: DeLesley Hutchins Date: Sat, 19 Apr 2014 00:35:54 +0000 (+0000) Subject: Thread Safety Analysis: Update SSA pass to handle loops. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0d60af37712b2a5f81565b43545c19dea1dab93f;p=clang Thread Safety Analysis: Update SSA pass to handle loops. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206676 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h index 2b693cf0e4..6adef3471f 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -117,8 +117,9 @@ public: V.enterCFGBlock(CurrBlock); - // Process predecessors + // Process predecessors, handling back edges last if (V.visitPredecessors()) { + SmallVector 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 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 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 NameIndexMap; + // Map from statements in the clang CFG to SExprs in the til::SCFG. + typedef llvm::DenseMap StatementMap; + + // Map from clang local variables to indices in a LVarDefinitionMap. + typedef llvm::DenseMap LVarIndexMap; - // Used for looking up the current SSA variable for a name, by index. - typedef CopyOnWriteVector> - NameVarMap; + // Map from local variable indices to SSA variables (or constants). + typedef std::pair NameVarPair; + typedef CopyOnWriteVector 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 BlockMap; // Map from clang to til BBs. std::vector BBInfo; // Extra information per BB. // Indexed by clang BlockID. SExprBuilder::CallingContext *CallCtx; // Root calling context - NameVarMap CurrentNameMap; + LVarDefinitionMap CurrentLVarMap; + std::vector CurrentArguments; + std::vector CurrentInstructions; til::BasicBlock *CurrentBB; BlockInfo *CurrentBlockInfo; - unsigned CurrentBlockID; - unsigned CurrentVarID; - unsigned CurrentArgIndex; }; diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h index 331e885178..94ef9b3951 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -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 BasicBlock *traverse(V &Visitor) { typename V::template Container 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 typename V::R_SExpr SCFG::traverse(V &Visitor) { Visitor.enterCFG(*this); @@ -1084,6 +1101,7 @@ typename V::R_SExpr SCFG::traverse(V &Visitor) { 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 typename V::R_SExpr traverse(V &Visitor) { typename V::template Container Nvs(Visitor, Values.size()); diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h index 603c5f556c..dd10a34531 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h @@ -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) { diff --git a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h index 4ca49dfbd9..3b768c5a69 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h @@ -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(Cp)), Size(0), Capacity(Cp) {} + : Data(Cp == 0 ? nullptr : A.allocateT(Cp)), Size(0), Capacity(Cp) {} SimpleArray(SimpleArray &&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(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; diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp index 02c9e8dc03..6545bb1d0e 100644 --- a/lib/Analysis/ThreadSafetyCommon.cpp +++ b/lib/Analysis/ThreadSafetyCommon.cpp @@ -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) { +// 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(E)) { + if (til::Phi *Ph = dyn_cast(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(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(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(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(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(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(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(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(); }