void CSDataRando::findArgNodes(Module &M) { // Create function equivalence classes from the global equivalence classes. EquivalenceClasses<const GlobalValue*> &GlobalECs = DSA->getGlobalECs(); EquivalenceClasses<const Function*> FunctionECs; for (auto ei = GlobalECs.begin(), ee = GlobalECs.end(); ei != ee; ei++) { // Ignore non-leader values. if (!ei->isLeader()) { continue; } const Function *Leader = nullptr; for (auto mi = GlobalECs.member_begin(ei), me = GlobalECs.member_end(); mi != me; mi++) { // Only look at functions. if (const Function *F = dyn_cast<Function>(*mi)) { if (Leader) { FunctionECs.unionSets(Leader, F); } else { Leader = FunctionECs.getOrInsertLeaderValue(F); } } } } // Make sure all Functions are part of an equivalence class. This is important // since non-address taken functions may not appear in GlobalECs. for (Function &F : M) { if (!F.isDeclaration()) { FunctionECs.insert(&F); } } // Go through all equivalence classes and determine the additional // arguments. for (auto ei = FunctionECs.begin(), ee = FunctionECs.end();ei != ee; ei++) { if (ei->isLeader()) { NumFunctionECs++; std::vector<const Function*> Functions; Functions.insert(Functions.end(), FunctionECs.member_begin(ei), FunctionECs.member_end()); // If we can't safely replace uses of the function's address with its // clone's address then we can't safely transform indirect calls to this // equivalence class. We still find the arg nodes for each function to // replace direct calls to these functions. if (!DSA->canReplaceAddress(ei->getData())) { NumFunECsWithExternal++; for (const Function *F : Functions) { if (!F->isDeclaration()) { findFunctionArgNodes(F); FunctionInfo[F].CanReplaceAddress = false; } } } else { findFunctionArgNodes(Functions); } } } }
ObservationTable::EquivalenceClasses ObservationTable::_getEquivalenceClasses(bool ofK) { EquivalenceClasses equivalenceClasses; StringSet& localK = ofK ? this->K : this->_KK; // Divide K into equivalence classes according to \equiv F for (string k : localK) { ContextSet distribution = this->_getDistributionByK(k); auto equivalenceClass = equivalenceClasses.find(distribution); if (equivalenceClass != equivalenceClasses.end()) { // Found equivalenceClass->second.insert(k); } else { // Not found StringSet ks; // set of k strings ks.insert(k); equivalenceClasses.insert({ distribution, ks }); } } return equivalenceClasses; }
bool AArch64A57FPLoadBalancing::runOnBasicBlock(MachineBasicBlock &MBB) { bool Changed = false; DEBUG(dbgs() << "Running on MBB: " << MBB << " - scanning instructions...\n"); // First, scan the basic block producing a set of chains. // The currently "active" chains - chains that can be added to and haven't // been killed yet. This is keyed by register - all chains can only have one // "link" register between each inst in the chain. std::map<unsigned, Chain*> ActiveChains; std::set<Chain*> AllChains; unsigned Idx = 0; for (auto &MI : MBB) scanInstruction(&MI, Idx++, ActiveChains, AllChains); DEBUG(dbgs() << "Scan complete, "<< AllChains.size() << " chains created.\n"); // Group the chains into disjoint sets based on their liveness range. This is // a poor-man's version of graph coloring. Ideally we'd create an interference // graph and perform full-on graph coloring on that, but; // (a) That's rather heavyweight for only two colors. // (b) We expect multiple disjoint interference regions - in practice the live // range of chains is quite small and they are clustered between loads // and stores. EquivalenceClasses<Chain*> EC; for (auto *I : AllChains) EC.insert(I); for (auto *I : AllChains) { for (auto *J : AllChains) { if (I != J && I->rangeOverlapsWith(J)) EC.unionSets(I, J); } } DEBUG(dbgs() << "Created " << EC.getNumClasses() << " disjoint sets.\n"); // Now we assume that every member of an equivalence class interferes // with every other member of that class, and with no members of other classes. // Convert the EquivalenceClasses to a simpler set of sets. std::vector<std::vector<Chain*> > V; for (auto I = EC.begin(), E = EC.end(); I != E; ++I) { std::vector<Chain*> Cs(EC.member_begin(I), EC.member_end()); if (Cs.empty()) continue; V.push_back(Cs); } // Now we have a set of sets, order them by start address so // we can iterate over them sequentially. std::sort(V.begin(), V.end(), [](const std::vector<Chain*> &A, const std::vector<Chain*> &B) { return A.front()->startsBefore(B.front()); }); // As we only have two colors, we can track the global (BB-level) balance of // odds versus evens. We aim to keep this near zero to keep both execution // units fed. // Positive means we're even-heavy, negative we're odd-heavy. // // FIXME: If chains have interdependencies, for example: // mul r0, r1, r2 // mul r3, r0, r1 // We do not model this and may color each one differently, assuming we'll // get ILP when we obviously can't. This hasn't been seen to be a problem // in practice so far, so we simplify the algorithm by ignoring it. int Parity = 0; for (auto &I : V) Changed |= colorChainSet(I, MBB, Parity); for (auto *C : AllChains) delete C; return Changed; }