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