Home | History | Annotate | Line # | Download | only in CodeGen
      1 //===- SpillPlacement.cpp - Optimal Spill Code Placement ------------------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file implements the spill code placement analysis.
     10 //
     11 // Each edge bundle corresponds to a node in a Hopfield network. Constraints on
     12 // basic blocks are weighted by the block frequency and added to become the node
     13 // bias.
     14 //
     15 // Transparent basic blocks have the variable live through, but don't care if it
     16 // is spilled or in a register. These blocks become connections in the Hopfield
     17 // network, again weighted by block frequency.
     18 //
     19 // The Hopfield network minimizes (possibly locally) its energy function:
     20 //
     21 //   E = -sum_n V_n * ( B_n + sum_{n, m linked by b} V_m * F_b )
     22 //
     23 // The energy function represents the expected spill code execution frequency,
     24 // or the cost of spilling. This is a Lyapunov function which never increases
     25 // when a node is updated. It is guaranteed to converge to a local minimum.
     26 //
     27 //===----------------------------------------------------------------------===//
     28 
     29 #include "SpillPlacement.h"
     30 #include "llvm/ADT/BitVector.h"
     31 #include "llvm/CodeGen/EdgeBundles.h"
     32 #include "llvm/CodeGen/MachineBasicBlock.h"
     33 #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
     34 #include "llvm/CodeGen/MachineFunction.h"
     35 #include "llvm/CodeGen/MachineLoopInfo.h"
     36 #include "llvm/CodeGen/Passes.h"
     37 #include "llvm/InitializePasses.h"
     38 #include "llvm/Pass.h"
     39 #include <algorithm>
     40 #include <cassert>
     41 #include <cstdint>
     42 #include <utility>
     43 
     44 using namespace llvm;
     45 
     46 #define DEBUG_TYPE "spill-code-placement"
     47 
     48 char SpillPlacement::ID = 0;
     49 
     50 char &llvm::SpillPlacementID = SpillPlacement::ID;
     51 
     52 INITIALIZE_PASS_BEGIN(SpillPlacement, DEBUG_TYPE,
     53                       "Spill Code Placement Analysis", true, true)
     54 INITIALIZE_PASS_DEPENDENCY(EdgeBundles)
     55 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
     56 INITIALIZE_PASS_END(SpillPlacement, DEBUG_TYPE,
     57                     "Spill Code Placement Analysis", true, true)
     58 
     59 void SpillPlacement::getAnalysisUsage(AnalysisUsage &AU) const {
     60   AU.setPreservesAll();
     61   AU.addRequired<MachineBlockFrequencyInfo>();
     62   AU.addRequiredTransitive<EdgeBundles>();
     63   AU.addRequiredTransitive<MachineLoopInfo>();
     64   MachineFunctionPass::getAnalysisUsage(AU);
     65 }
     66 
     67 /// Node - Each edge bundle corresponds to a Hopfield node.
     68 ///
     69 /// The node contains precomputed frequency data that only depends on the CFG,
     70 /// but Bias and Links are computed each time placeSpills is called.
     71 ///
     72 /// The node Value is positive when the variable should be in a register. The
     73 /// value can change when linked nodes change, but convergence is very fast
     74 /// because all weights are positive.
     75 struct SpillPlacement::Node {
     76   /// BiasN - Sum of blocks that prefer a spill.
     77   BlockFrequency BiasN;
     78 
     79   /// BiasP - Sum of blocks that prefer a register.
     80   BlockFrequency BiasP;
     81 
     82   /// Value - Output value of this node computed from the Bias and links.
     83   /// This is always on of the values {-1, 0, 1}. A positive number means the
     84   /// variable should go in a register through this bundle.
     85   int Value;
     86 
     87   using LinkVector = SmallVector<std::pair<BlockFrequency, unsigned>, 4>;
     88 
     89   /// Links - (Weight, BundleNo) for all transparent blocks connecting to other
     90   /// bundles. The weights are all positive block frequencies.
     91   LinkVector Links;
     92 
     93   /// SumLinkWeights - Cached sum of the weights of all links + ThresHold.
     94   BlockFrequency SumLinkWeights;
     95 
     96   /// preferReg - Return true when this node prefers to be in a register.
     97   bool preferReg() const {
     98     // Undecided nodes (Value==0) go on the stack.
     99     return Value > 0;
    100   }
    101 
    102   /// mustSpill - Return True if this node is so biased that it must spill.
    103   bool mustSpill() const {
    104     // We must spill if Bias < -sum(weights) or the MustSpill flag was set.
    105     // BiasN is saturated when MustSpill is set, make sure this still returns
    106     // true when the RHS saturates. Note that SumLinkWeights includes Threshold.
    107     return BiasN >= BiasP + SumLinkWeights;
    108   }
    109 
    110   /// clear - Reset per-query data, but preserve frequencies that only depend on
    111   /// the CFG.
    112   void clear(const BlockFrequency &Threshold) {
    113     BiasN = BiasP = Value = 0;
    114     SumLinkWeights = Threshold;
    115     Links.clear();
    116   }
    117 
    118   /// addLink - Add a link to bundle b with weight w.
    119   void addLink(unsigned b, BlockFrequency w) {
    120     // Update cached sum.
    121     SumLinkWeights += w;
    122 
    123     // There can be multiple links to the same bundle, add them up.
    124     for (std::pair<BlockFrequency, unsigned> &L : Links)
    125       if (L.second == b) {
    126         L.first += w;
    127         return;
    128       }
    129     // This must be the first link to b.
    130     Links.push_back(std::make_pair(w, b));
    131   }
    132 
    133   /// addBias - Bias this node.
    134   void addBias(BlockFrequency freq, BorderConstraint direction) {
    135     switch (direction) {
    136     default:
    137       break;
    138     case PrefReg:
    139       BiasP += freq;
    140       break;
    141     case PrefSpill:
    142       BiasN += freq;
    143       break;
    144     case MustSpill:
    145       BiasN = BlockFrequency::getMaxFrequency();
    146       break;
    147     }
    148   }
    149 
    150   /// update - Recompute Value from Bias and Links. Return true when node
    151   /// preference changes.
    152   bool update(const Node nodes[], const BlockFrequency &Threshold) {
    153     // Compute the weighted sum of inputs.
    154     BlockFrequency SumN = BiasN;
    155     BlockFrequency SumP = BiasP;
    156     for (std::pair<BlockFrequency, unsigned> &L : Links) {
    157       if (nodes[L.second].Value == -1)
    158         SumN += L.first;
    159       else if (nodes[L.second].Value == 1)
    160         SumP += L.first;
    161     }
    162 
    163     // Each weighted sum is going to be less than the total frequency of the
    164     // bundle. Ideally, we should simply set Value = sign(SumP - SumN), but we
    165     // will add a dead zone around 0 for two reasons:
    166     //
    167     //  1. It avoids arbitrary bias when all links are 0 as is possible during
    168     //     initial iterations.
    169     //  2. It helps tame rounding errors when the links nominally sum to 0.
    170     //
    171     bool Before = preferReg();
    172     if (SumN >= SumP + Threshold)
    173       Value = -1;
    174     else if (SumP >= SumN + Threshold)
    175       Value = 1;
    176     else
    177       Value = 0;
    178     return Before != preferReg();
    179   }
    180 
    181   void getDissentingNeighbors(SparseSet<unsigned> &List,
    182                               const Node nodes[]) const {
    183     for (const auto &Elt : Links) {
    184       unsigned n = Elt.second;
    185       // Neighbors that already have the same value are not going to
    186       // change because of this node changing.
    187       if (Value != nodes[n].Value)
    188         List.insert(n);
    189     }
    190   }
    191 };
    192 
    193 bool SpillPlacement::runOnMachineFunction(MachineFunction &mf) {
    194   MF = &mf;
    195   bundles = &getAnalysis<EdgeBundles>();
    196   loops = &getAnalysis<MachineLoopInfo>();
    197 
    198   assert(!nodes && "Leaking node array");
    199   nodes = new Node[bundles->getNumBundles()];
    200   TodoList.clear();
    201   TodoList.setUniverse(bundles->getNumBundles());
    202 
    203   // Compute total ingoing and outgoing block frequencies for all bundles.
    204   BlockFrequencies.resize(mf.getNumBlockIDs());
    205   MBFI = &getAnalysis<MachineBlockFrequencyInfo>();
    206   setThreshold(MBFI->getEntryFreq());
    207   for (auto &I : mf) {
    208     unsigned Num = I.getNumber();
    209     BlockFrequencies[Num] = MBFI->getBlockFreq(&I);
    210   }
    211 
    212   // We never change the function.
    213   return false;
    214 }
    215 
    216 void SpillPlacement::releaseMemory() {
    217   delete[] nodes;
    218   nodes = nullptr;
    219   TodoList.clear();
    220 }
    221 
    222 /// activate - mark node n as active if it wasn't already.
    223 void SpillPlacement::activate(unsigned n) {
    224   TodoList.insert(n);
    225   if (ActiveNodes->test(n))
    226     return;
    227   ActiveNodes->set(n);
    228   nodes[n].clear(Threshold);
    229 
    230   // Very large bundles usually come from big switches, indirect branches,
    231   // landing pads, or loops with many 'continue' statements. It is difficult to
    232   // allocate registers when so many different blocks are involved.
    233   //
    234   // Give a small negative bias to large bundles such that a substantial
    235   // fraction of the connected blocks need to be interested before we consider
    236   // expanding the region through the bundle. This helps compile time by
    237   // limiting the number of blocks visited and the number of links in the
    238   // Hopfield network.
    239   if (bundles->getBlocks(n).size() > 100) {
    240     nodes[n].BiasP = 0;
    241     nodes[n].BiasN = (MBFI->getEntryFreq() / 16);
    242   }
    243 }
    244 
    245 /// Set the threshold for a given entry frequency.
    246 ///
    247 /// Set the threshold relative to \c Entry.  Since the threshold is used as a
    248 /// bound on the open interval (-Threshold;Threshold), 1 is the minimum
    249 /// threshold.
    250 void SpillPlacement::setThreshold(const BlockFrequency &Entry) {
    251   // Apparently 2 is a good threshold when Entry==2^14, but we need to scale
    252   // it.  Divide by 2^13, rounding as appropriate.
    253   uint64_t Freq = Entry.getFrequency();
    254   uint64_t Scaled = (Freq >> 13) + bool(Freq & (1 << 12));
    255   Threshold = std::max(UINT64_C(1), Scaled);
    256 }
    257 
    258 /// addConstraints - Compute node biases and weights from a set of constraints.
    259 /// Set a bit in NodeMask for each active node.
    260 void SpillPlacement::addConstraints(ArrayRef<BlockConstraint> LiveBlocks) {
    261   for (const BlockConstraint &LB : LiveBlocks) {
    262     BlockFrequency Freq = BlockFrequencies[LB.Number];
    263 
    264     // Live-in to block?
    265     if (LB.Entry != DontCare) {
    266       unsigned ib = bundles->getBundle(LB.Number, false);
    267       activate(ib);
    268       nodes[ib].addBias(Freq, LB.Entry);
    269     }
    270 
    271     // Live-out from block?
    272     if (LB.Exit != DontCare) {
    273       unsigned ob = bundles->getBundle(LB.Number, true);
    274       activate(ob);
    275       nodes[ob].addBias(Freq, LB.Exit);
    276     }
    277   }
    278 }
    279 
    280 /// addPrefSpill - Same as addConstraints(PrefSpill)
    281 void SpillPlacement::addPrefSpill(ArrayRef<unsigned> Blocks, bool Strong) {
    282   for (unsigned B : Blocks) {
    283     BlockFrequency Freq = BlockFrequencies[B];
    284     if (Strong)
    285       Freq += Freq;
    286     unsigned ib = bundles->getBundle(B, false);
    287     unsigned ob = bundles->getBundle(B, true);
    288     activate(ib);
    289     activate(ob);
    290     nodes[ib].addBias(Freq, PrefSpill);
    291     nodes[ob].addBias(Freq, PrefSpill);
    292   }
    293 }
    294 
    295 void SpillPlacement::addLinks(ArrayRef<unsigned> Links) {
    296   for (unsigned Number : Links) {
    297     unsigned ib = bundles->getBundle(Number, false);
    298     unsigned ob = bundles->getBundle(Number, true);
    299 
    300     // Ignore self-loops.
    301     if (ib == ob)
    302       continue;
    303     activate(ib);
    304     activate(ob);
    305     BlockFrequency Freq = BlockFrequencies[Number];
    306     nodes[ib].addLink(ob, Freq);
    307     nodes[ob].addLink(ib, Freq);
    308   }
    309 }
    310 
    311 bool SpillPlacement::scanActiveBundles() {
    312   RecentPositive.clear();
    313   for (unsigned n : ActiveNodes->set_bits()) {
    314     update(n);
    315     // A node that must spill, or a node without any links is not going to
    316     // change its value ever again, so exclude it from iterations.
    317     if (nodes[n].mustSpill())
    318       continue;
    319     if (nodes[n].preferReg())
    320       RecentPositive.push_back(n);
    321   }
    322   return !RecentPositive.empty();
    323 }
    324 
    325 bool SpillPlacement::update(unsigned n) {
    326   if (!nodes[n].update(nodes, Threshold))
    327     return false;
    328   nodes[n].getDissentingNeighbors(TodoList, nodes);
    329   return true;
    330 }
    331 
    332 /// iterate - Repeatedly update the Hopfield nodes until stability or the
    333 /// maximum number of iterations is reached.
    334 void SpillPlacement::iterate() {
    335   // We do not need to push those node in the todolist.
    336   // They are already been proceeded as part of the previous iteration.
    337   RecentPositive.clear();
    338 
    339   // Since the last iteration, the todolist have been augmented by calls
    340   // to addConstraints, addLinks, and co.
    341   // Update the network energy starting at this new frontier.
    342   // The call to ::update will add the nodes that changed into the todolist.
    343   unsigned Limit = bundles->getNumBundles() * 10;
    344   while(Limit-- > 0 && !TodoList.empty()) {
    345     unsigned n = TodoList.pop_back_val();
    346     if (!update(n))
    347       continue;
    348     if (nodes[n].preferReg())
    349       RecentPositive.push_back(n);
    350   }
    351 }
    352 
    353 void SpillPlacement::prepare(BitVector &RegBundles) {
    354   RecentPositive.clear();
    355   TodoList.clear();
    356   // Reuse RegBundles as our ActiveNodes vector.
    357   ActiveNodes = &RegBundles;
    358   ActiveNodes->clear();
    359   ActiveNodes->resize(bundles->getNumBundles());
    360 }
    361 
    362 bool
    363 SpillPlacement::finish() {
    364   assert(ActiveNodes && "Call prepare() first");
    365 
    366   // Write preferences back to ActiveNodes.
    367   bool Perfect = true;
    368   for (unsigned n : ActiveNodes->set_bits())
    369     if (!nodes[n].preferReg()) {
    370       ActiveNodes->reset(n);
    371       Perfect = false;
    372     }
    373   ActiveNodes = nullptr;
    374   return Perfect;
    375 }
    376 
    377 void SpillPlacement::BlockConstraint::print(raw_ostream &OS) const {
    378   auto toString = [](BorderConstraint C) -> StringRef {
    379     switch(C) {
    380     case DontCare: return "DontCare";
    381     case PrefReg: return "PrefReg";
    382     case PrefSpill: return "PrefSpill";
    383     case PrefBoth: return "PrefBoth";
    384     case MustSpill: return "MustSpill";
    385     };
    386     llvm_unreachable("uncovered switch");
    387   };
    388 
    389   dbgs() << "{" << Number << ", "
    390          << toString(Entry) << ", "
    391          << toString(Exit) << ", "
    392          << (ChangesValue ? "changes" : "no change") << "}";
    393 }
    394 
    395 void SpillPlacement::BlockConstraint::dump() const {
    396   print(dbgs());
    397   dbgs() << "\n";
    398 }
    399