// Calculate the largest possible vregsPassed sets. These are the registers that // can pass through an MBB live, but may not be live every time. It is assumed // that all vregsPassed sets are empty before the call. void MachineVerifier::calcRegsPassed() { // First push live-out regs to successors' vregsPassed. Remember the MBBs that // have any vregsPassed. DenseSet<const MachineBasicBlock*> todo; for (MachineFunction::const_iterator MFI = MF->begin(), MFE = MF->end(); MFI != MFE; ++MFI) { const MachineBasicBlock &MBB(*MFI); BBInfo &MInfo = MBBInfoMap[&MBB]; if (!MInfo.reachable) continue; for (MachineBasicBlock::const_succ_iterator SuI = MBB.succ_begin(), SuE = MBB.succ_end(); SuI != SuE; ++SuI) { BBInfo &SInfo = MBBInfoMap[*SuI]; if (SInfo.addPassed(MInfo.regsLiveOut)) todo.insert(*SuI); } } // Iteratively push vregsPassed to successors. This will converge to the same // final state regardless of DenseSet iteration order. while (!todo.empty()) { const MachineBasicBlock *MBB = *todo.begin(); todo.erase(MBB); BBInfo &MInfo = MBBInfoMap[MBB]; for (MachineBasicBlock::const_succ_iterator SuI = MBB->succ_begin(), SuE = MBB->succ_end(); SuI != SuE; ++SuI) { if (*SuI == MBB) continue; BBInfo &SInfo = MBBInfoMap[*SuI]; if (SInfo.addPassed(MInfo.vregsPassed)) todo.insert(*SuI); } } }
// Calculate the set of virtual registers that must be passed through each basic // block in order to satisfy the requirements of successor blocks. This is very // similar to calcRegsPassed, only backwards. void MachineVerifier::calcRegsRequired() { // First push live-in regs to predecessors' vregsRequired. DenseSet<const MachineBasicBlock*> todo; for (MachineFunction::const_iterator MFI = MF->begin(), MFE = MF->end(); MFI != MFE; ++MFI) { const MachineBasicBlock &MBB(*MFI); BBInfo &MInfo = MBBInfoMap[&MBB]; for (MachineBasicBlock::const_pred_iterator PrI = MBB.pred_begin(), PrE = MBB.pred_end(); PrI != PrE; ++PrI) { BBInfo &PInfo = MBBInfoMap[*PrI]; if (PInfo.addRequired(MInfo.vregsLiveIn)) todo.insert(*PrI); } } // Iteratively push vregsRequired to predecessors. This will converge to the // same final state regardless of DenseSet iteration order. while (!todo.empty()) { const MachineBasicBlock *MBB = *todo.begin(); todo.erase(MBB); BBInfo &MInfo = MBBInfoMap[MBB]; for (MachineBasicBlock::const_pred_iterator PrI = MBB->pred_begin(), PrE = MBB->pred_end(); PrI != PrE; ++PrI) { if (*PrI == MBB) continue; BBInfo &SInfo = MBBInfoMap[*PrI]; if (SInfo.addRequired(MInfo.vregsRequired)) todo.insert(*PrI); } } }
static void MarkNodesWhichMustBePassedIn(DenseSet<const DSNode*> &MarkedNodes, Function &F, DSGraph* G, EntryPointAnalysis* EPA) { // All DSNodes reachable from arguments must be passed in... // Unless this is an entry point to the program if (!EPA->isEntryPoint(&F)) { for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) { DSGraph::ScalarMapTy::iterator AI = G->getScalarMap().find(I); if (AI != G->getScalarMap().end()) if (DSNode * N = AI->second.getNode()) N->markReachableNodes(MarkedNodes); } } // Marked the returned node as needing to be passed in. if (DSNode * RetNode = G->getReturnNodeFor(F).getNode()) RetNode->markReachableNodes(MarkedNodes); // Calculate which DSNodes are reachable from globals. If a node is reachable // from a global, we will create a global pool for it, so no argument passage // is required. DenseSet<const DSNode*> NodesFromGlobals; GetNodesReachableFromGlobals(G, NodesFromGlobals); // Remove any nodes reachable from a global. These nodes will be put into // global pools, which do not require arguments to be passed in. for (DenseSet<const DSNode*>::iterator I = NodesFromGlobals.begin(), E = NodesFromGlobals.end(); I != E; ++I) MarkedNodes.erase(*I); }
// Find the number of arguments we need to add to the functions. void CSDataRando::findFunctionArgNodes(const std::vector<const Function *> &Functions) { std::vector<DSNodeHandle> RootNodes; for (const Function *F : Functions) { DSGraph *G = DSA->getDSGraph(*F); G->getFunctionArgumentsForCall(F, RootNodes); } // No additional args to pass. if (RootNodes.size() == 0) { return; } DenseSet<const DSNode*> MarkedNodes; for (DSNodeHandle &NH : RootNodes) { if (DSNode *N = NH.getNode()) { N->markReachableNodes(MarkedNodes); } } // Remove global nodes from the arg nodes. If we are using the bottom-up // analysis then if a node is a global node all contexts will use the global map. for (auto i : GlobalNodes) { MarkedNodes.erase(i); } // Remove any nodes that are marked do not encrypt. SmallVector<const DSNode*, 8> MarkedNodeWorkList; for (auto i : MarkedNodes) { if (i->isDoNotEncryptNode()) { MarkedNodeWorkList.push_back(i); } } for (auto i : MarkedNodeWorkList) { MarkedNodes.erase(i); } if (MarkedNodes.empty()) { return; } // Create a FuncInfo entry for each of the functions with the arg nodes that // need to be passed for (const Function *F : Functions) { FuncInfo &FI = FunctionInfo[F]; FI.ArgNodes.insert(FI.ArgNodes.end(), MarkedNodes.begin(), MarkedNodes.end()); } }
void RTAssociate::SetupGlobalPools(Module* M, DSGraph* GG) { // Get the globals graph for the program. // DSGraph* GG = Graphs->getGlobalsGraph(); // Get all of the nodes reachable from globals. DenseSet<const DSNode*> GlobalHeapNodes; GetNodesReachableFromGlobals(GG, GlobalHeapNodes); errs() << "Pool allocating " << GlobalHeapNodes.size() << " global nodes!\n"; FuncInfo& FI = makeFuncInfo(0, GG); while (GlobalHeapNodes.size()) { const DSNode* D = *GlobalHeapNodes.begin(); GlobalHeapNodes.erase(D); FI.PoolDescriptors[D] = CreateGlobalPool(D, M); } }
// // Function: GetNodesReachableFromGlobals() // // Description: // This function finds all DSNodes which are reachable from globals. It finds // DSNodes both within the local DSGraph as well as in the Globals graph that // are reachable from globals. It does, however, filter out those DSNodes // which are of no interest to automatic pool allocation. // // Inputs: // G - The DSGraph for which to find DSNodes which are reachable by globals. // This DSGraph can either by a DSGraph associated with a function *or* // it can be the globals graph itself. // // Outputs: // NodesFromGlobals - A reference to a container object in which to record // DSNodes reachable from globals. DSNodes are *added* to // this container; it is not cleared by this function. // DSNodes from both the local and globals graph are added. void AllHeapNodesHeuristic::GetNodesReachableFromGlobals (DSGraph* G, DenseSet<const DSNode*> &NodesFromGlobals) { // // Get the globals graph associated with this DSGraph. If the globals graph // is NULL, then the graph that was passed in *is* the globals graph. // DSGraph * GlobalsGraph = G->getGlobalsGraph(); if (!GlobalsGraph) GlobalsGraph = G; // // Find all DSNodes which are reachable in the globals graph. // for (DSGraph::node_iterator NI = GlobalsGraph->node_begin(); NI != GlobalsGraph->node_end(); ++NI) { NI->markReachableNodes(NodesFromGlobals); } // // Remove those global nodes which we know will never be pool allocated. // std::vector<const DSNode *> toRemove; for (DenseSet<const DSNode*>::iterator I = NodesFromGlobals.begin(), E = NodesFromGlobals.end(); I != E; ) { DenseSet<const DSNode*>::iterator Last = I; ++I; const DSNode *tmp = *Last; if (!(tmp->isHeapNode())) toRemove.push_back (tmp); // Do not poolallocate nodes that are cast to Int. // As we do not track through ints, these could be escaping if (tmp->isPtrToIntNode()) toRemove.push_back(tmp); } // // Remove all globally reachable DSNodes which do not require pools. // for (unsigned index = 0; index < toRemove.size(); ++index) { NodesFromGlobals.erase(toRemove[index]); } // // Now the fun part. Find DSNodes in the local graph that correspond to // those nodes reachable in the globals graph. Add them to the set of // reachable nodes, too. // if (G->getGlobalsGraph()) { // // Compute a mapping between local DSNodes and DSNodes in the globals // graph. // DSGraph::NodeMapTy NodeMap; G->computeGToGGMapping (NodeMap); // // Scan through all DSNodes in the local graph. If a local DSNode has a // corresponding DSNode in the globals graph that is reachable from a // global, then add the local DSNode to the set of DSNodes reachable from a // global. // // FIXME: A node's existance within the global DSGraph is probably // sufficient evidence that it is reachable from a global. // DSGraph::node_iterator ni = G->node_begin(); for (; ni != G->node_end(); ++ni) { DSNode * N = ni; if (NodesFromGlobals.count (NodeMap[N].getNode())) NodesFromGlobals.insert (N); } } }
Error AnalysisStyle::dump() { auto Tpi = File.getPDBTpiStream(); if (!Tpi) return Tpi.takeError(); TypeDatabase TypeDB(Tpi->getNumTypeRecords()); TypeDatabaseVisitor DBV(TypeDB); TypeVisitorCallbackPipeline Pipeline; HashLookupVisitor Hasher(*Tpi); // Add them to the database Pipeline.addCallbackToPipeline(DBV); // Store their hash values Pipeline.addCallbackToPipeline(Hasher); if (auto EC = codeview::visitTypeStream(Tpi->typeArray(), Pipeline)) return EC; auto &Adjusters = Tpi->getHashAdjusters(); DenseSet<uint32_t> AdjusterSet; for (const auto &Adj : Adjusters) { assert(AdjusterSet.find(Adj.second) == AdjusterSet.end()); AdjusterSet.insert(Adj.second); } uint32_t Count = 0; outs() << "Searching for hash collisions\n"; for (const auto &H : Hasher.Lookup) { if (H.second.size() <= 1) continue; ++Count; outs() << formatv("Hash: {0}, Count: {1} records\n", H.first, H.second.size()); for (const auto &R : H.second) { auto Iter = AdjusterSet.find(R.TI.getIndex()); StringRef Prefix; if (Iter != AdjusterSet.end()) { Prefix = "[HEAD]"; AdjusterSet.erase(Iter); } StringRef LeafName = getLeafTypeName(R.Record.Type); uint32_t TI = R.TI.getIndex(); StringRef TypeName = TypeDB.getTypeName(R.TI); outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI, TypeName); } } outs() << "\n"; outs() << "Dumping hash adjustment chains\n"; for (const auto &A : Tpi->getHashAdjusters()) { TypeIndex TI(A.second); StringRef TypeName = TypeDB.getTypeName(TI); const CVType &HeadRecord = TypeDB.getTypeRecord(TI); assert(HeadRecord.Hash.hasValue()); auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash); if (CollisionsIter == Hasher.Lookup.end()) continue; const auto &Collisions = CollisionsIter->second; outs() << TypeName << "\n"; outs() << formatv(" [HEAD] {0:x} {1} {2}\n", A.second, getLeafTypeName(HeadRecord.Type), TypeName); for (const auto &Chain : Collisions) { if (Chain.TI == TI) continue; const CVType &TailRecord = TypeDB.getTypeRecord(Chain.TI); outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(), getLeafTypeName(TailRecord.Type), TypeDB.getTypeName(Chain.TI)); } } outs() << formatv("There are {0} orphaned hash adjusters\n", AdjusterSet.size()); for (const auto &Adj : AdjusterSet) { outs() << formatv(" {0}\n", Adj); } uint32_t DistinctHashValues = Hasher.Lookup.size(); outs() << formatv("{0}/{1} hash collisions", Count, DistinctHashValues); return Error::success(); }