1*4fc4e42dSDan Gohman //===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===// 2*4fc4e42dSDan Gohman // 3*4fc4e42dSDan Gohman // The LLVM Compiler Infrastructure 4*4fc4e42dSDan Gohman // 5*4fc4e42dSDan Gohman // This file is distributed under the University of Illinois Open Source 6*4fc4e42dSDan Gohman // License. See LICENSE.TXT for details. 7*4fc4e42dSDan Gohman // 8*4fc4e42dSDan Gohman //===----------------------------------------------------------------------===// 9*4fc4e42dSDan Gohman /// 10*4fc4e42dSDan Gohman /// \file 11*4fc4e42dSDan Gohman /// \brief This file converts any remaining registers into WebAssembly locals. 12*4fc4e42dSDan Gohman /// 13*4fc4e42dSDan Gohman /// After register stackification and register coloring, convert non-stackified 14*4fc4e42dSDan Gohman /// registers into locals, inserting explicit get_local and set_local 15*4fc4e42dSDan Gohman /// instructions. 16*4fc4e42dSDan Gohman /// 17*4fc4e42dSDan Gohman //===----------------------------------------------------------------------===// 18*4fc4e42dSDan Gohman 19*4fc4e42dSDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 20*4fc4e42dSDan Gohman #include "WebAssembly.h" 21*4fc4e42dSDan Gohman #include "WebAssemblyMachineFunctionInfo.h" 22*4fc4e42dSDan Gohman #include "WebAssemblySubtarget.h" 23*4fc4e42dSDan Gohman #include "WebAssemblyUtilities.h" 24*4fc4e42dSDan Gohman #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 25*4fc4e42dSDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h" 26*4fc4e42dSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h" 27*4fc4e42dSDan Gohman #include "llvm/CodeGen/Passes.h" 28*4fc4e42dSDan Gohman #include "llvm/Support/Debug.h" 29*4fc4e42dSDan Gohman #include "llvm/Support/raw_ostream.h" 30*4fc4e42dSDan Gohman using namespace llvm; 31*4fc4e42dSDan Gohman 32*4fc4e42dSDan Gohman #define DEBUG_TYPE "wasm-explicit-locals" 33*4fc4e42dSDan Gohman 34*4fc4e42dSDan Gohman namespace { 35*4fc4e42dSDan Gohman class WebAssemblyExplicitLocals final : public MachineFunctionPass { 36*4fc4e42dSDan Gohman StringRef getPassName() const override { 37*4fc4e42dSDan Gohman return "WebAssembly Explicit Locals"; 38*4fc4e42dSDan Gohman } 39*4fc4e42dSDan Gohman 40*4fc4e42dSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override { 41*4fc4e42dSDan Gohman AU.setPreservesCFG(); 42*4fc4e42dSDan Gohman AU.addPreserved<MachineBlockFrequencyInfo>(); 43*4fc4e42dSDan Gohman MachineFunctionPass::getAnalysisUsage(AU); 44*4fc4e42dSDan Gohman } 45*4fc4e42dSDan Gohman 46*4fc4e42dSDan Gohman bool runOnMachineFunction(MachineFunction &MF) override; 47*4fc4e42dSDan Gohman 48*4fc4e42dSDan Gohman public: 49*4fc4e42dSDan Gohman static char ID; // Pass identification, replacement for typeid 50*4fc4e42dSDan Gohman WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {} 51*4fc4e42dSDan Gohman }; 52*4fc4e42dSDan Gohman } // end anonymous namespace 53*4fc4e42dSDan Gohman 54*4fc4e42dSDan Gohman char WebAssemblyExplicitLocals::ID = 0; 55*4fc4e42dSDan Gohman FunctionPass *llvm::createWebAssemblyExplicitLocals() { 56*4fc4e42dSDan Gohman return new WebAssemblyExplicitLocals(); 57*4fc4e42dSDan Gohman } 58*4fc4e42dSDan Gohman 59*4fc4e42dSDan Gohman /// Return a local id number for the given register, assigning it a new one 60*4fc4e42dSDan Gohman /// if it doesn't yet have one. 61*4fc4e42dSDan Gohman static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local, 62*4fc4e42dSDan Gohman unsigned &CurLocal, unsigned Reg) { 63*4fc4e42dSDan Gohman return Reg2Local.insert(std::make_pair(Reg, CurLocal++)).first->second; 64*4fc4e42dSDan Gohman } 65*4fc4e42dSDan Gohman 66*4fc4e42dSDan Gohman /// Get the appropriate get_local opcode for the given register class. 67*4fc4e42dSDan Gohman static unsigned getGetLocalOpcode(const TargetRegisterClass *RC) { 68*4fc4e42dSDan Gohman if (RC == &WebAssembly::I32RegClass) 69*4fc4e42dSDan Gohman return WebAssembly::GET_LOCAL_I32; 70*4fc4e42dSDan Gohman if (RC == &WebAssembly::I64RegClass) 71*4fc4e42dSDan Gohman return WebAssembly::GET_LOCAL_I64; 72*4fc4e42dSDan Gohman if (RC == &WebAssembly::F32RegClass) 73*4fc4e42dSDan Gohman return WebAssembly::GET_LOCAL_F32; 74*4fc4e42dSDan Gohman if (RC == &WebAssembly::F64RegClass) 75*4fc4e42dSDan Gohman return WebAssembly::GET_LOCAL_F64; 76*4fc4e42dSDan Gohman if (RC == &WebAssembly::V128RegClass) 77*4fc4e42dSDan Gohman return WebAssembly::GET_LOCAL_V128; 78*4fc4e42dSDan Gohman llvm_unreachable("Unexpected register class"); 79*4fc4e42dSDan Gohman } 80*4fc4e42dSDan Gohman 81*4fc4e42dSDan Gohman /// Get the appropriate set_local opcode for the given register class. 82*4fc4e42dSDan Gohman static unsigned getSetLocalOpcode(const TargetRegisterClass *RC) { 83*4fc4e42dSDan Gohman if (RC == &WebAssembly::I32RegClass) 84*4fc4e42dSDan Gohman return WebAssembly::SET_LOCAL_I32; 85*4fc4e42dSDan Gohman if (RC == &WebAssembly::I64RegClass) 86*4fc4e42dSDan Gohman return WebAssembly::SET_LOCAL_I64; 87*4fc4e42dSDan Gohman if (RC == &WebAssembly::F32RegClass) 88*4fc4e42dSDan Gohman return WebAssembly::SET_LOCAL_F32; 89*4fc4e42dSDan Gohman if (RC == &WebAssembly::F64RegClass) 90*4fc4e42dSDan Gohman return WebAssembly::SET_LOCAL_F64; 91*4fc4e42dSDan Gohman if (RC == &WebAssembly::V128RegClass) 92*4fc4e42dSDan Gohman return WebAssembly::SET_LOCAL_V128; 93*4fc4e42dSDan Gohman llvm_unreachable("Unexpected register class"); 94*4fc4e42dSDan Gohman } 95*4fc4e42dSDan Gohman 96*4fc4e42dSDan Gohman /// Get the appropriate tee_local opcode for the given register class. 97*4fc4e42dSDan Gohman static unsigned getTeeLocalOpcode(const TargetRegisterClass *RC) { 98*4fc4e42dSDan Gohman if (RC == &WebAssembly::I32RegClass) 99*4fc4e42dSDan Gohman return WebAssembly::TEE_LOCAL_I32; 100*4fc4e42dSDan Gohman if (RC == &WebAssembly::I64RegClass) 101*4fc4e42dSDan Gohman return WebAssembly::TEE_LOCAL_I64; 102*4fc4e42dSDan Gohman if (RC == &WebAssembly::F32RegClass) 103*4fc4e42dSDan Gohman return WebAssembly::TEE_LOCAL_F32; 104*4fc4e42dSDan Gohman if (RC == &WebAssembly::F64RegClass) 105*4fc4e42dSDan Gohman return WebAssembly::TEE_LOCAL_F64; 106*4fc4e42dSDan Gohman if (RC == &WebAssembly::V128RegClass) 107*4fc4e42dSDan Gohman return WebAssembly::TEE_LOCAL_V128; 108*4fc4e42dSDan Gohman llvm_unreachable("Unexpected register class"); 109*4fc4e42dSDan Gohman } 110*4fc4e42dSDan Gohman 111*4fc4e42dSDan Gohman /// Get the type associated with the given register class. 112*4fc4e42dSDan Gohman static WebAssembly::ValType typeForRegClass(const TargetRegisterClass *RC) { 113*4fc4e42dSDan Gohman if (RC == &WebAssembly::I32RegClass) 114*4fc4e42dSDan Gohman return WebAssembly::ValType::I32; 115*4fc4e42dSDan Gohman if (RC == &WebAssembly::I64RegClass) 116*4fc4e42dSDan Gohman return WebAssembly::ValType::I64; 117*4fc4e42dSDan Gohman if (RC == &WebAssembly::F32RegClass) 118*4fc4e42dSDan Gohman return WebAssembly::ValType::F32; 119*4fc4e42dSDan Gohman if (RC == &WebAssembly::F64RegClass) 120*4fc4e42dSDan Gohman return WebAssembly::ValType::F64; 121*4fc4e42dSDan Gohman llvm_unreachable("unrecognized register class"); 122*4fc4e42dSDan Gohman } 123*4fc4e42dSDan Gohman 124*4fc4e42dSDan Gohman /// Given a MachineOperand of a stackified vreg, return the instruction at the 125*4fc4e42dSDan Gohman /// start of the expression tree. 126*4fc4e42dSDan Gohman static MachineInstr *FindStartOfTree(MachineOperand &MO, 127*4fc4e42dSDan Gohman MachineRegisterInfo &MRI, 128*4fc4e42dSDan Gohman WebAssemblyFunctionInfo &MFI) { 129*4fc4e42dSDan Gohman unsigned Reg = MO.getReg(); 130*4fc4e42dSDan Gohman assert(MFI.isVRegStackified(Reg)); 131*4fc4e42dSDan Gohman MachineInstr *Def = MRI.getVRegDef(Reg); 132*4fc4e42dSDan Gohman 133*4fc4e42dSDan Gohman // Find the first stackified use and proceed from there. 134*4fc4e42dSDan Gohman for (MachineOperand &DefMO : Def->explicit_uses()) { 135*4fc4e42dSDan Gohman if (!DefMO.isReg()) 136*4fc4e42dSDan Gohman continue; 137*4fc4e42dSDan Gohman return FindStartOfTree(DefMO, MRI, MFI); 138*4fc4e42dSDan Gohman } 139*4fc4e42dSDan Gohman 140*4fc4e42dSDan Gohman // If there were no stackified uses, we've reached the start. 141*4fc4e42dSDan Gohman return Def; 142*4fc4e42dSDan Gohman } 143*4fc4e42dSDan Gohman 144*4fc4e42dSDan Gohman bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) { 145*4fc4e42dSDan Gohman DEBUG(dbgs() << "********** Make Locals Explicit **********\n" 146*4fc4e42dSDan Gohman "********** Function: " 147*4fc4e42dSDan Gohman << MF.getName() << '\n'); 148*4fc4e42dSDan Gohman 149*4fc4e42dSDan Gohman bool Changed = false; 150*4fc4e42dSDan Gohman MachineRegisterInfo &MRI = MF.getRegInfo(); 151*4fc4e42dSDan Gohman WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 152*4fc4e42dSDan Gohman const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 153*4fc4e42dSDan Gohman 154*4fc4e42dSDan Gohman // Map non-stackified virtual registers to their local ids. 155*4fc4e42dSDan Gohman DenseMap<unsigned, unsigned> Reg2Local; 156*4fc4e42dSDan Gohman 157*4fc4e42dSDan Gohman // Handle ARGUMENTS first to ensure that they get the designated numbers. 158*4fc4e42dSDan Gohman for (MachineBasicBlock::iterator I = MF.begin()->begin(), 159*4fc4e42dSDan Gohman E = MF.begin()->end(); 160*4fc4e42dSDan Gohman I != E;) { 161*4fc4e42dSDan Gohman MachineInstr &MI = *I++; 162*4fc4e42dSDan Gohman if (!WebAssembly::isArgument(MI)) 163*4fc4e42dSDan Gohman break; 164*4fc4e42dSDan Gohman unsigned Reg = MI.getOperand(0).getReg(); 165*4fc4e42dSDan Gohman assert(!MFI.isVRegStackified(Reg)); 166*4fc4e42dSDan Gohman Reg2Local[Reg] = MI.getOperand(1).getImm(); 167*4fc4e42dSDan Gohman MI.eraseFromParent(); 168*4fc4e42dSDan Gohman Changed = true; 169*4fc4e42dSDan Gohman } 170*4fc4e42dSDan Gohman 171*4fc4e42dSDan Gohman // Start assigning local numbers after the last parameter. 172*4fc4e42dSDan Gohman unsigned CurLocal = MFI.getParams().size(); 173*4fc4e42dSDan Gohman 174*4fc4e42dSDan Gohman // Visit each instruction in the function. 175*4fc4e42dSDan Gohman for (MachineBasicBlock &MBB : MF) { 176*4fc4e42dSDan Gohman for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) { 177*4fc4e42dSDan Gohman MachineInstr &MI = *I++; 178*4fc4e42dSDan Gohman assert(!WebAssembly::isArgument(MI)); 179*4fc4e42dSDan Gohman 180*4fc4e42dSDan Gohman if (MI.isDebugValue() || MI.isLabel()) 181*4fc4e42dSDan Gohman continue; 182*4fc4e42dSDan Gohman 183*4fc4e42dSDan Gohman // Replace tee instructions with tee_local. The difference is that tee 184*4fc4e42dSDan Gohman // instructins have two defs, while tee_local instructions have one def 185*4fc4e42dSDan Gohman // and an index of a local to write to. 186*4fc4e42dSDan Gohman if (WebAssembly::isTee(MI)) { 187*4fc4e42dSDan Gohman assert(MFI.isVRegStackified(MI.getOperand(0).getReg())); 188*4fc4e42dSDan Gohman assert(!MFI.isVRegStackified(MI.getOperand(1).getReg())); 189*4fc4e42dSDan Gohman unsigned OldReg = MI.getOperand(2).getReg(); 190*4fc4e42dSDan Gohman const TargetRegisterClass *RC = MRI.getRegClass(OldReg); 191*4fc4e42dSDan Gohman 192*4fc4e42dSDan Gohman // Stackify the input if it isn't stackified yet. 193*4fc4e42dSDan Gohman if (!MFI.isVRegStackified(OldReg)) { 194*4fc4e42dSDan Gohman unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); 195*4fc4e42dSDan Gohman unsigned NewReg = MRI.createVirtualRegister(RC); 196*4fc4e42dSDan Gohman unsigned Opc = getGetLocalOpcode(RC); 197*4fc4e42dSDan Gohman BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg) 198*4fc4e42dSDan Gohman .addImm(LocalId); 199*4fc4e42dSDan Gohman MI.getOperand(2).setReg(NewReg); 200*4fc4e42dSDan Gohman MFI.stackifyVReg(NewReg); 201*4fc4e42dSDan Gohman } 202*4fc4e42dSDan Gohman 203*4fc4e42dSDan Gohman // Replace the TEE with a TEE_LOCAL. 204*4fc4e42dSDan Gohman unsigned LocalId = 205*4fc4e42dSDan Gohman getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg()); 206*4fc4e42dSDan Gohman unsigned Opc = getTeeLocalOpcode(RC); 207*4fc4e42dSDan Gohman BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), 208*4fc4e42dSDan Gohman MI.getOperand(0).getReg()) 209*4fc4e42dSDan Gohman .addImm(LocalId) 210*4fc4e42dSDan Gohman .addReg(MI.getOperand(2).getReg()); 211*4fc4e42dSDan Gohman 212*4fc4e42dSDan Gohman MI.eraseFromParent(); 213*4fc4e42dSDan Gohman Changed = true; 214*4fc4e42dSDan Gohman continue; 215*4fc4e42dSDan Gohman } 216*4fc4e42dSDan Gohman 217*4fc4e42dSDan Gohman // Insert set_locals for any defs that aren't stackified yet. Currently 218*4fc4e42dSDan Gohman // we handle at most one def. 219*4fc4e42dSDan Gohman assert(MI.getDesc().getNumDefs() <= 1); 220*4fc4e42dSDan Gohman if (MI.getDesc().getNumDefs() == 1) { 221*4fc4e42dSDan Gohman unsigned OldReg = MI.getOperand(0).getReg(); 222*4fc4e42dSDan Gohman if (!MFI.isVRegStackified(OldReg) && !MRI.use_empty(OldReg)) { 223*4fc4e42dSDan Gohman unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); 224*4fc4e42dSDan Gohman const TargetRegisterClass *RC = MRI.getRegClass(OldReg); 225*4fc4e42dSDan Gohman unsigned NewReg = MRI.createVirtualRegister(RC); 226*4fc4e42dSDan Gohman auto InsertPt = std::next(MachineBasicBlock::iterator(&MI)); 227*4fc4e42dSDan Gohman unsigned Opc = getSetLocalOpcode(RC); 228*4fc4e42dSDan Gohman BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc)) 229*4fc4e42dSDan Gohman .addImm(LocalId) 230*4fc4e42dSDan Gohman .addReg(NewReg); 231*4fc4e42dSDan Gohman MI.getOperand(0).setReg(NewReg); 232*4fc4e42dSDan Gohman MFI.stackifyVReg(NewReg); 233*4fc4e42dSDan Gohman Changed = true; 234*4fc4e42dSDan Gohman } 235*4fc4e42dSDan Gohman } 236*4fc4e42dSDan Gohman 237*4fc4e42dSDan Gohman // Insert get_locals for any uses that aren't stackified yet. 238*4fc4e42dSDan Gohman MachineInstr *InsertPt = &MI; 239*4fc4e42dSDan Gohman for (MachineOperand &MO : reverse(MI.explicit_uses())) { 240*4fc4e42dSDan Gohman if (!MO.isReg()) 241*4fc4e42dSDan Gohman continue; 242*4fc4e42dSDan Gohman 243*4fc4e42dSDan Gohman unsigned OldReg = MO.getReg(); 244*4fc4e42dSDan Gohman 245*4fc4e42dSDan Gohman // If we see a stackified register, prepare to insert subsequent 246*4fc4e42dSDan Gohman // get_locals before the start of its tree. 247*4fc4e42dSDan Gohman if (MFI.isVRegStackified(OldReg)) { 248*4fc4e42dSDan Gohman InsertPt = FindStartOfTree(MO, MRI, MFI); 249*4fc4e42dSDan Gohman continue; 250*4fc4e42dSDan Gohman } 251*4fc4e42dSDan Gohman 252*4fc4e42dSDan Gohman // Insert a get_local. 253*4fc4e42dSDan Gohman unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); 254*4fc4e42dSDan Gohman const TargetRegisterClass *RC = MRI.getRegClass(OldReg); 255*4fc4e42dSDan Gohman unsigned NewReg = MRI.createVirtualRegister(RC); 256*4fc4e42dSDan Gohman unsigned Opc = getGetLocalOpcode(RC); 257*4fc4e42dSDan Gohman InsertPt = 258*4fc4e42dSDan Gohman BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg) 259*4fc4e42dSDan Gohman .addImm(LocalId); 260*4fc4e42dSDan Gohman MO.setReg(NewReg); 261*4fc4e42dSDan Gohman MFI.stackifyVReg(NewReg); 262*4fc4e42dSDan Gohman Changed = true; 263*4fc4e42dSDan Gohman } 264*4fc4e42dSDan Gohman 265*4fc4e42dSDan Gohman // Coalesce and eliminate COPY instructions. 266*4fc4e42dSDan Gohman if (WebAssembly::isCopy(MI)) { 267*4fc4e42dSDan Gohman MRI.replaceRegWith(MI.getOperand(1).getReg(), 268*4fc4e42dSDan Gohman MI.getOperand(0).getReg()); 269*4fc4e42dSDan Gohman MI.eraseFromParent(); 270*4fc4e42dSDan Gohman Changed = true; 271*4fc4e42dSDan Gohman } 272*4fc4e42dSDan Gohman } 273*4fc4e42dSDan Gohman } 274*4fc4e42dSDan Gohman 275*4fc4e42dSDan Gohman // Insert a .locals directive to declare the locals. 276*4fc4e42dSDan Gohman MachineInstrBuilder DeclareLocals; 277*4fc4e42dSDan Gohman for (size_t i = 0, e = MRI.getNumVirtRegs(); i < e; ++i) { 278*4fc4e42dSDan Gohman unsigned Reg = TargetRegisterInfo::index2VirtReg(i); 279*4fc4e42dSDan Gohman auto I = Reg2Local.find(Reg); 280*4fc4e42dSDan Gohman if (I == Reg2Local.end() || I->second < MFI.getParams().size()) 281*4fc4e42dSDan Gohman continue; 282*4fc4e42dSDan Gohman 283*4fc4e42dSDan Gohman if (!DeclareLocals) { 284*4fc4e42dSDan Gohman DeclareLocals = BuildMI(*MF.begin(), MF.begin()->begin(), DebugLoc(), 285*4fc4e42dSDan Gohman TII->get(WebAssembly::DECLARE_LOCALS)); 286*4fc4e42dSDan Gohman Changed = true; 287*4fc4e42dSDan Gohman } 288*4fc4e42dSDan Gohman 289*4fc4e42dSDan Gohman DeclareLocals.addImm(int64_t(typeForRegClass(MRI.getRegClass(Reg)))); 290*4fc4e42dSDan Gohman } 291*4fc4e42dSDan Gohman 292*4fc4e42dSDan Gohman #ifndef NDEBUG 293*4fc4e42dSDan Gohman // Assert that all registers have been stackified at this point. 294*4fc4e42dSDan Gohman for (const MachineBasicBlock &MBB : MF) { 295*4fc4e42dSDan Gohman for (const MachineInstr &MI : MBB) { 296*4fc4e42dSDan Gohman if (MI.isDebugValue() || MI.isLabel()) 297*4fc4e42dSDan Gohman continue; 298*4fc4e42dSDan Gohman for (const MachineOperand &MO : MI.explicit_operands()) { 299*4fc4e42dSDan Gohman assert( 300*4fc4e42dSDan Gohman (!MO.isReg() || MRI.use_empty(MO.getReg()) || 301*4fc4e42dSDan Gohman MFI.isVRegStackified(MO.getReg())) && 302*4fc4e42dSDan Gohman "WebAssemblyExplicitLocals failed to stackify a register operand"); 303*4fc4e42dSDan Gohman } 304*4fc4e42dSDan Gohman } 305*4fc4e42dSDan Gohman } 306*4fc4e42dSDan Gohman #endif 307*4fc4e42dSDan Gohman 308*4fc4e42dSDan Gohman return Changed; 309*4fc4e42dSDan Gohman } 310