1321d5220SHeejin Ahn //== WebAssemblyMemIntrinsicResults.cpp - Optimize memory intrinsic results ==// 2321d5220SHeejin Ahn // 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 6321d5220SHeejin Ahn // 7321d5220SHeejin Ahn //===----------------------------------------------------------------------===// 8321d5220SHeejin Ahn /// 9321d5220SHeejin Ahn /// \file 10321d5220SHeejin Ahn /// This file implements an optimization pass using memory intrinsic results. 11321d5220SHeejin Ahn /// 12321d5220SHeejin Ahn /// Calls to memory intrinsics (memcpy, memmove, memset) return the destination 13321d5220SHeejin Ahn /// address. They are in the form of 14321d5220SHeejin Ahn /// %dst_new = call @memcpy %dst, %src, %len 15321d5220SHeejin Ahn /// where %dst and %dst_new registers contain the same value. 16321d5220SHeejin Ahn /// 17321d5220SHeejin Ahn /// This is to enable an optimization wherein uses of the %dst register used in 18321d5220SHeejin Ahn /// the parameter can be replaced by uses of the %dst_new register used in the 19321d5220SHeejin Ahn /// result, making the %dst register more likely to be single-use, thus more 20321d5220SHeejin Ahn /// likely to be useful to register stackifying, and potentially also exposing 21321d5220SHeejin Ahn /// the call instruction itself to register stackifying. These both can reduce 22321d5220SHeejin Ahn /// local.get/local.set traffic. 23321d5220SHeejin Ahn /// 24321d5220SHeejin Ahn /// The LLVM intrinsics for these return void so they can't use the returned 25321d5220SHeejin Ahn /// attribute and consequently aren't handled by the OptimizeReturned pass. 26321d5220SHeejin Ahn /// 27321d5220SHeejin Ahn //===----------------------------------------------------------------------===// 28321d5220SHeejin Ahn 29321d5220SHeejin Ahn #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 30321d5220SHeejin Ahn #include "WebAssembly.h" 31321d5220SHeejin Ahn #include "WebAssemblyMachineFunctionInfo.h" 32321d5220SHeejin Ahn #include "WebAssemblySubtarget.h" 33321d5220SHeejin Ahn #include "llvm/Analysis/TargetLibraryInfo.h" 34321d5220SHeejin Ahn #include "llvm/CodeGen/LiveIntervals.h" 35321d5220SHeejin Ahn #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 36321d5220SHeejin Ahn #include "llvm/CodeGen/MachineDominators.h" 37321d5220SHeejin Ahn #include "llvm/CodeGen/MachineRegisterInfo.h" 38321d5220SHeejin Ahn #include "llvm/CodeGen/Passes.h" 39321d5220SHeejin Ahn #include "llvm/Support/Debug.h" 40321d5220SHeejin Ahn #include "llvm/Support/raw_ostream.h" 41321d5220SHeejin Ahn using namespace llvm; 42321d5220SHeejin Ahn 43321d5220SHeejin Ahn #define DEBUG_TYPE "wasm-mem-intrinsic-results" 44321d5220SHeejin Ahn 45321d5220SHeejin Ahn namespace { 46321d5220SHeejin Ahn class WebAssemblyMemIntrinsicResults final : public MachineFunctionPass { 47321d5220SHeejin Ahn public: 48321d5220SHeejin Ahn static char ID; // Pass identification, replacement for typeid 49321d5220SHeejin Ahn WebAssemblyMemIntrinsicResults() : MachineFunctionPass(ID) {} 50321d5220SHeejin Ahn 51321d5220SHeejin Ahn StringRef getPassName() const override { 52321d5220SHeejin Ahn return "WebAssembly Memory Intrinsic Results"; 53321d5220SHeejin Ahn } 54321d5220SHeejin Ahn 55321d5220SHeejin Ahn void getAnalysisUsage(AnalysisUsage &AU) const override { 56321d5220SHeejin Ahn AU.setPreservesCFG(); 57321d5220SHeejin Ahn AU.addRequired<MachineBlockFrequencyInfo>(); 58321d5220SHeejin Ahn AU.addPreserved<MachineBlockFrequencyInfo>(); 59321d5220SHeejin Ahn AU.addRequired<MachineDominatorTree>(); 60321d5220SHeejin Ahn AU.addPreserved<MachineDominatorTree>(); 61321d5220SHeejin Ahn AU.addRequired<LiveIntervals>(); 62321d5220SHeejin Ahn AU.addPreserved<SlotIndexes>(); 63321d5220SHeejin Ahn AU.addPreserved<LiveIntervals>(); 64321d5220SHeejin Ahn AU.addRequired<TargetLibraryInfoWrapperPass>(); 65321d5220SHeejin Ahn MachineFunctionPass::getAnalysisUsage(AU); 66321d5220SHeejin Ahn } 67321d5220SHeejin Ahn 68321d5220SHeejin Ahn bool runOnMachineFunction(MachineFunction &MF) override; 69321d5220SHeejin Ahn 70321d5220SHeejin Ahn private: 71321d5220SHeejin Ahn }; 72321d5220SHeejin Ahn } // end anonymous namespace 73321d5220SHeejin Ahn 74321d5220SHeejin Ahn char WebAssemblyMemIntrinsicResults::ID = 0; 75321d5220SHeejin Ahn INITIALIZE_PASS(WebAssemblyMemIntrinsicResults, DEBUG_TYPE, 76321d5220SHeejin Ahn "Optimize memory intrinsic result values for WebAssembly", 77321d5220SHeejin Ahn false, false) 78321d5220SHeejin Ahn 79321d5220SHeejin Ahn FunctionPass *llvm::createWebAssemblyMemIntrinsicResults() { 80321d5220SHeejin Ahn return new WebAssemblyMemIntrinsicResults(); 81321d5220SHeejin Ahn } 82321d5220SHeejin Ahn 83321d5220SHeejin Ahn // Replace uses of FromReg with ToReg if they are dominated by MI. 8418c56a07SHeejin Ahn static bool replaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI, 85321d5220SHeejin Ahn unsigned FromReg, unsigned ToReg, 86321d5220SHeejin Ahn const MachineRegisterInfo &MRI, 87321d5220SHeejin Ahn MachineDominatorTree &MDT, 88321d5220SHeejin Ahn LiveIntervals &LIS) { 89321d5220SHeejin Ahn bool Changed = false; 90321d5220SHeejin Ahn 91321d5220SHeejin Ahn LiveInterval *FromLI = &LIS.getInterval(FromReg); 92321d5220SHeejin Ahn LiveInterval *ToLI = &LIS.getInterval(ToReg); 93321d5220SHeejin Ahn 94321d5220SHeejin Ahn SlotIndex FromIdx = LIS.getInstructionIndex(MI).getRegSlot(); 95321d5220SHeejin Ahn VNInfo *FromVNI = FromLI->getVNInfoAt(FromIdx); 96321d5220SHeejin Ahn 97321d5220SHeejin Ahn SmallVector<SlotIndex, 4> Indices; 98321d5220SHeejin Ahn 99321d5220SHeejin Ahn for (auto I = MRI.use_nodbg_begin(FromReg), E = MRI.use_nodbg_end(); 100321d5220SHeejin Ahn I != E;) { 101321d5220SHeejin Ahn MachineOperand &O = *I++; 102321d5220SHeejin Ahn MachineInstr *Where = O.getParent(); 103321d5220SHeejin Ahn 104321d5220SHeejin Ahn // Check that MI dominates the instruction in the normal way. 105321d5220SHeejin Ahn if (&MI == Where || !MDT.dominates(&MI, Where)) 106321d5220SHeejin Ahn continue; 107321d5220SHeejin Ahn 108321d5220SHeejin Ahn // If this use gets a different value, skip it. 109321d5220SHeejin Ahn SlotIndex WhereIdx = LIS.getInstructionIndex(*Where); 110321d5220SHeejin Ahn VNInfo *WhereVNI = FromLI->getVNInfoAt(WhereIdx); 111321d5220SHeejin Ahn if (WhereVNI && WhereVNI != FromVNI) 112321d5220SHeejin Ahn continue; 113321d5220SHeejin Ahn 114321d5220SHeejin Ahn // Make sure ToReg isn't clobbered before it gets there. 115321d5220SHeejin Ahn VNInfo *ToVNI = ToLI->getVNInfoAt(WhereIdx); 116321d5220SHeejin Ahn if (ToVNI && ToVNI != FromVNI) 117321d5220SHeejin Ahn continue; 118321d5220SHeejin Ahn 119321d5220SHeejin Ahn Changed = true; 120321d5220SHeejin Ahn LLVM_DEBUG(dbgs() << "Setting operand " << O << " in " << *Where << " from " 121321d5220SHeejin Ahn << MI << "\n"); 122321d5220SHeejin Ahn O.setReg(ToReg); 123321d5220SHeejin Ahn 124321d5220SHeejin Ahn // If the store's def was previously dead, it is no longer. 125321d5220SHeejin Ahn if (!O.isUndef()) { 126321d5220SHeejin Ahn MI.getOperand(0).setIsDead(false); 127321d5220SHeejin Ahn 128321d5220SHeejin Ahn Indices.push_back(WhereIdx.getRegSlot()); 129321d5220SHeejin Ahn } 130321d5220SHeejin Ahn } 131321d5220SHeejin Ahn 132321d5220SHeejin Ahn if (Changed) { 133321d5220SHeejin Ahn // Extend ToReg's liveness. 134321d5220SHeejin Ahn LIS.extendToIndices(*ToLI, Indices); 135321d5220SHeejin Ahn 136321d5220SHeejin Ahn // Shrink FromReg's liveness. 137321d5220SHeejin Ahn LIS.shrinkToUses(FromLI); 138321d5220SHeejin Ahn 139321d5220SHeejin Ahn // If we replaced all dominated uses, FromReg is now killed at MI. 140321d5220SHeejin Ahn if (!FromLI->liveAt(FromIdx.getDeadSlot())) 141321d5220SHeejin Ahn MI.addRegisterKilled(FromReg, MBB.getParent() 142321d5220SHeejin Ahn ->getSubtarget<WebAssemblySubtarget>() 143321d5220SHeejin Ahn .getRegisterInfo()); 144321d5220SHeejin Ahn } 145321d5220SHeejin Ahn 146321d5220SHeejin Ahn return Changed; 147321d5220SHeejin Ahn } 148321d5220SHeejin Ahn 149321d5220SHeejin Ahn static bool optimizeCall(MachineBasicBlock &MBB, MachineInstr &MI, 150321d5220SHeejin Ahn const MachineRegisterInfo &MRI, 151321d5220SHeejin Ahn MachineDominatorTree &MDT, LiveIntervals &LIS, 152321d5220SHeejin Ahn const WebAssemblyTargetLowering &TLI, 153321d5220SHeejin Ahn const TargetLibraryInfo &LibInfo) { 154321d5220SHeejin Ahn MachineOperand &Op1 = MI.getOperand(1); 155321d5220SHeejin Ahn if (!Op1.isSymbol()) 156321d5220SHeejin Ahn return false; 157321d5220SHeejin Ahn 158321d5220SHeejin Ahn StringRef Name(Op1.getSymbolName()); 15918c56a07SHeejin Ahn bool CallReturnsInput = Name == TLI.getLibcallName(RTLIB::MEMCPY) || 160321d5220SHeejin Ahn Name == TLI.getLibcallName(RTLIB::MEMMOVE) || 161321d5220SHeejin Ahn Name == TLI.getLibcallName(RTLIB::MEMSET); 16218c56a07SHeejin Ahn if (!CallReturnsInput) 163321d5220SHeejin Ahn return false; 164321d5220SHeejin Ahn 165321d5220SHeejin Ahn LibFunc Func; 166321d5220SHeejin Ahn if (!LibInfo.getLibFunc(Name, Func)) 167321d5220SHeejin Ahn return false; 168321d5220SHeejin Ahn 169321d5220SHeejin Ahn unsigned FromReg = MI.getOperand(2).getReg(); 170321d5220SHeejin Ahn unsigned ToReg = MI.getOperand(0).getReg(); 171321d5220SHeejin Ahn if (MRI.getRegClass(FromReg) != MRI.getRegClass(ToReg)) 172321d5220SHeejin Ahn report_fatal_error("Memory Intrinsic results: call to builtin function " 173321d5220SHeejin Ahn "with wrong signature, from/to mismatch"); 17418c56a07SHeejin Ahn return replaceDominatedUses(MBB, MI, FromReg, ToReg, MRI, MDT, LIS); 175321d5220SHeejin Ahn } 176321d5220SHeejin Ahn 177321d5220SHeejin Ahn bool WebAssemblyMemIntrinsicResults::runOnMachineFunction(MachineFunction &MF) { 178321d5220SHeejin Ahn LLVM_DEBUG({ 179321d5220SHeejin Ahn dbgs() << "********** Memory Intrinsic Results **********\n" 180321d5220SHeejin Ahn << "********** Function: " << MF.getName() << '\n'; 181321d5220SHeejin Ahn }); 182321d5220SHeejin Ahn 183321d5220SHeejin Ahn MachineRegisterInfo &MRI = MF.getRegInfo(); 18418c56a07SHeejin Ahn auto &MDT = getAnalysis<MachineDominatorTree>(); 185321d5220SHeejin Ahn const WebAssemblyTargetLowering &TLI = 186321d5220SHeejin Ahn *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 187321d5220SHeejin Ahn const auto &LibInfo = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); 18818c56a07SHeejin Ahn auto &LIS = getAnalysis<LiveIntervals>(); 189321d5220SHeejin Ahn bool Changed = false; 190321d5220SHeejin Ahn 191321d5220SHeejin Ahn // We don't preserve SSA form. 192321d5220SHeejin Ahn MRI.leaveSSA(); 193321d5220SHeejin Ahn 194321d5220SHeejin Ahn assert(MRI.tracksLiveness() && 195321d5220SHeejin Ahn "MemIntrinsicResults expects liveness tracking"); 196321d5220SHeejin Ahn 197321d5220SHeejin Ahn for (auto &MBB : MF) { 198321d5220SHeejin Ahn LLVM_DEBUG(dbgs() << "Basic Block: " << MBB.getName() << '\n'); 199321d5220SHeejin Ahn for (auto &MI : MBB) 200321d5220SHeejin Ahn switch (MI.getOpcode()) { 201321d5220SHeejin Ahn default: 202321d5220SHeejin Ahn break; 203*a1d97a96SThomas Lively case WebAssembly::CALL_i32: 204*a1d97a96SThomas Lively case WebAssembly::CALL_i64: 205321d5220SHeejin Ahn Changed |= optimizeCall(MBB, MI, MRI, MDT, LIS, TLI, LibInfo); 206321d5220SHeejin Ahn break; 207321d5220SHeejin Ahn } 208321d5220SHeejin Ahn } 209321d5220SHeejin Ahn 210321d5220SHeejin Ahn return Changed; 211321d5220SHeejin Ahn } 212