|  | //===- ThreadSafetyTIL.cpp -------------------------------------*- C++ --*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT in the llvm repository for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" | 
|  | #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" | 
|  | using namespace clang; | 
|  | using namespace threadSafety; | 
|  | using namespace til; | 
|  |  | 
|  | StringRef til::getUnaryOpcodeString(TIL_UnaryOpcode Op) { | 
|  | switch (Op) { | 
|  | case UOP_Minus:    return "-"; | 
|  | case UOP_BitNot:   return "~"; | 
|  | case UOP_LogicNot: return "!"; | 
|  | } | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | StringRef til::getBinaryOpcodeString(TIL_BinaryOpcode Op) { | 
|  | switch (Op) { | 
|  | case BOP_Mul:      return "*"; | 
|  | case BOP_Div:      return "/"; | 
|  | case BOP_Rem:      return "%"; | 
|  | case BOP_Add:      return "+"; | 
|  | case BOP_Sub:      return "-"; | 
|  | case BOP_Shl:      return "<<"; | 
|  | case BOP_Shr:      return ">>"; | 
|  | case BOP_BitAnd:   return "&"; | 
|  | case BOP_BitXor:   return "^"; | 
|  | case BOP_BitOr:    return "|"; | 
|  | case BOP_Eq:       return "=="; | 
|  | case BOP_Neq:      return "!="; | 
|  | case BOP_Lt:       return "<"; | 
|  | case BOP_Leq:      return "<="; | 
|  | case BOP_LogicAnd: return "&&"; | 
|  | case BOP_LogicOr:  return "||"; | 
|  | } | 
|  | return ""; | 
|  | } | 
|  |  | 
|  |  | 
|  | SExpr* Future::force() { | 
|  | Status = FS_evaluating; | 
|  | Result = compute(); | 
|  | Status = FS_done; | 
|  | return Result; | 
|  | } | 
|  |  | 
|  |  | 
|  | unsigned BasicBlock::addPredecessor(BasicBlock *Pred) { | 
|  | unsigned Idx = Predecessors.size(); | 
|  | Predecessors.reserveCheck(1, Arena); | 
|  | Predecessors.push_back(Pred); | 
|  | for (SExpr *E : Args) { | 
|  | if (Phi* Ph = dyn_cast<Phi>(E)) { | 
|  | Ph->values().reserveCheck(1, Arena); | 
|  | Ph->values().push_back(nullptr); | 
|  | } | 
|  | } | 
|  | return Idx; | 
|  | } | 
|  |  | 
|  |  | 
|  | void BasicBlock::reservePredecessors(unsigned NumPreds) { | 
|  | Predecessors.reserve(NumPreds, Arena); | 
|  | for (SExpr *E : Args) { | 
|  | if (Phi* Ph = dyn_cast<Phi>(E)) { | 
|  | Ph->values().reserve(NumPreds, Arena); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | // If E is a variable, then trace back through any aliases or redundant | 
|  | // Phi nodes to find the canonical definition. | 
|  | const SExpr *til::getCanonicalVal(const SExpr *E) { | 
|  | while (true) { | 
|  | if (auto *V = dyn_cast<Variable>(E)) { | 
|  | if (V->kind() == Variable::VK_Let) { | 
|  | E = V->definition(); | 
|  | continue; | 
|  | } | 
|  | } | 
|  | if (const Phi *Ph = dyn_cast<Phi>(E)) { | 
|  | if (Ph->status() == Phi::PH_SingleVal) { | 
|  | E = Ph->values()[0]; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | return E; | 
|  | } | 
|  |  | 
|  |  | 
|  | // If E is a variable, then trace back through any aliases or redundant | 
|  | // Phi nodes to find the canonical definition. | 
|  | // The non-const version will simplify incomplete Phi nodes. | 
|  | SExpr *til::simplifyToCanonicalVal(SExpr *E) { | 
|  | while (true) { | 
|  | if (auto *V = dyn_cast<Variable>(E)) { | 
|  | if (V->kind() != Variable::VK_Let) | 
|  | return V; | 
|  | // Eliminate redundant variables, e.g. x = y, or x = 5, | 
|  | // but keep anything more complicated. | 
|  | if (til::ThreadSafetyTIL::isTrivial(V->definition())) { | 
|  | E = V->definition(); | 
|  | continue; | 
|  | } | 
|  | return V; | 
|  | } | 
|  | if (auto *Ph = dyn_cast<Phi>(E)) { | 
|  | if (Ph->status() == Phi::PH_Incomplete) | 
|  | simplifyIncompleteArg(Ph); | 
|  | // Eliminate redundant Phi nodes. | 
|  | if (Ph->status() == Phi::PH_SingleVal) { | 
|  | E = Ph->values()[0]; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | return E; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | // Trace the arguments of an incomplete Phi node to see if they have the same | 
|  | // canonical definition.  If so, mark the Phi node as redundant. | 
|  | // getCanonicalVal() will recursively call simplifyIncompletePhi(). | 
|  | void til::simplifyIncompleteArg(til::Phi *Ph) { | 
|  | assert(Ph && Ph->status() == Phi::PH_Incomplete); | 
|  |  | 
|  | // eliminate infinite recursion -- assume that this node is not redundant. | 
|  | Ph->setStatus(Phi::PH_MultiVal); | 
|  |  | 
|  | SExpr *E0 = simplifyToCanonicalVal(Ph->values()[0]); | 
|  | for (unsigned i=1, n=Ph->values().size(); i<n; ++i) { | 
|  | SExpr *Ei = simplifyToCanonicalVal(Ph->values()[i]); | 
|  | if (Ei == Ph) | 
|  | continue;  // Recursive reference to itself.  Don't count. | 
|  | if (Ei != E0) { | 
|  | return;    // Status is already set to MultiVal. | 
|  | } | 
|  | } | 
|  | Ph->setStatus(Phi::PH_SingleVal); | 
|  | } | 
|  |  | 
|  |  | 
|  | // Renumbers the arguments and instructions to have unique, sequential IDs. | 
|  | int BasicBlock::renumberInstrs(int ID) { | 
|  | for (auto *Arg : Args) | 
|  | Arg->setID(this, ID++); | 
|  | for (auto *Instr : Instrs) | 
|  | Instr->setID(this, ID++); | 
|  | TermInstr->setID(this, ID++); | 
|  | return ID; | 
|  | } | 
|  |  | 
|  | // Sorts the CFGs blocks using a reverse post-order depth-first traversal. | 
|  | // Each block will be written into the Blocks array in order, and its BlockID | 
|  | // will be set to the index in the array.  Sorting should start from the entry | 
|  | // block, and ID should be the total number of blocks. | 
|  | int BasicBlock::topologicalSort(SimpleArray<BasicBlock*>& Blocks, int ID) { | 
|  | if (Visited) return ID; | 
|  | Visited = true; | 
|  | for (auto *Block : successors()) | 
|  | ID = Block->topologicalSort(Blocks, ID); | 
|  | // set ID and update block array in place. | 
|  | // We may lose pointers to unreachable blocks. | 
|  | assert(ID > 0); | 
|  | BlockID = --ID; | 
|  | Blocks[BlockID] = this; | 
|  | return ID; | 
|  | } | 
|  |  | 
|  | // Performs a reverse topological traversal, starting from the exit block and | 
|  | // following back-edges.  The dominator is serialized before any predecessors, | 
|  | // which guarantees that all blocks are serialized after their dominator and | 
|  | // before their post-dominator (because it's a reverse topological traversal). | 
|  | // ID should be initially set to 0. | 
|  | // | 
|  | // This sort assumes that (1) dominators have been computed, (2) there are no | 
|  | // critical edges, and (3) the entry block is reachable from the exit block | 
|  | // and no blocks are accessable via traversal of back-edges from the exit that | 
|  | // weren't accessable via forward edges from the entry. | 
|  | int BasicBlock::topologicalFinalSort(SimpleArray<BasicBlock*>& Blocks, int ID) { | 
|  | // Visited is assumed to have been set by the topologicalSort.  This pass | 
|  | // assumes !Visited means that we've visited this node before. | 
|  | if (!Visited) return ID; | 
|  | Visited = false; | 
|  | if (DominatorNode.Parent) | 
|  | ID = DominatorNode.Parent->topologicalFinalSort(Blocks, ID); | 
|  | for (auto *Pred : Predecessors) | 
|  | ID = Pred->topologicalFinalSort(Blocks, ID); | 
|  | assert(static_cast<size_t>(ID) < Blocks.size()); | 
|  | BlockID = ID++; | 
|  | Blocks[BlockID] = this; | 
|  | return ID; | 
|  | } | 
|  |  | 
|  | // Computes the immediate dominator of the current block.  Assumes that all of | 
|  | // its predecessors have already computed their dominators.  This is achieved | 
|  | // by visiting the nodes in topological order. | 
|  | void BasicBlock::computeDominator() { | 
|  | BasicBlock *Candidate = nullptr; | 
|  | // Walk backwards from each predecessor to find the common dominator node. | 
|  | for (auto *Pred : Predecessors) { | 
|  | // Skip back-edges | 
|  | if (Pred->BlockID >= BlockID) continue; | 
|  | // If we don't yet have a candidate for dominator yet, take this one. | 
|  | if (Candidate == nullptr) { | 
|  | Candidate = Pred; | 
|  | continue; | 
|  | } | 
|  | // Walk the alternate and current candidate back to find a common ancestor. | 
|  | auto *Alternate = Pred; | 
|  | while (Alternate != Candidate) { | 
|  | if (Candidate->BlockID > Alternate->BlockID) | 
|  | Candidate = Candidate->DominatorNode.Parent; | 
|  | else | 
|  | Alternate = Alternate->DominatorNode.Parent; | 
|  | } | 
|  | } | 
|  | DominatorNode.Parent = Candidate; | 
|  | DominatorNode.SizeOfSubTree = 1; | 
|  | } | 
|  |  | 
|  | // Computes the immediate post-dominator of the current block.  Assumes that all | 
|  | // of its successors have already computed their post-dominators.  This is | 
|  | // achieved visiting the nodes in reverse topological order. | 
|  | void BasicBlock::computePostDominator() { | 
|  | BasicBlock *Candidate = nullptr; | 
|  | // Walk back from each predecessor to find the common post-dominator node. | 
|  | for (auto *Succ : successors()) { | 
|  | // Skip back-edges | 
|  | if (Succ->BlockID <= BlockID) continue; | 
|  | // If we don't yet have a candidate for post-dominator yet, take this one. | 
|  | if (Candidate == nullptr) { | 
|  | Candidate = Succ; | 
|  | continue; | 
|  | } | 
|  | // Walk the alternate and current candidate back to find a common ancestor. | 
|  | auto *Alternate = Succ; | 
|  | while (Alternate != Candidate) { | 
|  | if (Candidate->BlockID < Alternate->BlockID) | 
|  | Candidate = Candidate->PostDominatorNode.Parent; | 
|  | else | 
|  | Alternate = Alternate->PostDominatorNode.Parent; | 
|  | } | 
|  | } | 
|  | PostDominatorNode.Parent = Candidate; | 
|  | PostDominatorNode.SizeOfSubTree = 1; | 
|  | } | 
|  |  | 
|  |  | 
|  | // Renumber instructions in all blocks | 
|  | void SCFG::renumberInstrs() { | 
|  | int InstrID = 0; | 
|  | for (auto *Block : Blocks) | 
|  | InstrID = Block->renumberInstrs(InstrID); | 
|  | } | 
|  |  | 
|  |  | 
|  | static inline void computeNodeSize(BasicBlock *B, | 
|  | BasicBlock::TopologyNode BasicBlock::*TN) { | 
|  | BasicBlock::TopologyNode *N = &(B->*TN); | 
|  | if (N->Parent) { | 
|  | BasicBlock::TopologyNode *P = &(N->Parent->*TN); | 
|  | // Initially set ID relative to the (as yet uncomputed) parent ID | 
|  | N->NodeID = P->SizeOfSubTree; | 
|  | P->SizeOfSubTree += N->SizeOfSubTree; | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline void computeNodeID(BasicBlock *B, | 
|  | BasicBlock::TopologyNode BasicBlock::*TN) { | 
|  | BasicBlock::TopologyNode *N = &(B->*TN); | 
|  | if (N->Parent) { | 
|  | BasicBlock::TopologyNode *P = &(N->Parent->*TN); | 
|  | N->NodeID += P->NodeID;    // Fix NodeIDs relative to starting node. | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | // Normalizes a CFG.  Normalization has a few major components: | 
|  | // 1) Removing unreachable blocks. | 
|  | // 2) Computing dominators and post-dominators | 
|  | // 3) Topologically sorting the blocks into the "Blocks" array. | 
|  | void SCFG::computeNormalForm() { | 
|  | // Topologically sort the blocks starting from the entry block. | 
|  | int NumUnreachableBlocks = Entry->topologicalSort(Blocks, Blocks.size()); | 
|  | if (NumUnreachableBlocks > 0) { | 
|  | // If there were unreachable blocks shift everything down, and delete them. | 
|  | for (size_t I = NumUnreachableBlocks, E = Blocks.size(); I < E; ++I) { | 
|  | size_t NI = I - NumUnreachableBlocks; | 
|  | Blocks[NI] = Blocks[I]; | 
|  | Blocks[NI]->BlockID = NI; | 
|  | // FIXME: clean up predecessor pointers to unreachable blocks? | 
|  | } | 
|  | Blocks.drop(NumUnreachableBlocks); | 
|  | } | 
|  |  | 
|  | // Compute dominators. | 
|  | for (auto *Block : Blocks) | 
|  | Block->computeDominator(); | 
|  |  | 
|  | // Once dominators have been computed, the final sort may be performed. | 
|  | int NumBlocks = Exit->topologicalFinalSort(Blocks, 0); | 
|  | assert(static_cast<size_t>(NumBlocks) == Blocks.size()); | 
|  | (void) NumBlocks; | 
|  |  | 
|  | // Renumber the instructions now that we have a final sort. | 
|  | renumberInstrs(); | 
|  |  | 
|  | // Compute post-dominators and compute the sizes of each node in the | 
|  | // dominator tree. | 
|  | for (auto *Block : Blocks.reverse()) { | 
|  | Block->computePostDominator(); | 
|  | computeNodeSize(Block, &BasicBlock::DominatorNode); | 
|  | } | 
|  | // Compute the sizes of each node in the post-dominator tree and assign IDs in | 
|  | // the dominator tree. | 
|  | for (auto *Block : Blocks) { | 
|  | computeNodeID(Block, &BasicBlock::DominatorNode); | 
|  | computeNodeSize(Block, &BasicBlock::PostDominatorNode); | 
|  | } | 
|  | // Assign IDs in the post-dominator tree. | 
|  | for (auto *Block : Blocks.reverse()) { | 
|  | computeNodeID(Block, &BasicBlock::PostDominatorNode); | 
|  | } | 
|  | } |