LLVM 19.0.0git
WebAssemblyMemIntrinsicResults.cpp
Go to the documentation of this file.
1//== WebAssemblyMemIntrinsicResults.cpp - Optimize memory intrinsic results ==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// This file implements an optimization pass using memory intrinsic results.
11///
12/// Calls to memory intrinsics (memcpy, memmove, memset) return the destination
13/// address. They are in the form of
14/// %dst_new = call @memcpy %dst, %src, %len
15/// where %dst and %dst_new registers contain the same value.
16///
17/// This is to enable an optimization wherein uses of the %dst register used in
18/// the parameter can be replaced by uses of the %dst_new register used in the
19/// result, making the %dst register more likely to be single-use, thus more
20/// likely to be useful to register stackifying, and potentially also exposing
21/// the call instruction itself to register stackifying. These both can reduce
22/// local.get/local.set traffic.
23///
24/// The LLVM intrinsics for these return void so they can't use the returned
25/// attribute and consequently aren't handled by the OptimizeReturned pass.
26///
27//===----------------------------------------------------------------------===//
28
30#include "WebAssembly.h"
38#include "llvm/CodeGen/Passes.h"
39#include "llvm/Support/Debug.h"
41using namespace llvm;
42
43#define DEBUG_TYPE "wasm-mem-intrinsic-results"
44
45namespace {
46class WebAssemblyMemIntrinsicResults final : public MachineFunctionPass {
47public:
48 static char ID; // Pass identification, replacement for typeid
49 WebAssemblyMemIntrinsicResults() : MachineFunctionPass(ID) {}
50
51 StringRef getPassName() const override {
52 return "WebAssembly Memory Intrinsic Results";
53 }
54
55 void getAnalysisUsage(AnalysisUsage &AU) const override {
56 AU.setPreservesCFG();
66 }
67
68 bool runOnMachineFunction(MachineFunction &MF) override;
69
70private:
71};
72} // end anonymous namespace
73
74char WebAssemblyMemIntrinsicResults::ID = 0;
75INITIALIZE_PASS(WebAssemblyMemIntrinsicResults, DEBUG_TYPE,
76 "Optimize memory intrinsic result values for WebAssembly",
77 false, false)
78
80 return new WebAssemblyMemIntrinsicResults();
81}
82
83// Replace uses of FromReg with ToReg if they are dominated by MI.
85 unsigned FromReg, unsigned ToReg,
88 LiveIntervals &LIS) {
89 bool Changed = false;
90
91 LiveInterval *FromLI = &LIS.getInterval(FromReg);
92 LiveInterval *ToLI = &LIS.getInterval(ToReg);
93
95 VNInfo *FromVNI = FromLI->getVNInfoAt(FromIdx);
96
98
99 for (MachineOperand &O :
100 llvm::make_early_inc_range(MRI.use_nodbg_operands(FromReg))) {
101 MachineInstr *Where = O.getParent();
102
103 // Check that MI dominates the instruction in the normal way.
104 if (&MI == Where || !MDT.dominates(&MI, Where))
105 continue;
106
107 // If this use gets a different value, skip it.
108 SlotIndex WhereIdx = LIS.getInstructionIndex(*Where);
109 VNInfo *WhereVNI = FromLI->getVNInfoAt(WhereIdx);
110 if (WhereVNI && WhereVNI != FromVNI)
111 continue;
112
113 // Make sure ToReg isn't clobbered before it gets there.
114 VNInfo *ToVNI = ToLI->getVNInfoAt(WhereIdx);
115 if (ToVNI && ToVNI != FromVNI)
116 continue;
117
118 Changed = true;
119 LLVM_DEBUG(dbgs() << "Setting operand " << O << " in " << *Where << " from "
120 << MI << "\n");
121 O.setReg(ToReg);
122
123 // If the store's def was previously dead, it is no longer.
124 if (!O.isUndef()) {
125 MI.getOperand(0).setIsDead(false);
126
127 Indices.push_back(WhereIdx.getRegSlot());
128 }
129 }
130
131 if (Changed) {
132 // Extend ToReg's liveness.
133 LIS.extendToIndices(*ToLI, Indices);
134
135 // Shrink FromReg's liveness.
136 LIS.shrinkToUses(FromLI);
137
138 // If we replaced all dominated uses, FromReg is now killed at MI.
139 if (!FromLI->liveAt(FromIdx.getDeadSlot()))
140 MI.addRegisterKilled(FromReg, MBB.getParent()
142 .getRegisterInfo());
143 }
144
145 return Changed;
146}
147
151 const WebAssemblyTargetLowering &TLI,
152 const TargetLibraryInfo &LibInfo) {
153 MachineOperand &Op1 = MI.getOperand(1);
154 if (!Op1.isSymbol())
155 return false;
156
158 bool CallReturnsInput = Name == TLI.getLibcallName(RTLIB::MEMCPY) ||
159 Name == TLI.getLibcallName(RTLIB::MEMMOVE) ||
160 Name == TLI.getLibcallName(RTLIB::MEMSET);
161 if (!CallReturnsInput)
162 return false;
163
164 LibFunc Func;
165 if (!LibInfo.getLibFunc(Name, Func))
166 return false;
167
168 Register FromReg = MI.getOperand(2).getReg();
169 Register ToReg = MI.getOperand(0).getReg();
170 if (MRI.getRegClass(FromReg) != MRI.getRegClass(ToReg))
171 report_fatal_error("Memory Intrinsic results: call to builtin function "
172 "with wrong signature, from/to mismatch");
173 return replaceDominatedUses(MBB, MI, FromReg, ToReg, MRI, MDT, LIS);
174}
175
176bool WebAssemblyMemIntrinsicResults::runOnMachineFunction(MachineFunction &MF) {
177 LLVM_DEBUG({
178 dbgs() << "********** Memory Intrinsic Results **********\n"
179 << "********** Function: " << MF.getName() << '\n';
180 });
181
183 auto &MDT = getAnalysis<MachineDominatorTree>();
184 const WebAssemblyTargetLowering &TLI =
185 *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
186 const auto &LibInfo =
187 getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(MF.getFunction());
188 auto &LIS = getAnalysis<LiveIntervals>();
189 bool Changed = false;
190
191 // We don't preserve SSA form.
192 MRI.leaveSSA();
193
194 assert(MRI.tracksLiveness() &&
195 "MemIntrinsicResults expects liveness tracking");
196
197 for (auto &MBB : MF) {
198 LLVM_DEBUG(dbgs() << "Basic Block: " << MBB.getName() << '\n');
199 for (auto &MI : MBB)
200 switch (MI.getOpcode()) {
201 default:
202 break;
203 case WebAssembly::CALL:
204 Changed |= optimizeCall(MBB, MI, MRI, MDT, LIS, TLI, LibInfo);
205 break;
206 }
207 }
208
209 return Changed;
210}
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock & MBB
#define LLVM_DEBUG(X)
Definition: Debug.h:101
std::string Name
IRTranslator LLVM IR MI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file provides WebAssembly-specific target descriptions.
This file declares WebAssembly-specific per-machine-function information.
static bool optimizeCall(MachineBasicBlock &MBB, MachineInstr &MI, const MachineRegisterInfo &MRI, MachineDominatorTree &MDT, LiveIntervals &LIS, const WebAssemblyTargetLowering &TLI, const TargetLibraryInfo &LibInfo)
static bool replaceDominatedUses(MachineBasicBlock &MBB, MachineInstr &MI, unsigned FromReg, unsigned ToReg, const MachineRegisterInfo &MRI, MachineDominatorTree &MDT, LiveIntervals &LIS)
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:269
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
LiveInterval - This class represents the liveness of a register, or stack slot.
Definition: LiveInterval.h:687
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
LiveInterval & getInterval(Register Reg)
bool shrinkToUses(LiveInterval *li, SmallVectorImpl< MachineInstr * > *dead=nullptr)
After removing some uses of a register, shrink its live range to just the remaining uses.
void extendToIndices(LiveRange &LR, ArrayRef< SlotIndex > Indices, ArrayRef< SlotIndex > Undefs)
Extend the live range LR to reach all points in Indices.
bool liveAt(SlotIndex index) const
Definition: LiveInterval.h:401
VNInfo * getVNInfoAt(SlotIndex Idx) const
getVNInfoAt - Return the VNInfo that is live at Idx, or NULL.
Definition: LiveInterval.h:421
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
MachineBlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate machine basic b...
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
bool dominates(const MachineDomTreeNode *A, const MachineDomTreeNode *B) const
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
Definition: MachineInstr.h:68
MachineOperand class - Representation of each machine instruction operand.
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
const char * getSymbolName() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
SlotIndex - An opaque wrapper around machine indexes.
Definition: SlotIndexes.h:68
SlotIndex getDeadSlot() const
Returns the dead def kill slot for the current instruction.
Definition: SlotIndexes.h:245
SlotIndex getRegSlot(bool EC=false) const
Returns the register use/def slot in the current instruction for a normal or early-clobber def.
Definition: SlotIndexes.h:240
SlotIndexes pass.
Definition: SlotIndexes.h:300
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Provides information about what library functions are available for the current target.
bool getLibFunc(StringRef funcName, LibFunc &F) const
Searches for a particular function name.
const char * getLibcallName(RTLIB::Libcall Call) const
Get the libcall routine name for the specified libcall.
VNInfo - Value Number Information.
Definition: LiveInterval.h:53
const WebAssemblyRegisterInfo * getRegisterInfo() const override
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition: STLExtras.h:665
FunctionPass * createWebAssemblyMemIntrinsicResults()
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:156