blob: b3da7861f29dca1099e1dc813ae3b52cb8a3b4df [file] [log] [blame]
Dan Gohman81719f82015-11-25 16:55:01 +00001//===-- WebAssemblyStoreResults.cpp - Optimize using store result values --===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file implements an optimization pass using store result values.
12///
Dan Gohman391a98a2015-12-03 23:07:03 +000013/// WebAssembly's store instructions return the stored value. This is to enable
14/// an optimization wherein uses of the stored value can be replaced by uses of
15/// the store's result value, making the stored value register more likely to
16/// be single-use, thus more likely to be useful to register stackifying, and
17/// potentially also exposing the store to register stackifying. These both can
18/// reduce get_local/set_local traffic.
Dan Gohman81719f82015-11-25 16:55:01 +000019///
Dan Gohmanbdf08d52016-01-26 04:01:11 +000020/// This pass also performs this optimization for memcpy, memmove, and memset
21/// calls, since the LLVM intrinsics for these return void so they can't use the
22/// returned attribute and consequently aren't handled by the OptimizeReturned
23/// pass.
24///
Dan Gohman81719f82015-11-25 16:55:01 +000025//===----------------------------------------------------------------------===//
26
27#include "WebAssembly.h"
28#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
29#include "WebAssemblyMachineFunctionInfo.h"
30#include "WebAssemblySubtarget.h"
Dan Gohmanbdf08d52016-01-26 04:01:11 +000031#include "llvm/Analysis/TargetLibraryInfo.h"
Dan Gohman0cfb5f82016-05-10 04:24:02 +000032#include "llvm/CodeGen/LiveIntervalAnalysis.h"
Dan Gohman81719f82015-11-25 16:55:01 +000033#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
34#include "llvm/CodeGen/MachineDominators.h"
35#include "llvm/CodeGen/MachineRegisterInfo.h"
36#include "llvm/CodeGen/Passes.h"
37#include "llvm/Support/Debug.h"
38#include "llvm/Support/raw_ostream.h"
39using namespace llvm;
40
41#define DEBUG_TYPE "wasm-store-results"
42
43namespace {
44class WebAssemblyStoreResults final : public MachineFunctionPass {
45public:
46 static char ID; // Pass identification, replacement for typeid
47 WebAssemblyStoreResults() : MachineFunctionPass(ID) {}
48
49 const char *getPassName() const override {
50 return "WebAssembly Store Results";
51 }
52
53 void getAnalysisUsage(AnalysisUsage &AU) const override {
54 AU.setPreservesCFG();
55 AU.addRequired<MachineBlockFrequencyInfo>();
56 AU.addPreserved<MachineBlockFrequencyInfo>();
57 AU.addRequired<MachineDominatorTree>();
58 AU.addPreserved<MachineDominatorTree>();
Dan Gohman0cfb5f82016-05-10 04:24:02 +000059 AU.addRequired<LiveIntervals>();
60 AU.addPreserved<SlotIndexes>();
61 AU.addPreserved<LiveIntervals>();
Dan Gohmanbdf08d52016-01-26 04:01:11 +000062 AU.addRequired<TargetLibraryInfoWrapperPass>();
Dan Gohman81719f82015-11-25 16:55:01 +000063 MachineFunctionPass::getAnalysisUsage(AU);
64 }
65
66 bool runOnMachineFunction(MachineFunction &MF) override;
67
68private:
69};
70} // end anonymous namespace
71
72char WebAssemblyStoreResults::ID = 0;
73FunctionPass *llvm::createWebAssemblyStoreResults() {
74 return new WebAssemblyStoreResults();
75}
76
Dan Gohmanbdf08d52016-01-26 04:01:11 +000077// Replace uses of FromReg with ToReg if they are dominated by MI.
78static bool ReplaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI,
79 unsigned FromReg, unsigned ToReg,
80 const MachineRegisterInfo &MRI,
Dan Gohman0cfb5f82016-05-10 04:24:02 +000081 MachineDominatorTree &MDT,
82 LiveIntervals &LIS) {
Dan Gohmanbdf08d52016-01-26 04:01:11 +000083 bool Changed = false;
Dan Gohman0cfb5f82016-05-10 04:24:02 +000084
85 LiveInterval *FromLI = &LIS.getInterval(FromReg);
86 LiveInterval *ToLI = &LIS.getInterval(ToReg);
87
88 SlotIndex FromIdx = LIS.getInstructionIndex(MI).getRegSlot();
89 VNInfo *FromVNI = FromLI->getVNInfoAt(FromIdx);
90
91 SmallVector<SlotIndex, 4> Indices;
92
Dan Gohmanbdf08d52016-01-26 04:01:11 +000093 for (auto I = MRI.use_begin(FromReg), E = MRI.use_end(); I != E;) {
94 MachineOperand &O = *I++;
95 MachineInstr *Where = O.getParent();
Dan Gohman0cfb5f82016-05-10 04:24:02 +000096
97 // Check that MI dominates the instruction in the normal way.
98 if (&MI == Where || !MDT.dominates(&MI, Where))
99 continue;
100
101 // If this use gets a different value, skip it.
102 SlotIndex WhereIdx = LIS.getInstructionIndex(*Where);
103 VNInfo *WhereVNI = FromLI->getVNInfoAt(WhereIdx);
104 if (WhereVNI && WhereVNI != FromVNI)
105 continue;
106
107 // Make sure ToReg isn't clobbered before it gets there.
108 VNInfo *ToVNI = ToLI->getVNInfoAt(WhereIdx);
109 if (ToVNI && ToVNI != FromVNI)
110 continue;
111
Dan Gohmanbdf08d52016-01-26 04:01:11 +0000112 Changed = true;
113 DEBUG(dbgs() << "Setting operand " << O << " in " << *Where << " from "
114 << MI << "\n");
115 O.setReg(ToReg);
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000116
117 // If the store's def was previously dead, it is no longer.
118 MI.getOperand(0).setIsDead(false);
119
120 Indices.push_back(WhereIdx.getRegSlot());
Dan Gohmanbdf08d52016-01-26 04:01:11 +0000121 }
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000122
123 if (Changed) {
124 // Extend ToReg's liveness.
125 LIS.extendToIndices(*ToLI, Indices);
126
127 // Shrink FromReg's liveness.
128 LIS.shrinkToUses(FromLI);
129
130 // If we replaced all dominated uses, FromReg is now killed at MI.
131 if (!FromLI->liveAt(FromIdx.getDeadSlot()))
132 MI.addRegisterKilled(FromReg,
133 MBB.getParent()->getSubtarget<WebAssemblySubtarget>()
134 .getRegisterInfo());
135 }
136
Dan Gohmanbdf08d52016-01-26 04:01:11 +0000137 return Changed;
138}
139
JF Bastiena5b8ea0d2016-02-01 10:46:16 +0000140static bool optimizeStore(MachineBasicBlock &MBB, MachineInstr &MI,
141 const MachineRegisterInfo &MRI,
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000142 MachineDominatorTree &MDT,
143 LiveIntervals &LIS) {
144 unsigned ToReg = MI.getOperand(0).getReg();
145 unsigned FromReg = MI.getOperand(WebAssembly::StoreValueOperandNo).getReg();
146 return ReplaceDominatedUses(MBB, MI, FromReg, ToReg, MRI, MDT, LIS);
JF Bastiena5b8ea0d2016-02-01 10:46:16 +0000147}
148
149static bool optimizeCall(MachineBasicBlock &MBB, MachineInstr &MI,
150 const MachineRegisterInfo &MRI,
151 MachineDominatorTree &MDT,
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000152 LiveIntervals &LIS,
JF Bastiena5b8ea0d2016-02-01 10:46:16 +0000153 const WebAssemblyTargetLowering &TLI,
154 const TargetLibraryInfo &LibInfo) {
155 MachineOperand &Op1 = MI.getOperand(1);
156 if (!Op1.isSymbol())
157 return false;
158
159 StringRef Name(Op1.getSymbolName());
160 bool callReturnsInput = Name == TLI.getLibcallName(RTLIB::MEMCPY) ||
161 Name == TLI.getLibcallName(RTLIB::MEMMOVE) ||
162 Name == TLI.getLibcallName(RTLIB::MEMSET);
163 if (!callReturnsInput)
164 return false;
165
166 LibFunc::Func Func;
167 if (!LibInfo.getLibFunc(Name, Func))
168 return false;
169
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000170 unsigned FromReg = MI.getOperand(2).getReg();
171 unsigned ToReg = MI.getOperand(0).getReg();
172 if (MRI.getRegClass(FromReg) != MRI.getRegClass(ToReg))
JF Bastiena5b8ea0d2016-02-01 10:46:16 +0000173 report_fatal_error("Store results: call to builtin function with wrong "
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000174 "signature, from/to mismatch");
175 return ReplaceDominatedUses(MBB, MI, FromReg, ToReg, MRI, MDT, LIS);
JF Bastiena5b8ea0d2016-02-01 10:46:16 +0000176}
177
Dan Gohman81719f82015-11-25 16:55:01 +0000178bool WebAssemblyStoreResults::runOnMachineFunction(MachineFunction &MF) {
179 DEBUG({
180 dbgs() << "********** Store Results **********\n"
181 << "********** Function: " << MF.getName() << '\n';
182 });
183
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000184 MachineRegisterInfo &MRI = MF.getRegInfo();
Dan Gohman81719f82015-11-25 16:55:01 +0000185 MachineDominatorTree &MDT = getAnalysis<MachineDominatorTree>();
Dan Gohmanbdf08d52016-01-26 04:01:11 +0000186 const WebAssemblyTargetLowering &TLI =
187 *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
JF Bastiena5b8ea0d2016-02-01 10:46:16 +0000188 const auto &LibInfo = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000189 LiveIntervals &LIS = getAnalysis<LiveIntervals>();
Dan Gohmanb949b9c2015-12-10 14:17:36 +0000190 bool Changed = false;
Dan Gohman81719f82015-11-25 16:55:01 +0000191
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000192 // We don't preserve SSA form.
193 MRI.leaveSSA();
194
195 assert(MRI.tracksLiveness() && "StoreResults expects liveness tracking");
Dan Gohmand70e5902015-12-08 03:30:42 +0000196
Derek Schuff5268aaf2015-12-03 00:50:30 +0000197 for (auto &MBB : MF) {
198 DEBUG(dbgs() << "Basic Block: " << MBB.getName() << '\n');
Dan Gohman81719f82015-11-25 16:55:01 +0000199 for (auto &MI : MBB)
200 switch (MI.getOpcode()) {
201 default:
202 break;
203 case WebAssembly::STORE8_I32:
204 case WebAssembly::STORE16_I32:
205 case WebAssembly::STORE8_I64:
206 case WebAssembly::STORE16_I64:
207 case WebAssembly::STORE32_I64:
208 case WebAssembly::STORE_F32:
209 case WebAssembly::STORE_F64:
210 case WebAssembly::STORE_I32:
JF Bastiena5b8ea0d2016-02-01 10:46:16 +0000211 case WebAssembly::STORE_I64:
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000212 Changed |= optimizeStore(MBB, MI, MRI, MDT, LIS);
Dan Gohmanbdf08d52016-01-26 04:01:11 +0000213 break;
Dan Gohmanbdf08d52016-01-26 04:01:11 +0000214 case WebAssembly::CALL_I32:
JF Bastiena5b8ea0d2016-02-01 10:46:16 +0000215 case WebAssembly::CALL_I64:
Dan Gohman0cfb5f82016-05-10 04:24:02 +0000216 Changed |= optimizeCall(MBB, MI, MRI, MDT, LIS, TLI, LibInfo);
JF Bastiena5b8ea0d2016-02-01 10:46:16 +0000217 break;
Dan Gohmanbdf08d52016-01-26 04:01:11 +0000218 }
Derek Schuff5268aaf2015-12-03 00:50:30 +0000219 }
Dan Gohman81719f82015-11-25 16:55:01 +0000220
Dan Gohmanb949b9c2015-12-10 14:17:36 +0000221 return Changed;
Dan Gohman81719f82015-11-25 16:55:01 +0000222}