1*321d5220SHeejin Ahn //== WebAssemblyMemIntrinsicResults.cpp - Optimize memory intrinsic results ==// 2*321d5220SHeejin Ahn // 3*321d5220SHeejin Ahn // The LLVM Compiler Infrastructure 4*321d5220SHeejin Ahn // 5*321d5220SHeejin Ahn // This file is distributed under the University of Illinois Open Source 6*321d5220SHeejin Ahn // License. See LICENSE.TXT for details. 7*321d5220SHeejin Ahn // 8*321d5220SHeejin Ahn //===----------------------------------------------------------------------===// 9*321d5220SHeejin Ahn /// 10*321d5220SHeejin Ahn /// \file 11*321d5220SHeejin Ahn /// This file implements an optimization pass using memory intrinsic results. 12*321d5220SHeejin Ahn /// 13*321d5220SHeejin Ahn /// Calls to memory intrinsics (memcpy, memmove, memset) return the destination 14*321d5220SHeejin Ahn /// address. They are in the form of 15*321d5220SHeejin Ahn /// %dst_new = call @memcpy %dst, %src, %len 16*321d5220SHeejin Ahn /// where %dst and %dst_new registers contain the same value. 17*321d5220SHeejin Ahn /// 18*321d5220SHeejin Ahn /// This is to enable an optimization wherein uses of the %dst register used in 19*321d5220SHeejin Ahn /// the parameter can be replaced by uses of the %dst_new register used in the 20*321d5220SHeejin Ahn /// result, making the %dst register more likely to be single-use, thus more 21*321d5220SHeejin Ahn /// likely to be useful to register stackifying, and potentially also exposing 22*321d5220SHeejin Ahn /// the call instruction itself to register stackifying. These both can reduce 23*321d5220SHeejin Ahn /// local.get/local.set traffic. 24*321d5220SHeejin Ahn /// 25*321d5220SHeejin Ahn /// The LLVM intrinsics for these return void so they can't use the returned 26*321d5220SHeejin Ahn /// attribute and consequently aren't handled by the OptimizeReturned pass. 27*321d5220SHeejin Ahn /// 28*321d5220SHeejin Ahn //===----------------------------------------------------------------------===// 29*321d5220SHeejin Ahn 30*321d5220SHeejin Ahn #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 31*321d5220SHeejin Ahn #include "WebAssembly.h" 32*321d5220SHeejin Ahn #include "WebAssemblyMachineFunctionInfo.h" 33*321d5220SHeejin Ahn #include "WebAssemblySubtarget.h" 34*321d5220SHeejin Ahn #include "llvm/Analysis/TargetLibraryInfo.h" 35*321d5220SHeejin Ahn #include "llvm/CodeGen/LiveIntervals.h" 36*321d5220SHeejin Ahn #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 37*321d5220SHeejin Ahn #include "llvm/CodeGen/MachineDominators.h" 38*321d5220SHeejin Ahn #include "llvm/CodeGen/MachineRegisterInfo.h" 39*321d5220SHeejin Ahn #include "llvm/CodeGen/Passes.h" 40*321d5220SHeejin Ahn #include "llvm/Support/Debug.h" 41*321d5220SHeejin Ahn #include "llvm/Support/raw_ostream.h" 42*321d5220SHeejin Ahn using namespace llvm; 43*321d5220SHeejin Ahn 44*321d5220SHeejin Ahn #define DEBUG_TYPE "wasm-mem-intrinsic-results" 45*321d5220SHeejin Ahn 46*321d5220SHeejin Ahn namespace { 47*321d5220SHeejin Ahn class WebAssemblyMemIntrinsicResults final : public MachineFunctionPass { 48*321d5220SHeejin Ahn public: 49*321d5220SHeejin Ahn static char ID; // Pass identification, replacement for typeid 50*321d5220SHeejin Ahn WebAssemblyMemIntrinsicResults() : MachineFunctionPass(ID) {} 51*321d5220SHeejin Ahn 52*321d5220SHeejin Ahn StringRef getPassName() const override { 53*321d5220SHeejin Ahn return "WebAssembly Memory Intrinsic Results"; 54*321d5220SHeejin Ahn } 55*321d5220SHeejin Ahn 56*321d5220SHeejin Ahn void getAnalysisUsage(AnalysisUsage &AU) const override { 57*321d5220SHeejin Ahn AU.setPreservesCFG(); 58*321d5220SHeejin Ahn AU.addRequired<MachineBlockFrequencyInfo>(); 59*321d5220SHeejin Ahn AU.addPreserved<MachineBlockFrequencyInfo>(); 60*321d5220SHeejin Ahn AU.addRequired<MachineDominatorTree>(); 61*321d5220SHeejin Ahn AU.addPreserved<MachineDominatorTree>(); 62*321d5220SHeejin Ahn AU.addRequired<LiveIntervals>(); 63*321d5220SHeejin Ahn AU.addPreserved<SlotIndexes>(); 64*321d5220SHeejin Ahn AU.addPreserved<LiveIntervals>(); 65*321d5220SHeejin Ahn AU.addRequired<TargetLibraryInfoWrapperPass>(); 66*321d5220SHeejin Ahn MachineFunctionPass::getAnalysisUsage(AU); 67*321d5220SHeejin Ahn } 68*321d5220SHeejin Ahn 69*321d5220SHeejin Ahn bool runOnMachineFunction(MachineFunction &MF) override; 70*321d5220SHeejin Ahn 71*321d5220SHeejin Ahn private: 72*321d5220SHeejin Ahn }; 73*321d5220SHeejin Ahn } // end anonymous namespace 74*321d5220SHeejin Ahn 75*321d5220SHeejin Ahn char WebAssemblyMemIntrinsicResults::ID = 0; 76*321d5220SHeejin Ahn INITIALIZE_PASS(WebAssemblyMemIntrinsicResults, DEBUG_TYPE, 77*321d5220SHeejin Ahn "Optimize memory intrinsic result values for WebAssembly", 78*321d5220SHeejin Ahn false, false) 79*321d5220SHeejin Ahn 80*321d5220SHeejin Ahn FunctionPass *llvm::createWebAssemblyMemIntrinsicResults() { 81*321d5220SHeejin Ahn return new WebAssemblyMemIntrinsicResults(); 82*321d5220SHeejin Ahn } 83*321d5220SHeejin Ahn 84*321d5220SHeejin Ahn // Replace uses of FromReg with ToReg if they are dominated by MI. 85*321d5220SHeejin Ahn static bool ReplaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI, 86*321d5220SHeejin Ahn unsigned FromReg, unsigned ToReg, 87*321d5220SHeejin Ahn const MachineRegisterInfo &MRI, 88*321d5220SHeejin Ahn MachineDominatorTree &MDT, 89*321d5220SHeejin Ahn LiveIntervals &LIS) { 90*321d5220SHeejin Ahn bool Changed = false; 91*321d5220SHeejin Ahn 92*321d5220SHeejin Ahn LiveInterval *FromLI = &LIS.getInterval(FromReg); 93*321d5220SHeejin Ahn LiveInterval *ToLI = &LIS.getInterval(ToReg); 94*321d5220SHeejin Ahn 95*321d5220SHeejin Ahn SlotIndex FromIdx = LIS.getInstructionIndex(MI).getRegSlot(); 96*321d5220SHeejin Ahn VNInfo *FromVNI = FromLI->getVNInfoAt(FromIdx); 97*321d5220SHeejin Ahn 98*321d5220SHeejin Ahn SmallVector<SlotIndex, 4> Indices; 99*321d5220SHeejin Ahn 100*321d5220SHeejin Ahn for (auto I = MRI.use_nodbg_begin(FromReg), E = MRI.use_nodbg_end(); 101*321d5220SHeejin Ahn I != E;) { 102*321d5220SHeejin Ahn MachineOperand &O = *I++; 103*321d5220SHeejin Ahn MachineInstr *Where = O.getParent(); 104*321d5220SHeejin Ahn 105*321d5220SHeejin Ahn // Check that MI dominates the instruction in the normal way. 106*321d5220SHeejin Ahn if (&MI == Where || !MDT.dominates(&MI, Where)) 107*321d5220SHeejin Ahn continue; 108*321d5220SHeejin Ahn 109*321d5220SHeejin Ahn // If this use gets a different value, skip it. 110*321d5220SHeejin Ahn SlotIndex WhereIdx = LIS.getInstructionIndex(*Where); 111*321d5220SHeejin Ahn VNInfo *WhereVNI = FromLI->getVNInfoAt(WhereIdx); 112*321d5220SHeejin Ahn if (WhereVNI && WhereVNI != FromVNI) 113*321d5220SHeejin Ahn continue; 114*321d5220SHeejin Ahn 115*321d5220SHeejin Ahn // Make sure ToReg isn't clobbered before it gets there. 116*321d5220SHeejin Ahn VNInfo *ToVNI = ToLI->getVNInfoAt(WhereIdx); 117*321d5220SHeejin Ahn if (ToVNI && ToVNI != FromVNI) 118*321d5220SHeejin Ahn continue; 119*321d5220SHeejin Ahn 120*321d5220SHeejin Ahn Changed = true; 121*321d5220SHeejin Ahn LLVM_DEBUG(dbgs() << "Setting operand " << O << " in " << *Where << " from " 122*321d5220SHeejin Ahn << MI << "\n"); 123*321d5220SHeejin Ahn O.setReg(ToReg); 124*321d5220SHeejin Ahn 125*321d5220SHeejin Ahn // If the store's def was previously dead, it is no longer. 126*321d5220SHeejin Ahn if (!O.isUndef()) { 127*321d5220SHeejin Ahn MI.getOperand(0).setIsDead(false); 128*321d5220SHeejin Ahn 129*321d5220SHeejin Ahn Indices.push_back(WhereIdx.getRegSlot()); 130*321d5220SHeejin Ahn } 131*321d5220SHeejin Ahn } 132*321d5220SHeejin Ahn 133*321d5220SHeejin Ahn if (Changed) { 134*321d5220SHeejin Ahn // Extend ToReg's liveness. 135*321d5220SHeejin Ahn LIS.extendToIndices(*ToLI, Indices); 136*321d5220SHeejin Ahn 137*321d5220SHeejin Ahn // Shrink FromReg's liveness. 138*321d5220SHeejin Ahn LIS.shrinkToUses(FromLI); 139*321d5220SHeejin Ahn 140*321d5220SHeejin Ahn // If we replaced all dominated uses, FromReg is now killed at MI. 141*321d5220SHeejin Ahn if (!FromLI->liveAt(FromIdx.getDeadSlot())) 142*321d5220SHeejin Ahn MI.addRegisterKilled(FromReg, MBB.getParent() 143*321d5220SHeejin Ahn ->getSubtarget<WebAssemblySubtarget>() 144*321d5220SHeejin Ahn .getRegisterInfo()); 145*321d5220SHeejin Ahn } 146*321d5220SHeejin Ahn 147*321d5220SHeejin Ahn return Changed; 148*321d5220SHeejin Ahn } 149*321d5220SHeejin Ahn 150*321d5220SHeejin Ahn static bool optimizeCall(MachineBasicBlock &MBB, MachineInstr &MI, 151*321d5220SHeejin Ahn const MachineRegisterInfo &MRI, 152*321d5220SHeejin Ahn MachineDominatorTree &MDT, LiveIntervals &LIS, 153*321d5220SHeejin Ahn const WebAssemblyTargetLowering &TLI, 154*321d5220SHeejin Ahn const TargetLibraryInfo &LibInfo) { 155*321d5220SHeejin Ahn MachineOperand &Op1 = MI.getOperand(1); 156*321d5220SHeejin Ahn if (!Op1.isSymbol()) 157*321d5220SHeejin Ahn return false; 158*321d5220SHeejin Ahn 159*321d5220SHeejin Ahn StringRef Name(Op1.getSymbolName()); 160*321d5220SHeejin Ahn bool callReturnsInput = Name == TLI.getLibcallName(RTLIB::MEMCPY) || 161*321d5220SHeejin Ahn Name == TLI.getLibcallName(RTLIB::MEMMOVE) || 162*321d5220SHeejin Ahn Name == TLI.getLibcallName(RTLIB::MEMSET); 163*321d5220SHeejin Ahn if (!callReturnsInput) 164*321d5220SHeejin Ahn return false; 165*321d5220SHeejin Ahn 166*321d5220SHeejin Ahn LibFunc Func; 167*321d5220SHeejin Ahn if (!LibInfo.getLibFunc(Name, Func)) 168*321d5220SHeejin Ahn return false; 169*321d5220SHeejin Ahn 170*321d5220SHeejin Ahn unsigned FromReg = MI.getOperand(2).getReg(); 171*321d5220SHeejin Ahn unsigned ToReg = MI.getOperand(0).getReg(); 172*321d5220SHeejin Ahn if (MRI.getRegClass(FromReg) != MRI.getRegClass(ToReg)) 173*321d5220SHeejin Ahn report_fatal_error("Memory Intrinsic results: call to builtin function " 174*321d5220SHeejin Ahn "with wrong signature, from/to mismatch"); 175*321d5220SHeejin Ahn return ReplaceDominatedUses(MBB, MI, FromReg, ToReg, MRI, MDT, LIS); 176*321d5220SHeejin Ahn } 177*321d5220SHeejin Ahn 178*321d5220SHeejin Ahn bool WebAssemblyMemIntrinsicResults::runOnMachineFunction(MachineFunction &MF) { 179*321d5220SHeejin Ahn LLVM_DEBUG({ 180*321d5220SHeejin Ahn dbgs() << "********** Memory Intrinsic Results **********\n" 181*321d5220SHeejin Ahn << "********** Function: " << MF.getName() << '\n'; 182*321d5220SHeejin Ahn }); 183*321d5220SHeejin Ahn 184*321d5220SHeejin Ahn MachineRegisterInfo &MRI = MF.getRegInfo(); 185*321d5220SHeejin Ahn MachineDominatorTree &MDT = getAnalysis<MachineDominatorTree>(); 186*321d5220SHeejin Ahn const WebAssemblyTargetLowering &TLI = 187*321d5220SHeejin Ahn *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 188*321d5220SHeejin Ahn const auto &LibInfo = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); 189*321d5220SHeejin Ahn LiveIntervals &LIS = getAnalysis<LiveIntervals>(); 190*321d5220SHeejin Ahn bool Changed = false; 191*321d5220SHeejin Ahn 192*321d5220SHeejin Ahn // We don't preserve SSA form. 193*321d5220SHeejin Ahn MRI.leaveSSA(); 194*321d5220SHeejin Ahn 195*321d5220SHeejin Ahn assert(MRI.tracksLiveness() && 196*321d5220SHeejin Ahn "MemIntrinsicResults expects liveness tracking"); 197*321d5220SHeejin Ahn 198*321d5220SHeejin Ahn for (auto &MBB : MF) { 199*321d5220SHeejin Ahn LLVM_DEBUG(dbgs() << "Basic Block: " << MBB.getName() << '\n'); 200*321d5220SHeejin Ahn for (auto &MI : MBB) 201*321d5220SHeejin Ahn switch (MI.getOpcode()) { 202*321d5220SHeejin Ahn default: 203*321d5220SHeejin Ahn break; 204*321d5220SHeejin Ahn case WebAssembly::CALL_I32: 205*321d5220SHeejin Ahn case WebAssembly::CALL_I64: 206*321d5220SHeejin Ahn Changed |= optimizeCall(MBB, MI, MRI, MDT, LIS, TLI, LibInfo); 207*321d5220SHeejin Ahn break; 208*321d5220SHeejin Ahn } 209*321d5220SHeejin Ahn } 210*321d5220SHeejin Ahn 211*321d5220SHeejin Ahn return Changed; 212*321d5220SHeejin Ahn } 213