11462faadSDan Gohman //===-- WebAssemblyRegColoring.cpp - Register coloring --------------------===//
21462faadSDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61462faadSDan Gohman //
71462faadSDan Gohman //===----------------------------------------------------------------------===//
81462faadSDan Gohman ///
91462faadSDan Gohman /// \file
105f8f34e4SAdrian Prantl /// This file implements a virtual register coloring pass.
111462faadSDan Gohman ///
121462faadSDan Gohman /// WebAssembly doesn't have a fixed number of registers, but it is still
131462faadSDan Gohman /// desirable to minimize the total number of registers used in each function.
141462faadSDan Gohman ///
151462faadSDan Gohman /// This code is modeled after lib/CodeGen/StackSlotColoring.cpp.
161462faadSDan Gohman ///
171462faadSDan Gohman //===----------------------------------------------------------------------===//
181462faadSDan Gohman 
191462faadSDan Gohman #include "WebAssembly.h"
201462faadSDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
21f842297dSMatthias Braun #include "llvm/CodeGen/LiveIntervals.h"
221462faadSDan Gohman #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
231462faadSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
241462faadSDan Gohman #include "llvm/CodeGen/Passes.h"
251462faadSDan Gohman #include "llvm/Support/Debug.h"
261462faadSDan Gohman #include "llvm/Support/raw_ostream.h"
271462faadSDan Gohman using namespace llvm;
281462faadSDan Gohman 
291462faadSDan Gohman #define DEBUG_TYPE "wasm-reg-coloring"
301462faadSDan Gohman 
311462faadSDan Gohman namespace {
321462faadSDan Gohman class WebAssemblyRegColoring final : public MachineFunctionPass {
331462faadSDan Gohman public:
341462faadSDan Gohman   static char ID; // Pass identification, replacement for typeid
WebAssemblyRegColoring()351462faadSDan Gohman   WebAssemblyRegColoring() : MachineFunctionPass(ID) {}
361462faadSDan Gohman 
getPassName() const37117296c0SMehdi Amini   StringRef getPassName() const override {
381462faadSDan Gohman     return "WebAssembly Register Coloring";
391462faadSDan Gohman   }
401462faadSDan Gohman 
getAnalysisUsage(AnalysisUsage & AU) const411462faadSDan Gohman   void getAnalysisUsage(AnalysisUsage &AU) const override {
421462faadSDan Gohman     AU.setPreservesCFG();
431462faadSDan Gohman     AU.addRequired<LiveIntervals>();
441462faadSDan Gohman     AU.addRequired<MachineBlockFrequencyInfo>();
451462faadSDan Gohman     AU.addPreserved<MachineBlockFrequencyInfo>();
461462faadSDan Gohman     AU.addPreservedID(MachineDominatorsID);
471462faadSDan Gohman     MachineFunctionPass::getAnalysisUsage(AU);
481462faadSDan Gohman   }
491462faadSDan Gohman 
501462faadSDan Gohman   bool runOnMachineFunction(MachineFunction &MF) override;
511462faadSDan Gohman 
521462faadSDan Gohman private:
531462faadSDan Gohman };
541462faadSDan Gohman } // end anonymous namespace
551462faadSDan Gohman 
561462faadSDan Gohman char WebAssemblyRegColoring::ID = 0;
5740926451SJacob Gravelle INITIALIZE_PASS(WebAssemblyRegColoring, DEBUG_TYPE,
5840926451SJacob Gravelle                 "Minimize number of registers used", false, false)
5940926451SJacob Gravelle 
createWebAssemblyRegColoring()601462faadSDan Gohman FunctionPass *llvm::createWebAssemblyRegColoring() {
611462faadSDan Gohman   return new WebAssemblyRegColoring();
621462faadSDan Gohman }
631462faadSDan Gohman 
641462faadSDan Gohman // Compute the total spill weight for VReg.
computeWeight(const MachineRegisterInfo * MRI,const MachineBlockFrequencyInfo * MBFI,unsigned VReg)651462faadSDan Gohman static float computeWeight(const MachineRegisterInfo *MRI,
661462faadSDan Gohman                            const MachineBlockFrequencyInfo *MBFI,
671462faadSDan Gohman                            unsigned VReg) {
6818c56a07SHeejin Ahn   float Weight = 0.0f;
691462faadSDan Gohman   for (MachineOperand &MO : MRI->reg_nodbg_operands(VReg))
7018c56a07SHeejin Ahn     Weight += LiveIntervals::getSpillWeight(MO.isDef(), MO.isUse(), MBFI,
711afd1e2bSJF Bastien                                             *MO.getParent());
7218c56a07SHeejin Ahn   return Weight;
731462faadSDan Gohman }
741462faadSDan Gohman 
runOnMachineFunction(MachineFunction & MF)751462faadSDan Gohman bool WebAssemblyRegColoring::runOnMachineFunction(MachineFunction &MF) {
76d34e60caSNicola Zaghen   LLVM_DEBUG({
771462faadSDan Gohman     dbgs() << "********** Register Coloring **********\n"
781462faadSDan Gohman            << "********** Function: " << MF.getName() << '\n';
791462faadSDan Gohman   });
801462faadSDan Gohman 
811462faadSDan Gohman   // If there are calls to setjmp or sigsetjmp, don't perform coloring. Virtual
821462faadSDan Gohman   // registers could be modified before the longjmp is executed, resulting in
831462faadSDan Gohman   // the wrong value being used afterwards. (See <rdar://problem/8007500>.)
841462faadSDan Gohman   // TODO: Does WebAssembly need to care about setjmp for register coloring?
851462faadSDan Gohman   if (MF.exposesReturnsTwice())
861462faadSDan Gohman     return false;
871462faadSDan Gohman 
881462faadSDan Gohman   MachineRegisterInfo *MRI = &MF.getRegInfo();
891462faadSDan Gohman   LiveIntervals *Liveness = &getAnalysis<LiveIntervals>();
901462faadSDan Gohman   const MachineBlockFrequencyInfo *MBFI =
911462faadSDan Gohman       &getAnalysis<MachineBlockFrequencyInfo>();
921462faadSDan Gohman   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
931462faadSDan Gohman 
941462faadSDan Gohman   // Gather all register intervals into a list and sort them.
951462faadSDan Gohman   unsigned NumVRegs = MRI->getNumVirtRegs();
961462faadSDan Gohman   SmallVector<LiveInterval *, 0> SortedIntervals;
971462faadSDan Gohman   SortedIntervals.reserve(NumVRegs);
981462faadSDan Gohman 
99d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Interesting register intervals:\n");
10018c56a07SHeejin Ahn   for (unsigned I = 0; I < NumVRegs; ++I) {
101*d6b07348SJim Lin     Register VReg = Register::index2VirtReg(I);
1021462faadSDan Gohman     if (MFI.isVRegStackified(VReg))
1031462faadSDan Gohman       continue;
10471008090SDan Gohman     // Skip unused registers, which can use $drop.
1057054ac1bSDan Gohman     if (MRI->use_empty(VReg))
1067054ac1bSDan Gohman       continue;
1071462faadSDan Gohman 
1081462faadSDan Gohman     LiveInterval *LI = &Liveness->getInterval(VReg);
1096e85c3d5SMircea Trofin     assert(LI->weight() == 0.0f);
1106e85c3d5SMircea Trofin     LI->setWeight(computeWeight(MRI, MBFI, VReg));
111d34e60caSNicola Zaghen     LLVM_DEBUG(LI->dump());
1121462faadSDan Gohman     SortedIntervals.push_back(LI);
1131462faadSDan Gohman   }
114d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << '\n');
1151462faadSDan Gohman 
1161462faadSDan Gohman   // Sort them to put arguments first (since we don't want to rename live-in
1171462faadSDan Gohman   // registers), by weight next, and then by position.
1181462faadSDan Gohman   // TODO: Investigate more intelligent sorting heuristics. For starters, we
1191462faadSDan Gohman   // should try to coalesce adjacent live intervals before non-adjacent ones.
1200cac726aSFangrui Song   llvm::sort(SortedIntervals, [MRI](LiveInterval *LHS, LiveInterval *RHS) {
1216e85c3d5SMircea Trofin     if (MRI->isLiveIn(LHS->reg()) != MRI->isLiveIn(RHS->reg()))
1226e85c3d5SMircea Trofin       return MRI->isLiveIn(LHS->reg());
1236e85c3d5SMircea Trofin     if (LHS->weight() != RHS->weight())
1246e85c3d5SMircea Trofin       return LHS->weight() > RHS->weight();
1251462faadSDan Gohman     if (LHS->empty() || RHS->empty())
1261462faadSDan Gohman       return !LHS->empty() && RHS->empty();
1271462faadSDan Gohman     return *LHS < *RHS;
1281462faadSDan Gohman   });
1291462faadSDan Gohman 
130d34e60caSNicola Zaghen   LLVM_DEBUG(dbgs() << "Coloring register intervals:\n");
1311462faadSDan Gohman   SmallVector<unsigned, 16> SlotMapping(SortedIntervals.size(), -1u);
1321462faadSDan Gohman   SmallVector<SmallVector<LiveInterval *, 4>, 16> Assignments(
1331462faadSDan Gohman       SortedIntervals.size());
1341462faadSDan Gohman   BitVector UsedColors(SortedIntervals.size());
1351462faadSDan Gohman   bool Changed = false;
13618c56a07SHeejin Ahn   for (size_t I = 0, E = SortedIntervals.size(); I < E; ++I) {
13718c56a07SHeejin Ahn     LiveInterval *LI = SortedIntervals[I];
138*d6b07348SJim Lin     Register Old = LI->reg();
13918c56a07SHeejin Ahn     size_t Color = I;
1401462faadSDan Gohman     const TargetRegisterClass *RC = MRI->getRegClass(Old);
1411462faadSDan Gohman 
1421462faadSDan Gohman     // Check if it's possible to reuse any of the used colors.
1431462faadSDan Gohman     if (!MRI->isLiveIn(Old))
144b52e0366SFrancis Visoiu Mistrih       for (unsigned C : UsedColors.set_bits()) {
1456e85c3d5SMircea Trofin         if (MRI->getRegClass(SortedIntervals[C]->reg()) != RC)
1461462faadSDan Gohman           continue;
1471462faadSDan Gohman         for (LiveInterval *OtherLI : Assignments[C])
1481462faadSDan Gohman           if (!OtherLI->empty() && OtherLI->overlaps(*LI))
1491462faadSDan Gohman             goto continue_outer;
1501462faadSDan Gohman         Color = C;
1511462faadSDan Gohman         break;
1521462faadSDan Gohman       continue_outer:;
1531462faadSDan Gohman       }
1541462faadSDan Gohman 
155*d6b07348SJim Lin     Register New = SortedIntervals[Color]->reg();
15618c56a07SHeejin Ahn     SlotMapping[I] = New;
1571462faadSDan Gohman     Changed |= Old != New;
1581462faadSDan Gohman     UsedColors.set(Color);
1591462faadSDan Gohman     Assignments[Color].push_back(LI);
160d966bf83SDerek Schuff     // If we reassigned the stack pointer, update the debug frame base info.
161d966bf83SDerek Schuff     if (Old != New && MFI.isFrameBaseVirtual() && MFI.getFrameBaseVreg() == Old)
162d966bf83SDerek Schuff       MFI.setFrameBaseVreg(New);
1636e85c3d5SMircea Trofin     LLVM_DEBUG(dbgs() << "Assigning vreg" << Register::virtReg2Index(LI->reg())
1642bea69bfSDaniel Sanders                       << " to vreg" << Register::virtReg2Index(New) << "\n");
1651462faadSDan Gohman   }
1661462faadSDan Gohman   if (!Changed)
1671462faadSDan Gohman     return false;
1681462faadSDan Gohman 
1691462faadSDan Gohman   // Rewrite register operands.
17018c56a07SHeejin Ahn   for (size_t I = 0, E = SortedIntervals.size(); I < E; ++I) {
171*d6b07348SJim Lin     Register Old = SortedIntervals[I]->reg();
17218c56a07SHeejin Ahn     unsigned New = SlotMapping[I];
1731462faadSDan Gohman     if (Old != New)
1741462faadSDan Gohman       MRI->replaceRegWith(Old, New);
1751462faadSDan Gohman   }
1761462faadSDan Gohman   return true;
1771462faadSDan Gohman }
178