17cc2493dSspupyrev //===- SampleProfileInference.cpp - Adjust sample profiles in the IR ------===//
27cc2493dSspupyrev //
37cc2493dSspupyrev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47cc2493dSspupyrev // See https://llvm.org/LICENSE.txt for license information.
57cc2493dSspupyrev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67cc2493dSspupyrev //
77cc2493dSspupyrev //===----------------------------------------------------------------------===//
87cc2493dSspupyrev //
97cc2493dSspupyrev // This file implements a profile inference algorithm. Given an incomplete and
107cc2493dSspupyrev // possibly imprecise block counts, the algorithm reconstructs realistic block
117cc2493dSspupyrev // and edge counts that satisfy flow conservation rules, while minimally modify
127cc2493dSspupyrev // input block counts.
137cc2493dSspupyrev //
147cc2493dSspupyrev //===----------------------------------------------------------------------===//
157cc2493dSspupyrev 
167cc2493dSspupyrev #include "llvm/Transforms/Utils/SampleProfileInference.h"
175f4ae564SJan Svoboda #include "llvm/ADT/BitVector.h"
187cc2493dSspupyrev #include "llvm/Support/Debug.h"
197cc2493dSspupyrev #include <queue>
207cc2493dSspupyrev #include <set>
217cc2493dSspupyrev 
227cc2493dSspupyrev using namespace llvm;
237cc2493dSspupyrev #define DEBUG_TYPE "sample-profile-inference"
247cc2493dSspupyrev 
257cc2493dSspupyrev namespace {
267cc2493dSspupyrev 
277cc2493dSspupyrev /// A value indicating an infinite flow/capacity/weight of a block/edge.
287cc2493dSspupyrev /// Not using numeric_limits<int64_t>::max(), as the values can be summed up
297cc2493dSspupyrev /// during the execution.
307cc2493dSspupyrev static constexpr int64_t INF = ((int64_t)1) << 50;
317cc2493dSspupyrev 
327cc2493dSspupyrev /// The minimum-cost maximum flow algorithm.
337cc2493dSspupyrev ///
347cc2493dSspupyrev /// The algorithm finds the maximum flow of minimum cost on a given (directed)
357cc2493dSspupyrev /// network using a modified version of the classical Moore-Bellman-Ford
367cc2493dSspupyrev /// approach. The algorithm applies a number of augmentation iterations in which
377cc2493dSspupyrev /// flow is sent along paths of positive capacity from the source to the sink.
387cc2493dSspupyrev /// The worst-case time complexity of the implementation is O(v(f)*m*n), where
397cc2493dSspupyrev /// where m is the number of edges, n is the number of vertices, and v(f) is the
407cc2493dSspupyrev /// value of the maximum flow. However, the observed running time on typical
417cc2493dSspupyrev /// instances is sub-quadratic, that is, o(n^2).
427cc2493dSspupyrev ///
437cc2493dSspupyrev /// The input is a set of edges with specified costs and capacities, and a pair
447cc2493dSspupyrev /// of nodes (source and sink). The output is the flow along each edge of the
457cc2493dSspupyrev /// minimum total cost respecting the given edge capacities.
467cc2493dSspupyrev class MinCostMaxFlow {
477cc2493dSspupyrev public:
487cc2493dSspupyrev   // Initialize algorithm's data structures for a network of a given size.
497cc2493dSspupyrev   void initialize(uint64_t NodeCount, uint64_t SourceNode, uint64_t SinkNode) {
507cc2493dSspupyrev     Source = SourceNode;
517cc2493dSspupyrev     Target = SinkNode;
527cc2493dSspupyrev 
537cc2493dSspupyrev     Nodes = std::vector<Node>(NodeCount);
547cc2493dSspupyrev     Edges = std::vector<std::vector<Edge>>(NodeCount, std::vector<Edge>());
557cc2493dSspupyrev   }
567cc2493dSspupyrev 
577cc2493dSspupyrev   // Run the algorithm.
587cc2493dSspupyrev   int64_t run() {
597cc2493dSspupyrev     // Find an augmenting path and update the flow along the path
607cc2493dSspupyrev     size_t AugmentationIters = 0;
617cc2493dSspupyrev     while (findAugmentingPath()) {
627cc2493dSspupyrev       augmentFlowAlongPath();
637cc2493dSspupyrev       AugmentationIters++;
647cc2493dSspupyrev     }
657cc2493dSspupyrev 
667cc2493dSspupyrev     // Compute the total flow and its cost
677cc2493dSspupyrev     int64_t TotalCost = 0;
687cc2493dSspupyrev     int64_t TotalFlow = 0;
697cc2493dSspupyrev     for (uint64_t Src = 0; Src < Nodes.size(); Src++) {
707cc2493dSspupyrev       for (auto &Edge : Edges[Src]) {
717cc2493dSspupyrev         if (Edge.Flow > 0) {
727cc2493dSspupyrev           TotalCost += Edge.Cost * Edge.Flow;
737cc2493dSspupyrev           if (Src == Source)
747cc2493dSspupyrev             TotalFlow += Edge.Flow;
757cc2493dSspupyrev         }
767cc2493dSspupyrev       }
777cc2493dSspupyrev     }
787cc2493dSspupyrev     LLVM_DEBUG(dbgs() << "Completed profi after " << AugmentationIters
797cc2493dSspupyrev                       << " iterations with " << TotalFlow << " total flow"
807cc2493dSspupyrev                       << " of " << TotalCost << " cost\n");
8122d82949SKazu Hirata     (void)TotalFlow;
827cc2493dSspupyrev     return TotalCost;
837cc2493dSspupyrev   }
847cc2493dSspupyrev 
857cc2493dSspupyrev   /// Adding an edge to the network with a specified capacity and a cost.
867cc2493dSspupyrev   /// Multiple edges between a pair of nodes are allowed but self-edges
877cc2493dSspupyrev   /// are not supported.
887cc2493dSspupyrev   void addEdge(uint64_t Src, uint64_t Dst, int64_t Capacity, int64_t Cost) {
897cc2493dSspupyrev     assert(Capacity > 0 && "adding an edge of zero capacity");
907cc2493dSspupyrev     assert(Src != Dst && "loop edge are not supported");
917cc2493dSspupyrev 
927cc2493dSspupyrev     Edge SrcEdge;
937cc2493dSspupyrev     SrcEdge.Dst = Dst;
947cc2493dSspupyrev     SrcEdge.Cost = Cost;
957cc2493dSspupyrev     SrcEdge.Capacity = Capacity;
967cc2493dSspupyrev     SrcEdge.Flow = 0;
977cc2493dSspupyrev     SrcEdge.RevEdgeIndex = Edges[Dst].size();
987cc2493dSspupyrev 
997cc2493dSspupyrev     Edge DstEdge;
1007cc2493dSspupyrev     DstEdge.Dst = Src;
1017cc2493dSspupyrev     DstEdge.Cost = -Cost;
1027cc2493dSspupyrev     DstEdge.Capacity = 0;
1037cc2493dSspupyrev     DstEdge.Flow = 0;
1047cc2493dSspupyrev     DstEdge.RevEdgeIndex = Edges[Src].size();
1057cc2493dSspupyrev 
1067cc2493dSspupyrev     Edges[Src].push_back(SrcEdge);
1077cc2493dSspupyrev     Edges[Dst].push_back(DstEdge);
1087cc2493dSspupyrev   }
1097cc2493dSspupyrev 
1107cc2493dSspupyrev   /// Adding an edge to the network of infinite capacity and a given cost.
1117cc2493dSspupyrev   void addEdge(uint64_t Src, uint64_t Dst, int64_t Cost) {
1127cc2493dSspupyrev     addEdge(Src, Dst, INF, Cost);
1137cc2493dSspupyrev   }
1147cc2493dSspupyrev 
1157cc2493dSspupyrev   /// Get the total flow from a given source node.
1167cc2493dSspupyrev   /// Returns a list of pairs (target node, amount of flow to the target).
1177cc2493dSspupyrev   const std::vector<std::pair<uint64_t, int64_t>> getFlow(uint64_t Src) const {
1187cc2493dSspupyrev     std::vector<std::pair<uint64_t, int64_t>> Flow;
1197cc2493dSspupyrev     for (auto &Edge : Edges[Src]) {
1207cc2493dSspupyrev       if (Edge.Flow > 0)
1217cc2493dSspupyrev         Flow.push_back(std::make_pair(Edge.Dst, Edge.Flow));
1227cc2493dSspupyrev     }
1237cc2493dSspupyrev     return Flow;
1247cc2493dSspupyrev   }
1257cc2493dSspupyrev 
1267cc2493dSspupyrev   /// Get the total flow between a pair of nodes.
1277cc2493dSspupyrev   int64_t getFlow(uint64_t Src, uint64_t Dst) const {
1287cc2493dSspupyrev     int64_t Flow = 0;
1297cc2493dSspupyrev     for (auto &Edge : Edges[Src]) {
1307cc2493dSspupyrev       if (Edge.Dst == Dst) {
1317cc2493dSspupyrev         Flow += Edge.Flow;
1327cc2493dSspupyrev       }
1337cc2493dSspupyrev     }
1347cc2493dSspupyrev     return Flow;
1357cc2493dSspupyrev   }
1367cc2493dSspupyrev 
1377cc2493dSspupyrev   /// A cost of increasing a block's count by one.
1387cc2493dSspupyrev   static constexpr int64_t AuxCostInc = 10;
1397cc2493dSspupyrev   /// A cost of decreasing a block's count by one.
1407cc2493dSspupyrev   static constexpr int64_t AuxCostDec = 20;
1417cc2493dSspupyrev   /// A cost of increasing a count of zero-weight block by one.
1427cc2493dSspupyrev   static constexpr int64_t AuxCostIncZero = 11;
1437cc2493dSspupyrev   /// A cost of increasing the entry block's count by one.
1447cc2493dSspupyrev   static constexpr int64_t AuxCostIncEntry = 40;
1457cc2493dSspupyrev   /// A cost of decreasing the entry block's count by one.
1467cc2493dSspupyrev   static constexpr int64_t AuxCostDecEntry = 10;
1477cc2493dSspupyrev   /// A cost of taking an unlikely jump.
148*13d1364aSspupyrev   static constexpr int64_t AuxCostUnlikely = ((int64_t)1) << 30;
1497cc2493dSspupyrev 
1507cc2493dSspupyrev private:
1517cc2493dSspupyrev   /// Check for existence of an augmenting path with a positive capacity.
1527cc2493dSspupyrev   bool findAugmentingPath() {
1537cc2493dSspupyrev     // Initialize data structures
1547cc2493dSspupyrev     for (auto &Node : Nodes) {
1557cc2493dSspupyrev       Node.Distance = INF;
1567cc2493dSspupyrev       Node.ParentNode = uint64_t(-1);
1577cc2493dSspupyrev       Node.ParentEdgeIndex = uint64_t(-1);
1587cc2493dSspupyrev       Node.Taken = false;
1597cc2493dSspupyrev     }
1607cc2493dSspupyrev 
1617cc2493dSspupyrev     std::queue<uint64_t> Queue;
1627cc2493dSspupyrev     Queue.push(Source);
1637cc2493dSspupyrev     Nodes[Source].Distance = 0;
1647cc2493dSspupyrev     Nodes[Source].Taken = true;
1657cc2493dSspupyrev     while (!Queue.empty()) {
1667cc2493dSspupyrev       uint64_t Src = Queue.front();
1677cc2493dSspupyrev       Queue.pop();
1687cc2493dSspupyrev       Nodes[Src].Taken = false;
1697cc2493dSspupyrev       // Although the residual network contains edges with negative costs
1707cc2493dSspupyrev       // (in particular, backward edges), it can be shown that there are no
1717cc2493dSspupyrev       // negative-weight cycles and the following two invariants are maintained:
1727cc2493dSspupyrev       // (i) Dist[Source, V] >= 0 and (ii) Dist[V, Target] >= 0 for all nodes V,
1737cc2493dSspupyrev       // where Dist is the length of the shortest path between two nodes. This
1747cc2493dSspupyrev       // allows to prune the search-space of the path-finding algorithm using
1757cc2493dSspupyrev       // the following early-stop criteria:
1767cc2493dSspupyrev       // -- If we find a path with zero-distance from Source to Target, stop the
1777cc2493dSspupyrev       //    search, as the path is the shortest since Dist[Source, Target] >= 0;
1787cc2493dSspupyrev       // -- If we have Dist[Source, V] > Dist[Source, Target], then do not
1797cc2493dSspupyrev       //    process node V, as it is guaranteed _not_ to be on a shortest path
1807cc2493dSspupyrev       //    from Source to Target; it follows from inequalities
1817cc2493dSspupyrev       //    Dist[Source, Target] >= Dist[Source, V] + Dist[V, Target]
1827cc2493dSspupyrev       //                         >= Dist[Source, V]
1837cc2493dSspupyrev       if (Nodes[Target].Distance == 0)
1847cc2493dSspupyrev         break;
1857cc2493dSspupyrev       if (Nodes[Src].Distance > Nodes[Target].Distance)
1867cc2493dSspupyrev         continue;
1877cc2493dSspupyrev 
1887cc2493dSspupyrev       // Process adjacent edges
1897cc2493dSspupyrev       for (uint64_t EdgeIdx = 0; EdgeIdx < Edges[Src].size(); EdgeIdx++) {
1907cc2493dSspupyrev         auto &Edge = Edges[Src][EdgeIdx];
1917cc2493dSspupyrev         if (Edge.Flow < Edge.Capacity) {
1927cc2493dSspupyrev           uint64_t Dst = Edge.Dst;
1937cc2493dSspupyrev           int64_t NewDistance = Nodes[Src].Distance + Edge.Cost;
1947cc2493dSspupyrev           if (Nodes[Dst].Distance > NewDistance) {
1957cc2493dSspupyrev             // Update the distance and the parent node/edge
1967cc2493dSspupyrev             Nodes[Dst].Distance = NewDistance;
1977cc2493dSspupyrev             Nodes[Dst].ParentNode = Src;
1987cc2493dSspupyrev             Nodes[Dst].ParentEdgeIndex = EdgeIdx;
1997cc2493dSspupyrev             // Add the node to the queue, if it is not there yet
2007cc2493dSspupyrev             if (!Nodes[Dst].Taken) {
2017cc2493dSspupyrev               Queue.push(Dst);
2027cc2493dSspupyrev               Nodes[Dst].Taken = true;
2037cc2493dSspupyrev             }
2047cc2493dSspupyrev           }
2057cc2493dSspupyrev         }
2067cc2493dSspupyrev       }
2077cc2493dSspupyrev     }
2087cc2493dSspupyrev 
2097cc2493dSspupyrev     return Nodes[Target].Distance != INF;
2107cc2493dSspupyrev   }
2117cc2493dSspupyrev 
2127cc2493dSspupyrev   /// Update the current flow along the augmenting path.
2137cc2493dSspupyrev   void augmentFlowAlongPath() {
2147cc2493dSspupyrev     // Find path capacity
2157cc2493dSspupyrev     int64_t PathCapacity = INF;
2167cc2493dSspupyrev     uint64_t Now = Target;
2177cc2493dSspupyrev     while (Now != Source) {
2187cc2493dSspupyrev       uint64_t Pred = Nodes[Now].ParentNode;
2197cc2493dSspupyrev       auto &Edge = Edges[Pred][Nodes[Now].ParentEdgeIndex];
2207cc2493dSspupyrev       PathCapacity = std::min(PathCapacity, Edge.Capacity - Edge.Flow);
2217cc2493dSspupyrev       Now = Pred;
2227cc2493dSspupyrev     }
2237cc2493dSspupyrev 
22493a2c291Sspupyrev     assert(PathCapacity > 0 && "found an incorrect augmenting path");
2257cc2493dSspupyrev 
2267cc2493dSspupyrev     // Update the flow along the path
2277cc2493dSspupyrev     Now = Target;
2287cc2493dSspupyrev     while (Now != Source) {
2297cc2493dSspupyrev       uint64_t Pred = Nodes[Now].ParentNode;
2307cc2493dSspupyrev       auto &Edge = Edges[Pred][Nodes[Now].ParentEdgeIndex];
2317cc2493dSspupyrev       auto &RevEdge = Edges[Now][Edge.RevEdgeIndex];
2327cc2493dSspupyrev 
2337cc2493dSspupyrev       Edge.Flow += PathCapacity;
2347cc2493dSspupyrev       RevEdge.Flow -= PathCapacity;
2357cc2493dSspupyrev 
2367cc2493dSspupyrev       Now = Pred;
2377cc2493dSspupyrev     }
2387cc2493dSspupyrev   }
2397cc2493dSspupyrev 
240*13d1364aSspupyrev   /// A node in a flow network.
2417cc2493dSspupyrev   struct Node {
2427cc2493dSspupyrev     /// The cost of the cheapest path from the source to the current node.
2437cc2493dSspupyrev     int64_t Distance;
2447cc2493dSspupyrev     /// The node preceding the current one in the path.
2457cc2493dSspupyrev     uint64_t ParentNode;
2467cc2493dSspupyrev     /// The index of the edge between ParentNode and the current node.
2477cc2493dSspupyrev     uint64_t ParentEdgeIndex;
2487cc2493dSspupyrev     /// An indicator of whether the current node is in a queue.
2497cc2493dSspupyrev     bool Taken;
2507cc2493dSspupyrev   };
2517cc2493dSspupyrev   /// An edge in a flow network.
2527cc2493dSspupyrev   struct Edge {
2537cc2493dSspupyrev     /// The cost of the edge.
2547cc2493dSspupyrev     int64_t Cost;
2557cc2493dSspupyrev     /// The capacity of the edge.
2567cc2493dSspupyrev     int64_t Capacity;
2577cc2493dSspupyrev     /// The current flow on the edge.
2587cc2493dSspupyrev     int64_t Flow;
2597cc2493dSspupyrev     /// The destination node of the edge.
2607cc2493dSspupyrev     uint64_t Dst;
2617cc2493dSspupyrev     /// The index of the reverse edge between Dst and the current node.
2627cc2493dSspupyrev     uint64_t RevEdgeIndex;
2637cc2493dSspupyrev   };
2647cc2493dSspupyrev 
2657cc2493dSspupyrev   /// The set of network nodes.
2667cc2493dSspupyrev   std::vector<Node> Nodes;
2677cc2493dSspupyrev   /// The set of network edges.
2687cc2493dSspupyrev   std::vector<std::vector<Edge>> Edges;
2697cc2493dSspupyrev   /// Source node of the flow.
2707cc2493dSspupyrev   uint64_t Source;
2717cc2493dSspupyrev   /// Target (sink) node of the flow.
2727cc2493dSspupyrev   uint64_t Target;
2737cc2493dSspupyrev };
2747cc2493dSspupyrev 
27593a2c291Sspupyrev /// A post-processing adjustment of control flow. It applies two steps by
27693a2c291Sspupyrev /// rerouting some flow and making it more realistic:
27793a2c291Sspupyrev ///
27893a2c291Sspupyrev /// - First, it removes all isolated components ("islands") with a positive flow
27993a2c291Sspupyrev ///   that are unreachable from the entry block. For every such component, we
28093a2c291Sspupyrev ///   find the shortest from the entry to an exit passing through the component,
28193a2c291Sspupyrev ///   and increase the flow by one unit along the path.
28293a2c291Sspupyrev ///
28393a2c291Sspupyrev /// - Second, it identifies all "unknown subgraphs" consisting of basic blocks
28493a2c291Sspupyrev ///   with no sampled counts. Then it rebalnces the flow that goes through such
28593a2c291Sspupyrev ///   a subgraph so that each branch is taken with probability 50%.
28693a2c291Sspupyrev ///   An unknown subgraph is such that for every two nodes u and v:
28793a2c291Sspupyrev ///     - u dominates v and u is not unknown;
28893a2c291Sspupyrev ///     - v post-dominates u; and
28993a2c291Sspupyrev ///     - all inner-nodes of all (u,v)-paths are unknown.
29093a2c291Sspupyrev ///
29198dd2f9eSspupyrev class FlowAdjuster {
29298dd2f9eSspupyrev public:
29398dd2f9eSspupyrev   FlowAdjuster(FlowFunction &Func) : Func(Func) {
29498dd2f9eSspupyrev     assert(Func.Blocks[Func.Entry].isEntry() &&
29598dd2f9eSspupyrev            "incorrect index of the entry block");
29698dd2f9eSspupyrev   }
29798dd2f9eSspupyrev 
29898dd2f9eSspupyrev   // Run the post-processing
29998dd2f9eSspupyrev   void run() {
30093a2c291Sspupyrev     /// Adjust the flow to get rid of isolated components.
30198dd2f9eSspupyrev     joinIsolatedComponents();
30293a2c291Sspupyrev 
30393a2c291Sspupyrev     /// Rebalance the flow inside unknown subgraphs.
30493a2c291Sspupyrev     rebalanceUnknownSubgraphs();
30598dd2f9eSspupyrev   }
30698dd2f9eSspupyrev 
30798dd2f9eSspupyrev private:
30898dd2f9eSspupyrev   void joinIsolatedComponents() {
30998dd2f9eSspupyrev     // Find blocks that are reachable from the source
3105f4ae564SJan Svoboda     auto Visited = BitVector(NumBlocks(), false);
31198dd2f9eSspupyrev     findReachable(Func.Entry, Visited);
31298dd2f9eSspupyrev 
31398dd2f9eSspupyrev     // Iterate over all non-reachable blocks and adjust their weights
31498dd2f9eSspupyrev     for (uint64_t I = 0; I < NumBlocks(); I++) {
31598dd2f9eSspupyrev       auto &Block = Func.Blocks[I];
31698dd2f9eSspupyrev       if (Block.Flow > 0 && !Visited[I]) {
31798dd2f9eSspupyrev         // Find a path from the entry to an exit passing through the block I
31898dd2f9eSspupyrev         auto Path = findShortestPath(I);
31998dd2f9eSspupyrev         // Increase the flow along the path
32098dd2f9eSspupyrev         assert(Path.size() > 0 && Path[0]->Source == Func.Entry &&
32198dd2f9eSspupyrev                "incorrectly computed path adjusting control flow");
32298dd2f9eSspupyrev         Func.Blocks[Func.Entry].Flow += 1;
32398dd2f9eSspupyrev         for (auto &Jump : Path) {
32498dd2f9eSspupyrev           Jump->Flow += 1;
32598dd2f9eSspupyrev           Func.Blocks[Jump->Target].Flow += 1;
32698dd2f9eSspupyrev           // Update reachability
32798dd2f9eSspupyrev           findReachable(Jump->Target, Visited);
32898dd2f9eSspupyrev         }
32998dd2f9eSspupyrev       }
33098dd2f9eSspupyrev     }
33198dd2f9eSspupyrev   }
33298dd2f9eSspupyrev 
33393a2c291Sspupyrev   /// Run BFS from a given block along the jumps with a positive flow and mark
33498dd2f9eSspupyrev   /// all reachable blocks.
3355f4ae564SJan Svoboda   void findReachable(uint64_t Src, BitVector &Visited) {
33698dd2f9eSspupyrev     if (Visited[Src])
33798dd2f9eSspupyrev       return;
33898dd2f9eSspupyrev     std::queue<uint64_t> Queue;
33998dd2f9eSspupyrev     Queue.push(Src);
34098dd2f9eSspupyrev     Visited[Src] = true;
34198dd2f9eSspupyrev     while (!Queue.empty()) {
34298dd2f9eSspupyrev       Src = Queue.front();
34398dd2f9eSspupyrev       Queue.pop();
34498dd2f9eSspupyrev       for (auto Jump : Func.Blocks[Src].SuccJumps) {
34598dd2f9eSspupyrev         uint64_t Dst = Jump->Target;
34698dd2f9eSspupyrev         if (Jump->Flow > 0 && !Visited[Dst]) {
34798dd2f9eSspupyrev           Queue.push(Dst);
34898dd2f9eSspupyrev           Visited[Dst] = true;
34998dd2f9eSspupyrev         }
35098dd2f9eSspupyrev       }
35198dd2f9eSspupyrev     }
35298dd2f9eSspupyrev   }
35398dd2f9eSspupyrev 
35498dd2f9eSspupyrev   /// Find the shortest path from the entry block to an exit block passing
35598dd2f9eSspupyrev   /// through a given block.
35698dd2f9eSspupyrev   std::vector<FlowJump *> findShortestPath(uint64_t BlockIdx) {
35798dd2f9eSspupyrev     // A path from the entry block to BlockIdx
35898dd2f9eSspupyrev     auto ForwardPath = findShortestPath(Func.Entry, BlockIdx);
35998dd2f9eSspupyrev     // A path from BlockIdx to an exit block
36098dd2f9eSspupyrev     auto BackwardPath = findShortestPath(BlockIdx, AnyExitBlock);
36198dd2f9eSspupyrev 
36298dd2f9eSspupyrev     // Concatenate the two paths
36398dd2f9eSspupyrev     std::vector<FlowJump *> Result;
36498dd2f9eSspupyrev     Result.insert(Result.end(), ForwardPath.begin(), ForwardPath.end());
36598dd2f9eSspupyrev     Result.insert(Result.end(), BackwardPath.begin(), BackwardPath.end());
36698dd2f9eSspupyrev     return Result;
36798dd2f9eSspupyrev   }
36898dd2f9eSspupyrev 
36998dd2f9eSspupyrev   /// Apply the Dijkstra algorithm to find the shortest path from a given
37098dd2f9eSspupyrev   /// Source to a given Target block.
37198dd2f9eSspupyrev   /// If Target == -1, then the path ends at an exit block.
37298dd2f9eSspupyrev   std::vector<FlowJump *> findShortestPath(uint64_t Source, uint64_t Target) {
37398dd2f9eSspupyrev     // Quit early, if possible
37498dd2f9eSspupyrev     if (Source == Target)
37598dd2f9eSspupyrev       return std::vector<FlowJump *>();
37698dd2f9eSspupyrev     if (Func.Blocks[Source].isExit() && Target == AnyExitBlock)
37798dd2f9eSspupyrev       return std::vector<FlowJump *>();
37898dd2f9eSspupyrev 
37998dd2f9eSspupyrev     // Initialize data structures
38098dd2f9eSspupyrev     auto Distance = std::vector<int64_t>(NumBlocks(), INF);
38198dd2f9eSspupyrev     auto Parent = std::vector<FlowJump *>(NumBlocks(), nullptr);
38298dd2f9eSspupyrev     Distance[Source] = 0;
38398dd2f9eSspupyrev     std::set<std::pair<uint64_t, uint64_t>> Queue;
38498dd2f9eSspupyrev     Queue.insert(std::make_pair(Distance[Source], Source));
38598dd2f9eSspupyrev 
38698dd2f9eSspupyrev     // Run the Dijkstra algorithm
38798dd2f9eSspupyrev     while (!Queue.empty()) {
38898dd2f9eSspupyrev       uint64_t Src = Queue.begin()->second;
38998dd2f9eSspupyrev       Queue.erase(Queue.begin());
39098dd2f9eSspupyrev       // If we found a solution, quit early
39198dd2f9eSspupyrev       if (Src == Target ||
39298dd2f9eSspupyrev           (Func.Blocks[Src].isExit() && Target == AnyExitBlock))
39398dd2f9eSspupyrev         break;
39498dd2f9eSspupyrev 
39598dd2f9eSspupyrev       for (auto Jump : Func.Blocks[Src].SuccJumps) {
39698dd2f9eSspupyrev         uint64_t Dst = Jump->Target;
39798dd2f9eSspupyrev         int64_t JumpDist = jumpDistance(Jump);
39898dd2f9eSspupyrev         if (Distance[Dst] > Distance[Src] + JumpDist) {
39998dd2f9eSspupyrev           Queue.erase(std::make_pair(Distance[Dst], Dst));
40098dd2f9eSspupyrev 
40198dd2f9eSspupyrev           Distance[Dst] = Distance[Src] + JumpDist;
40298dd2f9eSspupyrev           Parent[Dst] = Jump;
40398dd2f9eSspupyrev 
40498dd2f9eSspupyrev           Queue.insert(std::make_pair(Distance[Dst], Dst));
40598dd2f9eSspupyrev         }
40698dd2f9eSspupyrev       }
40798dd2f9eSspupyrev     }
40898dd2f9eSspupyrev     // If Target is not provided, find the closest exit block
40998dd2f9eSspupyrev     if (Target == AnyExitBlock) {
41098dd2f9eSspupyrev       for (uint64_t I = 0; I < NumBlocks(); I++) {
41198dd2f9eSspupyrev         if (Func.Blocks[I].isExit() && Parent[I] != nullptr) {
41298dd2f9eSspupyrev           if (Target == AnyExitBlock || Distance[Target] > Distance[I]) {
41398dd2f9eSspupyrev             Target = I;
41498dd2f9eSspupyrev           }
41598dd2f9eSspupyrev         }
41698dd2f9eSspupyrev       }
41798dd2f9eSspupyrev     }
41898dd2f9eSspupyrev     assert(Parent[Target] != nullptr && "a path does not exist");
41998dd2f9eSspupyrev 
42098dd2f9eSspupyrev     // Extract the constructed path
42198dd2f9eSspupyrev     std::vector<FlowJump *> Result;
42298dd2f9eSspupyrev     uint64_t Now = Target;
42398dd2f9eSspupyrev     while (Now != Source) {
42498dd2f9eSspupyrev       assert(Now == Parent[Now]->Target && "incorrect parent jump");
42598dd2f9eSspupyrev       Result.push_back(Parent[Now]);
42698dd2f9eSspupyrev       Now = Parent[Now]->Source;
42798dd2f9eSspupyrev     }
42898dd2f9eSspupyrev     // Reverse the path, since it is extracted from Target to Source
42998dd2f9eSspupyrev     std::reverse(Result.begin(), Result.end());
43098dd2f9eSspupyrev     return Result;
43198dd2f9eSspupyrev   }
43298dd2f9eSspupyrev 
43398dd2f9eSspupyrev   /// A distance of a path for a given jump.
43498dd2f9eSspupyrev   /// In order to incite the path to use blocks/jumps with large positive flow,
43598dd2f9eSspupyrev   /// and avoid changing branch probability of outgoing edges drastically,
43698dd2f9eSspupyrev   /// set the distance as follows:
43798dd2f9eSspupyrev   ///   if Jump.Flow > 0, then distance = max(100 - Jump->Flow, 0)
43898dd2f9eSspupyrev   ///   if Block.Weight > 0, then distance = 1
43998dd2f9eSspupyrev   ///   otherwise distance >> 1
44098dd2f9eSspupyrev   int64_t jumpDistance(FlowJump *Jump) const {
44198dd2f9eSspupyrev     int64_t BaseDistance = 100;
44298dd2f9eSspupyrev     if (Jump->IsUnlikely)
44398dd2f9eSspupyrev       return MinCostMaxFlow::AuxCostUnlikely;
44498dd2f9eSspupyrev     if (Jump->Flow > 0)
44598dd2f9eSspupyrev       return std::max(BaseDistance - (int64_t)Jump->Flow, (int64_t)0);
44698dd2f9eSspupyrev     if (Func.Blocks[Jump->Target].Weight > 0)
44798dd2f9eSspupyrev       return BaseDistance;
44898dd2f9eSspupyrev     return BaseDistance * (NumBlocks() + 1);
44998dd2f9eSspupyrev   };
45098dd2f9eSspupyrev 
45198dd2f9eSspupyrev   uint64_t NumBlocks() const { return Func.Blocks.size(); }
45298dd2f9eSspupyrev 
453*13d1364aSspupyrev   /// Rebalance unknown subgraphs so that the flow is split evenly across the
454*13d1364aSspupyrev   /// outgoing branches of every block of the subgraph. The method iterates over
455*13d1364aSspupyrev   /// blocks with known weight and identifies unknown subgraphs rooted at the
456*13d1364aSspupyrev   /// blocks. Then it verifies if flow rebalancing is feasible and applies it.
45793a2c291Sspupyrev   void rebalanceUnknownSubgraphs() {
458*13d1364aSspupyrev     // Try to find unknown subgraphs from each block
45993a2c291Sspupyrev     for (uint64_t I = 0; I < Func.Blocks.size(); I++) {
46093a2c291Sspupyrev       auto SrcBlock = &Func.Blocks[I];
461*13d1364aSspupyrev       // Verify if rebalancing rooted at SrcBlock is feasible
462*13d1364aSspupyrev       if (!canRebalanceAtRoot(SrcBlock))
46393a2c291Sspupyrev         continue;
46493a2c291Sspupyrev 
465*13d1364aSspupyrev       // Find an unknown subgraphs starting at SrcBlock. Along the way,
466*13d1364aSspupyrev       // fill in known destinations and intermediate unknown blocks.
467*13d1364aSspupyrev       std::vector<FlowBlock *> UnknownBlocks;
468*13d1364aSspupyrev       std::vector<FlowBlock *> KnownDstBlocks;
469*13d1364aSspupyrev       findUnknownSubgraph(SrcBlock, KnownDstBlocks, UnknownBlocks);
470*13d1364aSspupyrev 
471*13d1364aSspupyrev       // Verify if rebalancing of the subgraph is feasible. If the search is
472*13d1364aSspupyrev       // successful, find the unique destination block (which can be null)
47393a2c291Sspupyrev       FlowBlock *DstBlock = nullptr;
474*13d1364aSspupyrev       if (!canRebalanceSubgraph(SrcBlock, KnownDstBlocks, UnknownBlocks,
475*13d1364aSspupyrev                                 DstBlock))
47693a2c291Sspupyrev         continue;
477*13d1364aSspupyrev 
478*13d1364aSspupyrev       // We cannot rebalance subgraphs containing cycles among unknown blocks
479*13d1364aSspupyrev       if (!isAcyclicSubgraph(SrcBlock, DstBlock, UnknownBlocks))
48093a2c291Sspupyrev         continue;
48193a2c291Sspupyrev 
48293a2c291Sspupyrev       // Rebalance the flow
483*13d1364aSspupyrev       rebalanceUnknownSubgraph(SrcBlock, DstBlock, UnknownBlocks);
48493a2c291Sspupyrev     }
48593a2c291Sspupyrev   }
48693a2c291Sspupyrev 
487*13d1364aSspupyrev   /// Verify if rebalancing rooted at a given block is possible.
488*13d1364aSspupyrev   bool canRebalanceAtRoot(const FlowBlock *SrcBlock) {
489*13d1364aSspupyrev     // Do not attempt to find unknown subgraphs from an unknown or a
490*13d1364aSspupyrev     // zero-flow block
491*13d1364aSspupyrev     if (SrcBlock->UnknownWeight || SrcBlock->Flow == 0)
492*13d1364aSspupyrev       return false;
493*13d1364aSspupyrev 
494*13d1364aSspupyrev     // Do not attempt to process subgraphs from a block w/o unknown sucessors
495*13d1364aSspupyrev     bool HasUnknownSuccs = false;
496*13d1364aSspupyrev     for (auto Jump : SrcBlock->SuccJumps) {
497*13d1364aSspupyrev       if (Func.Blocks[Jump->Target].UnknownWeight) {
498*13d1364aSspupyrev         HasUnknownSuccs = true;
499*13d1364aSspupyrev         break;
500*13d1364aSspupyrev       }
501*13d1364aSspupyrev     }
502*13d1364aSspupyrev     if (!HasUnknownSuccs)
503*13d1364aSspupyrev       return false;
504*13d1364aSspupyrev 
505*13d1364aSspupyrev     return true;
506*13d1364aSspupyrev   }
507*13d1364aSspupyrev 
508*13d1364aSspupyrev   /// Find an unknown subgraph starting at block SrcBlock. The method sets
509*13d1364aSspupyrev   /// identified destinations, KnownDstBlocks, and intermediate UnknownBlocks.
510*13d1364aSspupyrev   void findUnknownSubgraph(const FlowBlock *SrcBlock,
511*13d1364aSspupyrev                            std::vector<FlowBlock *> &KnownDstBlocks,
512*13d1364aSspupyrev                            std::vector<FlowBlock *> &UnknownBlocks) {
51393a2c291Sspupyrev     // Run BFS from SrcBlock and make sure all paths are going through unknown
51493a2c291Sspupyrev     // blocks and end at a non-unknown DstBlock
5155f4ae564SJan Svoboda     auto Visited = BitVector(NumBlocks(), false);
51693a2c291Sspupyrev     std::queue<uint64_t> Queue;
51793a2c291Sspupyrev 
51893a2c291Sspupyrev     Queue.push(SrcBlock->Index);
51993a2c291Sspupyrev     Visited[SrcBlock->Index] = true;
52093a2c291Sspupyrev     while (!Queue.empty()) {
52193a2c291Sspupyrev       auto &Block = Func.Blocks[Queue.front()];
52293a2c291Sspupyrev       Queue.pop();
52393a2c291Sspupyrev       // Process blocks reachable from Block
52493a2c291Sspupyrev       for (auto Jump : Block.SuccJumps) {
525*13d1364aSspupyrev         // If Jump can be ignored, skip it
526*13d1364aSspupyrev         if (ignoreJump(SrcBlock, nullptr, Jump))
527*13d1364aSspupyrev           continue;
528*13d1364aSspupyrev 
52993a2c291Sspupyrev         uint64_t Dst = Jump->Target;
530*13d1364aSspupyrev         // If Dst has been visited, skip Jump
53193a2c291Sspupyrev         if (Visited[Dst])
53293a2c291Sspupyrev           continue;
533*13d1364aSspupyrev         // Process block Dst
53493a2c291Sspupyrev         Visited[Dst] = true;
53593a2c291Sspupyrev         if (!Func.Blocks[Dst].UnknownWeight) {
536*13d1364aSspupyrev           KnownDstBlocks.push_back(&Func.Blocks[Dst]);
53793a2c291Sspupyrev         } else {
53893a2c291Sspupyrev           Queue.push(Dst);
539*13d1364aSspupyrev           UnknownBlocks.push_back(&Func.Blocks[Dst]);
540*13d1364aSspupyrev         }
54193a2c291Sspupyrev       }
54293a2c291Sspupyrev     }
54393a2c291Sspupyrev   }
54493a2c291Sspupyrev 
545*13d1364aSspupyrev   /// Verify if rebalancing of the subgraph is feasible. If the checks are
546*13d1364aSspupyrev   /// successful, set the unique destination block, DstBlock (can be null).
547*13d1364aSspupyrev   bool canRebalanceSubgraph(const FlowBlock *SrcBlock,
548*13d1364aSspupyrev                             const std::vector<FlowBlock *> &KnownDstBlocks,
549*13d1364aSspupyrev                             const std::vector<FlowBlock *> &UnknownBlocks,
550*13d1364aSspupyrev                             FlowBlock *&DstBlock) {
55193a2c291Sspupyrev     // If the list of unknown blocks is empty, we don't need rebalancing
552*13d1364aSspupyrev     if (UnknownBlocks.empty())
55393a2c291Sspupyrev       return false;
554*13d1364aSspupyrev 
555*13d1364aSspupyrev     // If there are multiple known sinks, we can't rebalance
556*13d1364aSspupyrev     if (KnownDstBlocks.size() > 1)
55793a2c291Sspupyrev       return false;
558*13d1364aSspupyrev     DstBlock = KnownDstBlocks.empty() ? nullptr : KnownDstBlocks.front();
559*13d1364aSspupyrev 
560*13d1364aSspupyrev     // Verify sinks of the subgraph
561*13d1364aSspupyrev     for (auto Block : UnknownBlocks) {
562*13d1364aSspupyrev       if (Block->SuccJumps.empty()) {
563*13d1364aSspupyrev         // If there are multiple (known and unknown) sinks, we can't rebalance
564*13d1364aSspupyrev         if (DstBlock != nullptr)
565*13d1364aSspupyrev           return false;
566*13d1364aSspupyrev         continue;
567*13d1364aSspupyrev       }
568*13d1364aSspupyrev       size_t NumIgnoredJumps = 0;
569*13d1364aSspupyrev       for (auto Jump : Block->SuccJumps) {
570*13d1364aSspupyrev         if (ignoreJump(SrcBlock, DstBlock, Jump))
571*13d1364aSspupyrev           NumIgnoredJumps++;
572*13d1364aSspupyrev       }
573*13d1364aSspupyrev       // If there is a non-sink block in UnknownBlocks with all jumps ignored,
574*13d1364aSspupyrev       // then we can't rebalance
575*13d1364aSspupyrev       if (NumIgnoredJumps == Block->SuccJumps.size())
57693a2c291Sspupyrev         return false;
57793a2c291Sspupyrev     }
57893a2c291Sspupyrev 
57993a2c291Sspupyrev     return true;
58093a2c291Sspupyrev   }
58193a2c291Sspupyrev 
582*13d1364aSspupyrev   /// Decide whether the Jump is ignored while processing an unknown subgraphs
583*13d1364aSspupyrev   /// rooted at basic block SrcBlock with the destination block, DstBlock.
584*13d1364aSspupyrev   bool ignoreJump(const FlowBlock *SrcBlock, const FlowBlock *DstBlock,
585*13d1364aSspupyrev                   const FlowJump *Jump) {
586*13d1364aSspupyrev     // Ignore unlikely jumps with zero flow
587*13d1364aSspupyrev     if (Jump->IsUnlikely && Jump->Flow == 0)
588*13d1364aSspupyrev       return true;
589*13d1364aSspupyrev 
590*13d1364aSspupyrev     auto JumpSource = &Func.Blocks[Jump->Source];
591*13d1364aSspupyrev     auto JumpTarget = &Func.Blocks[Jump->Target];
592*13d1364aSspupyrev 
593*13d1364aSspupyrev     // Do not ignore jumps coming into DstBlock
594*13d1364aSspupyrev     if (DstBlock != nullptr && JumpTarget == DstBlock)
595*13d1364aSspupyrev       return false;
596*13d1364aSspupyrev 
597*13d1364aSspupyrev     // Ignore jumps out of SrcBlock to known blocks
598*13d1364aSspupyrev     if (!JumpTarget->UnknownWeight && JumpSource == SrcBlock)
599*13d1364aSspupyrev       return true;
600*13d1364aSspupyrev 
601*13d1364aSspupyrev     // Ignore jumps to known blocks with zero flow
602*13d1364aSspupyrev     if (!JumpTarget->UnknownWeight && JumpTarget->Flow == 0)
603*13d1364aSspupyrev       return true;
604*13d1364aSspupyrev 
605*13d1364aSspupyrev     return false;
606*13d1364aSspupyrev   }
607*13d1364aSspupyrev 
60893a2c291Sspupyrev   /// Verify if the given unknown subgraph is acyclic, and if yes, reorder
609*13d1364aSspupyrev   /// UnknownBlocks in the topological order (so that all jumps are "forward").
610*13d1364aSspupyrev   bool isAcyclicSubgraph(const FlowBlock *SrcBlock, const FlowBlock *DstBlock,
611*13d1364aSspupyrev                          std::vector<FlowBlock *> &UnknownBlocks) {
61293a2c291Sspupyrev     // Extract local in-degrees in the considered subgraph
61393a2c291Sspupyrev     auto LocalInDegree = std::vector<uint64_t>(NumBlocks(), 0);
614*13d1364aSspupyrev     auto fillInDegree = [&](const FlowBlock *Block) {
615*13d1364aSspupyrev       for (auto Jump : Block->SuccJumps) {
616*13d1364aSspupyrev         if (ignoreJump(SrcBlock, DstBlock, Jump))
617*13d1364aSspupyrev           continue;
61893a2c291Sspupyrev         LocalInDegree[Jump->Target]++;
61993a2c291Sspupyrev       }
620*13d1364aSspupyrev     };
621*13d1364aSspupyrev     fillInDegree(SrcBlock);
622*13d1364aSspupyrev     for (auto Block : UnknownBlocks) {
623*13d1364aSspupyrev       fillInDegree(Block);
62493a2c291Sspupyrev     }
62593a2c291Sspupyrev     // A loop containing SrcBlock
62693a2c291Sspupyrev     if (LocalInDegree[SrcBlock->Index] > 0)
62793a2c291Sspupyrev       return false;
62893a2c291Sspupyrev 
62993a2c291Sspupyrev     std::vector<FlowBlock *> AcyclicOrder;
63093a2c291Sspupyrev     std::queue<uint64_t> Queue;
63193a2c291Sspupyrev     Queue.push(SrcBlock->Index);
63293a2c291Sspupyrev     while (!Queue.empty()) {
633*13d1364aSspupyrev       FlowBlock *Block = &Func.Blocks[Queue.front()];
63493a2c291Sspupyrev       Queue.pop();
635*13d1364aSspupyrev       // Stop propagation once we reach DstBlock, if any
636*13d1364aSspupyrev       if (DstBlock != nullptr && Block == DstBlock)
63793a2c291Sspupyrev         break;
63893a2c291Sspupyrev 
639*13d1364aSspupyrev       // Keep an acyclic order of unknown blocks
640*13d1364aSspupyrev       if (Block->UnknownWeight && Block != SrcBlock)
641*13d1364aSspupyrev         AcyclicOrder.push_back(Block);
642*13d1364aSspupyrev 
64393a2c291Sspupyrev       // Add to the queue all successors with zero local in-degree
644*13d1364aSspupyrev       for (auto Jump : Block->SuccJumps) {
645*13d1364aSspupyrev         if (ignoreJump(SrcBlock, DstBlock, Jump))
646*13d1364aSspupyrev           continue;
64793a2c291Sspupyrev         uint64_t Dst = Jump->Target;
64893a2c291Sspupyrev         LocalInDegree[Dst]--;
64993a2c291Sspupyrev         if (LocalInDegree[Dst] == 0) {
65093a2c291Sspupyrev           Queue.push(Dst);
65193a2c291Sspupyrev         }
65293a2c291Sspupyrev       }
65393a2c291Sspupyrev     }
65493a2c291Sspupyrev 
65593a2c291Sspupyrev     // If there is a cycle in the subgraph, AcyclicOrder contains only a subset
65693a2c291Sspupyrev     // of all blocks
657*13d1364aSspupyrev     if (UnknownBlocks.size() != AcyclicOrder.size())
65893a2c291Sspupyrev       return false;
659*13d1364aSspupyrev     UnknownBlocks = AcyclicOrder;
66093a2c291Sspupyrev     return true;
66193a2c291Sspupyrev   }
66293a2c291Sspupyrev 
663*13d1364aSspupyrev   /// Rebalance a given subgraph rooted at SrcBlock, ending at DstBlock and
664*13d1364aSspupyrev   /// having UnknownBlocks intermediate blocks.
665*13d1364aSspupyrev   void rebalanceUnknownSubgraph(const FlowBlock *SrcBlock,
666*13d1364aSspupyrev                                 const FlowBlock *DstBlock,
667*13d1364aSspupyrev                                 const std::vector<FlowBlock *> &UnknownBlocks) {
66893a2c291Sspupyrev     assert(SrcBlock->Flow > 0 && "zero-flow block in unknown subgraph");
66993a2c291Sspupyrev 
670*13d1364aSspupyrev     // Ditribute flow from the source block
671*13d1364aSspupyrev     uint64_t BlockFlow = 0;
672*13d1364aSspupyrev     // SrcBlock's flow is the sum of outgoing flows along non-ignored jumps
673*13d1364aSspupyrev     for (auto Jump : SrcBlock->SuccJumps) {
674*13d1364aSspupyrev       if (ignoreJump(SrcBlock, DstBlock, Jump))
67593a2c291Sspupyrev         continue;
676*13d1364aSspupyrev       BlockFlow += Jump->Flow;
67793a2c291Sspupyrev     }
678*13d1364aSspupyrev     rebalanceBlock(SrcBlock, DstBlock, SrcBlock, BlockFlow);
679*13d1364aSspupyrev 
680*13d1364aSspupyrev     // Ditribute flow from the remaining blocks
681*13d1364aSspupyrev     for (auto Block : UnknownBlocks) {
682*13d1364aSspupyrev       assert(Block->UnknownWeight && "incorrect unknown subgraph");
683*13d1364aSspupyrev       uint64_t BlockFlow = 0;
684*13d1364aSspupyrev       // Block's flow is the sum of incoming flows
685*13d1364aSspupyrev       for (auto Jump : Block->PredJumps) {
686*13d1364aSspupyrev         BlockFlow += Jump->Flow;
687*13d1364aSspupyrev       }
688*13d1364aSspupyrev       Block->Flow = BlockFlow;
689*13d1364aSspupyrev       rebalanceBlock(SrcBlock, DstBlock, Block, BlockFlow);
690*13d1364aSspupyrev     }
691*13d1364aSspupyrev   }
692*13d1364aSspupyrev 
693*13d1364aSspupyrev   /// Redistribute flow for a block in a subgraph rooted at SrcBlock,
694*13d1364aSspupyrev   /// and ending at DstBlock.
695*13d1364aSspupyrev   void rebalanceBlock(const FlowBlock *SrcBlock, const FlowBlock *DstBlock,
696*13d1364aSspupyrev                       const FlowBlock *Block, uint64_t BlockFlow) {
697*13d1364aSspupyrev     // Process all successor jumps and update corresponding flow values
698*13d1364aSspupyrev     size_t BlockDegree = 0;
699*13d1364aSspupyrev     for (auto Jump : Block->SuccJumps) {
700*13d1364aSspupyrev       if (ignoreJump(SrcBlock, DstBlock, Jump))
701*13d1364aSspupyrev         continue;
702*13d1364aSspupyrev       BlockDegree++;
703*13d1364aSspupyrev     }
704*13d1364aSspupyrev     // If all successor jumps of the block are ignored, skip it
705*13d1364aSspupyrev     if (DstBlock == nullptr && BlockDegree == 0)
706*13d1364aSspupyrev       return;
707*13d1364aSspupyrev     assert(BlockDegree > 0 && "all outgoing jumps are ignored");
708*13d1364aSspupyrev 
709*13d1364aSspupyrev     // Each of the Block's successors gets the following amount of flow.
710*13d1364aSspupyrev     // Rounding the value up so that all flow is propagated
711*13d1364aSspupyrev     uint64_t SuccFlow = (BlockFlow + BlockDegree - 1) / BlockDegree;
712*13d1364aSspupyrev     for (auto Jump : Block->SuccJumps) {
713*13d1364aSspupyrev       if (ignoreJump(SrcBlock, DstBlock, Jump))
714*13d1364aSspupyrev         continue;
715*13d1364aSspupyrev       uint64_t Flow = std::min(SuccFlow, BlockFlow);
71693a2c291Sspupyrev       Jump->Flow = Flow;
717*13d1364aSspupyrev       BlockFlow -= Flow;
71893a2c291Sspupyrev     }
719*13d1364aSspupyrev     assert(BlockFlow == 0 && "not all flow is propagated");
72093a2c291Sspupyrev   }
72193a2c291Sspupyrev 
72298dd2f9eSspupyrev   /// A constant indicating an arbitrary exit block of a function.
72398dd2f9eSspupyrev   static constexpr uint64_t AnyExitBlock = uint64_t(-1);
72498dd2f9eSspupyrev 
72598dd2f9eSspupyrev   /// The function.
72698dd2f9eSspupyrev   FlowFunction &Func;
72798dd2f9eSspupyrev };
72898dd2f9eSspupyrev 
7297cc2493dSspupyrev /// Initializing flow network for a given function.
7307cc2493dSspupyrev ///
7317cc2493dSspupyrev /// Every block is split into three nodes that are responsible for (i) an
7327cc2493dSspupyrev /// incoming flow, (ii) an outgoing flow, and (iii) penalizing an increase or
7337cc2493dSspupyrev /// reduction of the block weight.
7347cc2493dSspupyrev void initializeNetwork(MinCostMaxFlow &Network, FlowFunction &Func) {
7357cc2493dSspupyrev   uint64_t NumBlocks = Func.Blocks.size();
7367cc2493dSspupyrev   assert(NumBlocks > 1 && "Too few blocks in a function");
7377cc2493dSspupyrev   LLVM_DEBUG(dbgs() << "Initializing profi for " << NumBlocks << " blocks\n");
7387cc2493dSspupyrev 
7397cc2493dSspupyrev   // Pre-process data: make sure the entry weight is at least 1
7407cc2493dSspupyrev   if (Func.Blocks[Func.Entry].Weight == 0) {
7417cc2493dSspupyrev     Func.Blocks[Func.Entry].Weight = 1;
7427cc2493dSspupyrev   }
7437cc2493dSspupyrev   // Introducing dummy source/sink pairs to allow flow circulation.
7447cc2493dSspupyrev   // The nodes corresponding to blocks of Func have indicies in the range
7457cc2493dSspupyrev   // [0..3 * NumBlocks); the dummy nodes are indexed by the next four values.
7467cc2493dSspupyrev   uint64_t S = 3 * NumBlocks;
7477cc2493dSspupyrev   uint64_t T = S + 1;
7487cc2493dSspupyrev   uint64_t S1 = S + 2;
7497cc2493dSspupyrev   uint64_t T1 = S + 3;
7507cc2493dSspupyrev 
7517cc2493dSspupyrev   Network.initialize(3 * NumBlocks + 4, S1, T1);
7527cc2493dSspupyrev 
7537cc2493dSspupyrev   // Create three nodes for every block of the function
7547cc2493dSspupyrev   for (uint64_t B = 0; B < NumBlocks; B++) {
7557cc2493dSspupyrev     auto &Block = Func.Blocks[B];
7567cc2493dSspupyrev     assert((!Block.UnknownWeight || Block.Weight == 0 || Block.isEntry()) &&
7577cc2493dSspupyrev            "non-zero weight of a block w/o weight except for an entry");
7587cc2493dSspupyrev 
7597cc2493dSspupyrev     // Split every block into two nodes
7607cc2493dSspupyrev     uint64_t Bin = 3 * B;
7617cc2493dSspupyrev     uint64_t Bout = 3 * B + 1;
7627cc2493dSspupyrev     uint64_t Baux = 3 * B + 2;
7637cc2493dSspupyrev     if (Block.Weight > 0) {
7647cc2493dSspupyrev       Network.addEdge(S1, Bout, Block.Weight, 0);
7657cc2493dSspupyrev       Network.addEdge(Bin, T1, Block.Weight, 0);
7667cc2493dSspupyrev     }
7677cc2493dSspupyrev 
7687cc2493dSspupyrev     // Edges from S and to T
7697cc2493dSspupyrev     assert((!Block.isEntry() || !Block.isExit()) &&
7707cc2493dSspupyrev            "a block cannot be an entry and an exit");
7717cc2493dSspupyrev     if (Block.isEntry()) {
7727cc2493dSspupyrev       Network.addEdge(S, Bin, 0);
7737cc2493dSspupyrev     } else if (Block.isExit()) {
7747cc2493dSspupyrev       Network.addEdge(Bout, T, 0);
7757cc2493dSspupyrev     }
7767cc2493dSspupyrev 
7777cc2493dSspupyrev     // An auxiliary node to allow increase/reduction of block counts:
7787cc2493dSspupyrev     // We assume that decreasing block counts is more expensive than increasing,
7797cc2493dSspupyrev     // and thus, setting separate costs here. In the future we may want to tune
7807cc2493dSspupyrev     // the relative costs so as to maximize the quality of generated profiles.
7817cc2493dSspupyrev     int64_t AuxCostInc = MinCostMaxFlow::AuxCostInc;
7827cc2493dSspupyrev     int64_t AuxCostDec = MinCostMaxFlow::AuxCostDec;
7837cc2493dSspupyrev     if (Block.UnknownWeight) {
7847cc2493dSspupyrev       // Do not penalize changing weights of blocks w/o known profile count
7857cc2493dSspupyrev       AuxCostInc = 0;
7867cc2493dSspupyrev       AuxCostDec = 0;
7877cc2493dSspupyrev     } else {
7887cc2493dSspupyrev       // Increasing the count for "cold" blocks with zero initial count is more
7897cc2493dSspupyrev       // expensive than for "hot" ones
7907cc2493dSspupyrev       if (Block.Weight == 0) {
7917cc2493dSspupyrev         AuxCostInc = MinCostMaxFlow::AuxCostIncZero;
7927cc2493dSspupyrev       }
7937cc2493dSspupyrev       // Modifying the count of the entry block is expensive
7947cc2493dSspupyrev       if (Block.isEntry()) {
7957cc2493dSspupyrev         AuxCostInc = MinCostMaxFlow::AuxCostIncEntry;
7967cc2493dSspupyrev         AuxCostDec = MinCostMaxFlow::AuxCostDecEntry;
7977cc2493dSspupyrev       }
7987cc2493dSspupyrev     }
7997cc2493dSspupyrev     // For blocks with self-edges, do not penalize a reduction of the count,
8007cc2493dSspupyrev     // as all of the increase can be attributed to the self-edge
8017cc2493dSspupyrev     if (Block.HasSelfEdge) {
8027cc2493dSspupyrev       AuxCostDec = 0;
8037cc2493dSspupyrev     }
8047cc2493dSspupyrev 
8057cc2493dSspupyrev     Network.addEdge(Bin, Baux, AuxCostInc);
8067cc2493dSspupyrev     Network.addEdge(Baux, Bout, AuxCostInc);
8077cc2493dSspupyrev     if (Block.Weight > 0) {
8087cc2493dSspupyrev       Network.addEdge(Bout, Baux, AuxCostDec);
8097cc2493dSspupyrev       Network.addEdge(Baux, Bin, AuxCostDec);
8107cc2493dSspupyrev     }
8117cc2493dSspupyrev   }
8127cc2493dSspupyrev 
8137cc2493dSspupyrev   // Creating edges for every jump
8147cc2493dSspupyrev   for (auto &Jump : Func.Jumps) {
8157cc2493dSspupyrev     uint64_t Src = Jump.Source;
8167cc2493dSspupyrev     uint64_t Dst = Jump.Target;
8177cc2493dSspupyrev     if (Src != Dst) {
8187cc2493dSspupyrev       uint64_t SrcOut = 3 * Src + 1;
8197cc2493dSspupyrev       uint64_t DstIn = 3 * Dst;
8207cc2493dSspupyrev       uint64_t Cost = Jump.IsUnlikely ? MinCostMaxFlow::AuxCostUnlikely : 0;
8217cc2493dSspupyrev       Network.addEdge(SrcOut, DstIn, Cost);
8227cc2493dSspupyrev     }
8237cc2493dSspupyrev   }
8247cc2493dSspupyrev 
8257cc2493dSspupyrev   // Make sure we have a valid flow circulation
8267cc2493dSspupyrev   Network.addEdge(T, S, 0);
8277cc2493dSspupyrev }
8287cc2493dSspupyrev 
8297cc2493dSspupyrev /// Extract resulting block and edge counts from the flow network.
8307cc2493dSspupyrev void extractWeights(MinCostMaxFlow &Network, FlowFunction &Func) {
8317cc2493dSspupyrev   uint64_t NumBlocks = Func.Blocks.size();
8327cc2493dSspupyrev 
8337cc2493dSspupyrev   // Extract resulting block counts
8347cc2493dSspupyrev   for (uint64_t Src = 0; Src < NumBlocks; Src++) {
8357cc2493dSspupyrev     auto &Block = Func.Blocks[Src];
8367cc2493dSspupyrev     uint64_t SrcOut = 3 * Src + 1;
8377cc2493dSspupyrev     int64_t Flow = 0;
8387cc2493dSspupyrev     for (auto &Adj : Network.getFlow(SrcOut)) {
8397cc2493dSspupyrev       uint64_t DstIn = Adj.first;
8407cc2493dSspupyrev       int64_t DstFlow = Adj.second;
8417cc2493dSspupyrev       bool IsAuxNode = (DstIn < 3 * NumBlocks && DstIn % 3 == 2);
8427cc2493dSspupyrev       if (!IsAuxNode || Block.HasSelfEdge) {
8437cc2493dSspupyrev         Flow += DstFlow;
8447cc2493dSspupyrev       }
8457cc2493dSspupyrev     }
8467cc2493dSspupyrev     Block.Flow = Flow;
8477cc2493dSspupyrev     assert(Flow >= 0 && "negative block flow");
8487cc2493dSspupyrev   }
8497cc2493dSspupyrev 
8507cc2493dSspupyrev   // Extract resulting jump counts
8517cc2493dSspupyrev   for (auto &Jump : Func.Jumps) {
8527cc2493dSspupyrev     uint64_t Src = Jump.Source;
8537cc2493dSspupyrev     uint64_t Dst = Jump.Target;
8547cc2493dSspupyrev     int64_t Flow = 0;
8557cc2493dSspupyrev     if (Src != Dst) {
8567cc2493dSspupyrev       uint64_t SrcOut = 3 * Src + 1;
8577cc2493dSspupyrev       uint64_t DstIn = 3 * Dst;
8587cc2493dSspupyrev       Flow = Network.getFlow(SrcOut, DstIn);
8597cc2493dSspupyrev     } else {
8607cc2493dSspupyrev       uint64_t SrcOut = 3 * Src + 1;
8617cc2493dSspupyrev       uint64_t SrcAux = 3 * Src + 2;
8627cc2493dSspupyrev       int64_t AuxFlow = Network.getFlow(SrcOut, SrcAux);
8637cc2493dSspupyrev       if (AuxFlow > 0)
8647cc2493dSspupyrev         Flow = AuxFlow;
8657cc2493dSspupyrev     }
8667cc2493dSspupyrev     Jump.Flow = Flow;
8677cc2493dSspupyrev     assert(Flow >= 0 && "negative jump flow");
8687cc2493dSspupyrev   }
8697cc2493dSspupyrev }
8707cc2493dSspupyrev 
8717cc2493dSspupyrev #ifndef NDEBUG
8727cc2493dSspupyrev /// Verify that the computed flow values satisfy flow conservation rules
8737cc2493dSspupyrev void verifyWeights(const FlowFunction &Func) {
8747cc2493dSspupyrev   const uint64_t NumBlocks = Func.Blocks.size();
8757cc2493dSspupyrev   auto InFlow = std::vector<uint64_t>(NumBlocks, 0);
8767cc2493dSspupyrev   auto OutFlow = std::vector<uint64_t>(NumBlocks, 0);
8777cc2493dSspupyrev   for (auto &Jump : Func.Jumps) {
8787cc2493dSspupyrev     InFlow[Jump.Target] += Jump.Flow;
8797cc2493dSspupyrev     OutFlow[Jump.Source] += Jump.Flow;
8807cc2493dSspupyrev   }
8817cc2493dSspupyrev 
8827cc2493dSspupyrev   uint64_t TotalInFlow = 0;
8837cc2493dSspupyrev   uint64_t TotalOutFlow = 0;
8847cc2493dSspupyrev   for (uint64_t I = 0; I < NumBlocks; I++) {
8857cc2493dSspupyrev     auto &Block = Func.Blocks[I];
8867cc2493dSspupyrev     if (Block.isEntry()) {
8877cc2493dSspupyrev       TotalInFlow += Block.Flow;
8887cc2493dSspupyrev       assert(Block.Flow == OutFlow[I] && "incorrectly computed control flow");
8897cc2493dSspupyrev     } else if (Block.isExit()) {
8907cc2493dSspupyrev       TotalOutFlow += Block.Flow;
8917cc2493dSspupyrev       assert(Block.Flow == InFlow[I] && "incorrectly computed control flow");
8927cc2493dSspupyrev     } else {
8937cc2493dSspupyrev       assert(Block.Flow == OutFlow[I] && "incorrectly computed control flow");
8947cc2493dSspupyrev       assert(Block.Flow == InFlow[I] && "incorrectly computed control flow");
8957cc2493dSspupyrev     }
8967cc2493dSspupyrev   }
8977cc2493dSspupyrev   assert(TotalInFlow == TotalOutFlow && "incorrectly computed control flow");
89898dd2f9eSspupyrev 
89998dd2f9eSspupyrev   // Verify that there are no isolated flow components
90098dd2f9eSspupyrev   // One could modify FlowFunction to hold edges indexed by the sources, which
90198dd2f9eSspupyrev   // will avoid a creation of the object
90298dd2f9eSspupyrev   auto PositiveFlowEdges = std::vector<std::vector<uint64_t>>(NumBlocks);
90398dd2f9eSspupyrev   for (auto &Jump : Func.Jumps) {
90498dd2f9eSspupyrev     if (Jump.Flow > 0) {
90598dd2f9eSspupyrev       PositiveFlowEdges[Jump.Source].push_back(Jump.Target);
90698dd2f9eSspupyrev     }
90798dd2f9eSspupyrev   }
90898dd2f9eSspupyrev 
90993a2c291Sspupyrev   // Run BFS from the source along edges with positive flow
91098dd2f9eSspupyrev   std::queue<uint64_t> Queue;
9115f4ae564SJan Svoboda   auto Visited = BitVector(NumBlocks, false);
91298dd2f9eSspupyrev   Queue.push(Func.Entry);
91398dd2f9eSspupyrev   Visited[Func.Entry] = true;
91498dd2f9eSspupyrev   while (!Queue.empty()) {
91598dd2f9eSspupyrev     uint64_t Src = Queue.front();
91698dd2f9eSspupyrev     Queue.pop();
91798dd2f9eSspupyrev     for (uint64_t Dst : PositiveFlowEdges[Src]) {
91898dd2f9eSspupyrev       if (!Visited[Dst]) {
91998dd2f9eSspupyrev         Queue.push(Dst);
92098dd2f9eSspupyrev         Visited[Dst] = true;
92198dd2f9eSspupyrev       }
92298dd2f9eSspupyrev     }
92398dd2f9eSspupyrev   }
92498dd2f9eSspupyrev 
92598dd2f9eSspupyrev   // Verify that every block that has a positive flow is reached from the source
92698dd2f9eSspupyrev   // along edges with a positive flow
92798dd2f9eSspupyrev   for (uint64_t I = 0; I < NumBlocks; I++) {
92898dd2f9eSspupyrev     auto &Block = Func.Blocks[I];
92998dd2f9eSspupyrev     assert((Visited[I] || Block.Flow == 0) && "an isolated flow component");
93098dd2f9eSspupyrev   }
9317cc2493dSspupyrev }
9327cc2493dSspupyrev #endif
9337cc2493dSspupyrev 
9347cc2493dSspupyrev } // end of anonymous namespace
9357cc2493dSspupyrev 
9367cc2493dSspupyrev /// Apply the profile inference algorithm for a given flow function
9377cc2493dSspupyrev void llvm::applyFlowInference(FlowFunction &Func) {
9387cc2493dSspupyrev   // Create and apply an inference network model
9397cc2493dSspupyrev   auto InferenceNetwork = MinCostMaxFlow();
9407cc2493dSspupyrev   initializeNetwork(InferenceNetwork, Func);
9417cc2493dSspupyrev   InferenceNetwork.run();
9427cc2493dSspupyrev 
9437cc2493dSspupyrev   // Extract flow values for every block and every edge
9447cc2493dSspupyrev   extractWeights(InferenceNetwork, Func);
9457cc2493dSspupyrev 
94698dd2f9eSspupyrev   // Post-processing adjustments to the flow
94798dd2f9eSspupyrev   auto Adjuster = FlowAdjuster(Func);
94898dd2f9eSspupyrev   Adjuster.run();
94998dd2f9eSspupyrev 
9507cc2493dSspupyrev #ifndef NDEBUG
9517cc2493dSspupyrev   // Verify the result
9527cc2493dSspupyrev   verifyWeights(Func);
9537cc2493dSspupyrev #endif
9547cc2493dSspupyrev }
955