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