1 //== WebAssemblyMemIntrinsicResults.cpp - Optimize memory intrinsic results ==//
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
7 //===----------------------------------------------------------------------===//
10 /// This file implements an optimization pass using memory intrinsic results.
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.
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.
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.
27 //===----------------------------------------------------------------------===//
29 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
30 #include "WebAssembly.h"
31 #include "WebAssemblyMachineFunctionInfo.h"
32 #include "WebAssemblySubtarget.h"
33 #include "llvm/Analysis/TargetLibraryInfo.h"
34 #include "llvm/CodeGen/LiveIntervals.h"
35 #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
36 #include "llvm/CodeGen/MachineDominators.h"
37 #include "llvm/CodeGen/MachineRegisterInfo.h"
38 #include "llvm/CodeGen/Passes.h"
39 #include "llvm/Support/Debug.h"
40 #include "llvm/Support/raw_ostream.h"
43 #define DEBUG_TYPE "wasm-mem-intrinsic-results"
46 class WebAssemblyMemIntrinsicResults final
: public MachineFunctionPass
{
48 static char ID
; // Pass identification, replacement for typeid
49 WebAssemblyMemIntrinsicResults() : MachineFunctionPass(ID
) {}
51 StringRef
getPassName() const override
{
52 return "WebAssembly Memory Intrinsic Results";
55 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
57 AU
.addRequired
<MachineBlockFrequencyInfoWrapperPass
>();
58 AU
.addPreserved
<MachineBlockFrequencyInfoWrapperPass
>();
59 AU
.addRequired
<MachineDominatorTreeWrapperPass
>();
60 AU
.addPreserved
<MachineDominatorTreeWrapperPass
>();
61 AU
.addRequired
<LiveIntervalsWrapperPass
>();
62 AU
.addPreserved
<SlotIndexesWrapperPass
>();
63 AU
.addPreserved
<LiveIntervalsWrapperPass
>();
64 AU
.addRequired
<TargetLibraryInfoWrapperPass
>();
65 MachineFunctionPass::getAnalysisUsage(AU
);
68 bool runOnMachineFunction(MachineFunction
&MF
) override
;
72 } // end anonymous namespace
74 char WebAssemblyMemIntrinsicResults::ID
= 0;
75 INITIALIZE_PASS(WebAssemblyMemIntrinsicResults
, DEBUG_TYPE
,
76 "Optimize memory intrinsic result values for WebAssembly",
79 FunctionPass
*llvm::createWebAssemblyMemIntrinsicResults() {
80 return new WebAssemblyMemIntrinsicResults();
83 // Replace uses of FromReg with ToReg if they are dominated by MI.
84 static bool replaceDominatedUses(MachineBasicBlock
&MBB
, MachineInstr
&MI
,
85 unsigned FromReg
, unsigned ToReg
,
86 const MachineRegisterInfo
&MRI
,
87 MachineDominatorTree
&MDT
,
91 LiveInterval
*FromLI
= &LIS
.getInterval(FromReg
);
92 LiveInterval
*ToLI
= &LIS
.getInterval(ToReg
);
94 SlotIndex FromIdx
= LIS
.getInstructionIndex(MI
).getRegSlot();
95 VNInfo
*FromVNI
= FromLI
->getVNInfoAt(FromIdx
);
97 SmallVector
<SlotIndex
, 4> Indices
;
99 for (MachineOperand
&O
:
100 llvm::make_early_inc_range(MRI
.use_nodbg_operands(FromReg
))) {
101 MachineInstr
*Where
= O
.getParent();
103 // Check that MI dominates the instruction in the normal way.
104 if (&MI
== Where
|| !MDT
.dominates(&MI
, Where
))
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
)
113 // Make sure ToReg isn't clobbered before it gets there.
114 VNInfo
*ToVNI
= ToLI
->getVNInfoAt(WhereIdx
);
115 if (ToVNI
&& ToVNI
!= FromVNI
)
119 LLVM_DEBUG(dbgs() << "Setting operand " << O
<< " in " << *Where
<< " from "
123 // If the store's def was previously dead, it is no longer.
125 MI
.getOperand(0).setIsDead(false);
127 Indices
.push_back(WhereIdx
.getRegSlot());
132 // Extend ToReg's liveness.
133 LIS
.extendToIndices(*ToLI
, Indices
);
135 // Shrink FromReg's liveness.
136 LIS
.shrinkToUses(FromLI
);
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()
141 ->getSubtarget
<WebAssemblySubtarget
>()
148 static bool optimizeCall(MachineBasicBlock
&MBB
, MachineInstr
&MI
,
149 const MachineRegisterInfo
&MRI
,
150 MachineDominatorTree
&MDT
, LiveIntervals
&LIS
,
151 const WebAssemblyTargetLowering
&TLI
,
152 const TargetLibraryInfo
&LibInfo
) {
153 MachineOperand
&Op1
= MI
.getOperand(1);
157 StringRef
Name(Op1
.getSymbolName());
158 bool CallReturnsInput
= Name
== TLI
.getLibcallName(RTLIB::MEMCPY
) ||
159 Name
== TLI
.getLibcallName(RTLIB::MEMMOVE
) ||
160 Name
== TLI
.getLibcallName(RTLIB::MEMSET
);
161 if (!CallReturnsInput
)
165 if (!LibInfo
.getLibFunc(Name
, Func
))
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
);
176 bool WebAssemblyMemIntrinsicResults::runOnMachineFunction(MachineFunction
&MF
) {
178 dbgs() << "********** Memory Intrinsic Results **********\n"
179 << "********** Function: " << MF
.getName() << '\n';
182 MachineRegisterInfo
&MRI
= MF
.getRegInfo();
183 auto &MDT
= getAnalysis
<MachineDominatorTreeWrapperPass
>().getDomTree();
184 const WebAssemblyTargetLowering
&TLI
=
185 *MF
.getSubtarget
<WebAssemblySubtarget
>().getTargetLowering();
186 const auto &LibInfo
=
187 getAnalysis
<TargetLibraryInfoWrapperPass
>().getTLI(MF
.getFunction());
188 auto &LIS
= getAnalysis
<LiveIntervalsWrapperPass
>().getLIS();
189 bool Changed
= false;
191 // We don't preserve SSA form.
194 assert(MRI
.tracksLiveness() &&
195 "MemIntrinsicResults expects liveness tracking");
197 for (auto &MBB
: MF
) {
198 LLVM_DEBUG(dbgs() << "Basic Block: " << MBB
.getName() << '\n');
200 switch (MI
.getOpcode()) {
203 case WebAssembly::CALL
:
204 Changed
|= optimizeCall(MBB
, MI
, MRI
, MDT
, LIS
, TLI
, LibInfo
);