1 //===-- WebAssemblyPeephole.cpp - WebAssembly Peephole Optimiztions -------===//
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 /// Late peephole optimizations for WebAssembly.
12 //===----------------------------------------------------------------------===//
14 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
15 #include "WebAssembly.h"
16 #include "WebAssemblyMachineFunctionInfo.h"
17 #include "WebAssemblySubtarget.h"
18 #include "llvm/Analysis/TargetLibraryInfo.h"
19 #include "llvm/CodeGen/MachineFunctionPass.h"
20 #include "llvm/CodeGen/MachineInstrBuilder.h"
21 #include "llvm/CodeGen/MachineRegisterInfo.h"
24 #define DEBUG_TYPE "wasm-peephole"
26 static cl::opt
<bool> DisableWebAssemblyFallthroughReturnOpt(
27 "disable-wasm-fallthrough-return-opt", cl::Hidden
,
28 cl::desc("WebAssembly: Disable fallthrough-return optimizations."),
32 class WebAssemblyPeephole final
: public MachineFunctionPass
{
33 StringRef
getPassName() const override
{
34 return "WebAssembly late peephole optimizer";
37 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
39 AU
.addRequired
<TargetLibraryInfoWrapperPass
>();
40 MachineFunctionPass::getAnalysisUsage(AU
);
43 bool runOnMachineFunction(MachineFunction
&MF
) override
;
47 WebAssemblyPeephole() : MachineFunctionPass(ID
) {}
49 } // end anonymous namespace
51 char WebAssemblyPeephole::ID
= 0;
52 INITIALIZE_PASS(WebAssemblyPeephole
, DEBUG_TYPE
,
53 "WebAssembly peephole optimizations", false, false)
55 FunctionPass
*llvm::createWebAssemblyPeephole() {
56 return new WebAssemblyPeephole();
59 /// If desirable, rewrite NewReg to a drop register.
60 static bool maybeRewriteToDrop(unsigned OldReg
, unsigned NewReg
,
61 MachineOperand
&MO
, WebAssemblyFunctionInfo
&MFI
,
62 MachineRegisterInfo
&MRI
) {
64 if (OldReg
== NewReg
) {
66 Register NewReg
= MRI
.createVirtualRegister(MRI
.getRegClass(OldReg
));
69 MFI
.stackifyVReg(NewReg
);
74 static bool maybeRewriteToFallthrough(MachineInstr
&MI
, MachineBasicBlock
&MBB
,
75 const MachineFunction
&MF
,
76 WebAssemblyFunctionInfo
&MFI
,
77 MachineRegisterInfo
&MRI
,
78 const WebAssemblyInstrInfo
&TII
,
79 unsigned FallthroughOpc
,
80 unsigned CopyLocalOpc
) {
81 if (DisableWebAssemblyFallthroughReturnOpt
)
83 if (&MBB
!= &MF
.back())
86 MachineBasicBlock::iterator End
= MBB
.end();
88 assert(End
->getOpcode() == WebAssembly::END_FUNCTION
);
93 if (FallthroughOpc
!= WebAssembly::FALLTHROUGH_RETURN_VOID
) {
94 // If the operand isn't stackified, insert a COPY to read the operand and
96 MachineOperand
&MO
= MI
.getOperand(0);
97 Register Reg
= MO
.getReg();
98 if (!MFI
.isVRegStackified(Reg
)) {
99 Register NewReg
= MRI
.createVirtualRegister(MRI
.getRegClass(Reg
));
100 BuildMI(MBB
, MI
, MI
.getDebugLoc(), TII
.get(CopyLocalOpc
), NewReg
)
103 MFI
.stackifyVReg(NewReg
);
107 // Rewrite the return.
108 MI
.setDesc(TII
.get(FallthroughOpc
));
112 bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction
&MF
) {
114 dbgs() << "********** Peephole **********\n"
115 << "********** Function: " << MF
.getName() << '\n';
118 MachineRegisterInfo
&MRI
= MF
.getRegInfo();
119 WebAssemblyFunctionInfo
&MFI
= *MF
.getInfo
<WebAssemblyFunctionInfo
>();
120 const auto &TII
= *MF
.getSubtarget
<WebAssemblySubtarget
>().getInstrInfo();
121 const WebAssemblyTargetLowering
&TLI
=
122 *MF
.getSubtarget
<WebAssemblySubtarget
>().getTargetLowering();
124 getAnalysis
<TargetLibraryInfoWrapperPass
>().getTLI(MF
.getFunction());
125 bool Changed
= false;
129 switch (MI
.getOpcode()) {
132 case WebAssembly::CALL_i32
:
133 case WebAssembly::CALL_i64
: {
134 MachineOperand
&Op1
= MI
.getOperand(1);
135 if (Op1
.isSymbol()) {
136 StringRef
Name(Op1
.getSymbolName());
137 if (Name
== TLI
.getLibcallName(RTLIB::MEMCPY
) ||
138 Name
== TLI
.getLibcallName(RTLIB::MEMMOVE
) ||
139 Name
== TLI
.getLibcallName(RTLIB::MEMSET
)) {
141 if (LibInfo
.getLibFunc(Name
, Func
)) {
142 const auto &Op2
= MI
.getOperand(2);
144 report_fatal_error("Peephole: call to builtin function with "
145 "wrong signature, not consuming reg");
146 MachineOperand
&MO
= MI
.getOperand(0);
147 Register OldReg
= MO
.getReg();
148 Register NewReg
= Op2
.getReg();
150 if (MRI
.getRegClass(NewReg
) != MRI
.getRegClass(OldReg
))
151 report_fatal_error("Peephole: call to builtin function with "
152 "wrong signature, from/to mismatch");
153 Changed
|= maybeRewriteToDrop(OldReg
, NewReg
, MO
, MFI
, MRI
);
159 // Optimize away an explicit void return at the end of the function.
160 case WebAssembly::RETURN_I32
:
161 Changed
|= maybeRewriteToFallthrough(
162 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_I32
,
163 WebAssembly::COPY_I32
);
165 case WebAssembly::RETURN_I64
:
166 Changed
|= maybeRewriteToFallthrough(
167 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_I64
,
168 WebAssembly::COPY_I64
);
170 case WebAssembly::RETURN_F32
:
171 Changed
|= maybeRewriteToFallthrough(
172 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_F32
,
173 WebAssembly::COPY_F32
);
175 case WebAssembly::RETURN_F64
:
176 Changed
|= maybeRewriteToFallthrough(
177 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_F64
,
178 WebAssembly::COPY_F64
);
180 case WebAssembly::RETURN_v16i8
:
181 Changed
|= maybeRewriteToFallthrough(
182 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v16i8
,
183 WebAssembly::COPY_V128
);
185 case WebAssembly::RETURN_v8i16
:
186 Changed
|= maybeRewriteToFallthrough(
187 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v8i16
,
188 WebAssembly::COPY_V128
);
190 case WebAssembly::RETURN_v4i32
:
191 Changed
|= maybeRewriteToFallthrough(
192 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v4i32
,
193 WebAssembly::COPY_V128
);
195 case WebAssembly::RETURN_v2i64
:
196 Changed
|= maybeRewriteToFallthrough(
197 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v2i64
,
198 WebAssembly::COPY_V128
);
200 case WebAssembly::RETURN_v4f32
:
201 Changed
|= maybeRewriteToFallthrough(
202 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v4f32
,
203 WebAssembly::COPY_V128
);
205 case WebAssembly::RETURN_v2f64
:
206 Changed
|= maybeRewriteToFallthrough(
207 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v2f64
,
208 WebAssembly::COPY_V128
);
210 case WebAssembly::RETURN_VOID
:
211 Changed
|= maybeRewriteToFallthrough(
212 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_VOID
,
213 WebAssembly::INSTRUCTION_LIST_END
);