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 unsigned 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 unsigned Reg
= MO
.getReg();
98 if (!MFI
.isVRegStackified(Reg
)) {
99 unsigned 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();
123 auto &LibInfo
= getAnalysis
<TargetLibraryInfoWrapperPass
>().getTLI();
124 bool Changed
= false;
128 switch (MI
.getOpcode()) {
131 case WebAssembly::CALL_i32
:
132 case WebAssembly::CALL_i64
: {
133 MachineOperand
&Op1
= MI
.getOperand(1);
134 if (Op1
.isSymbol()) {
135 StringRef
Name(Op1
.getSymbolName());
136 if (Name
== TLI
.getLibcallName(RTLIB::MEMCPY
) ||
137 Name
== TLI
.getLibcallName(RTLIB::MEMMOVE
) ||
138 Name
== TLI
.getLibcallName(RTLIB::MEMSET
)) {
140 if (LibInfo
.getLibFunc(Name
, Func
)) {
141 const auto &Op2
= MI
.getOperand(2);
143 report_fatal_error("Peephole: call to builtin function with "
144 "wrong signature, not consuming reg");
145 MachineOperand
&MO
= MI
.getOperand(0);
146 unsigned OldReg
= MO
.getReg();
147 unsigned NewReg
= Op2
.getReg();
149 if (MRI
.getRegClass(NewReg
) != MRI
.getRegClass(OldReg
))
150 report_fatal_error("Peephole: call to builtin function with "
151 "wrong signature, from/to mismatch");
152 Changed
|= maybeRewriteToDrop(OldReg
, NewReg
, MO
, MFI
, MRI
);
158 // Optimize away an explicit void return at the end of the function.
159 case WebAssembly::RETURN_I32
:
160 Changed
|= maybeRewriteToFallthrough(
161 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_I32
,
162 WebAssembly::COPY_I32
);
164 case WebAssembly::RETURN_I64
:
165 Changed
|= maybeRewriteToFallthrough(
166 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_I64
,
167 WebAssembly::COPY_I64
);
169 case WebAssembly::RETURN_F32
:
170 Changed
|= maybeRewriteToFallthrough(
171 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_F32
,
172 WebAssembly::COPY_F32
);
174 case WebAssembly::RETURN_F64
:
175 Changed
|= maybeRewriteToFallthrough(
176 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_F64
,
177 WebAssembly::COPY_F64
);
179 case WebAssembly::RETURN_v16i8
:
180 Changed
|= maybeRewriteToFallthrough(
181 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v16i8
,
182 WebAssembly::COPY_V128
);
184 case WebAssembly::RETURN_v8i16
:
185 Changed
|= maybeRewriteToFallthrough(
186 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v8i16
,
187 WebAssembly::COPY_V128
);
189 case WebAssembly::RETURN_v4i32
:
190 Changed
|= maybeRewriteToFallthrough(
191 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v4i32
,
192 WebAssembly::COPY_V128
);
194 case WebAssembly::RETURN_v2i64
:
195 Changed
|= maybeRewriteToFallthrough(
196 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v2i64
,
197 WebAssembly::COPY_V128
);
199 case WebAssembly::RETURN_v4f32
:
200 Changed
|= maybeRewriteToFallthrough(
201 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v4f32
,
202 WebAssembly::COPY_V128
);
204 case WebAssembly::RETURN_v2f64
:
205 Changed
|= maybeRewriteToFallthrough(
206 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_v2f64
,
207 WebAssembly::COPY_V128
);
209 case WebAssembly::RETURN_VOID
:
210 Changed
|= maybeRewriteToFallthrough(
211 MI
, MBB
, MF
, MFI
, MRI
, TII
, WebAssembly::FALLTHROUGH_RETURN_VOID
,
212 WebAssembly::INSTRUCTION_LIST_END
);