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(MRI
, NewReg
);
74 static bool maybeRewriteToFallthrough(MachineInstr
&MI
, MachineBasicBlock
&MBB
,
75 const MachineFunction
&MF
,
76 WebAssemblyFunctionInfo
&MFI
,
77 MachineRegisterInfo
&MRI
,
78 const WebAssemblyInstrInfo
&TII
) {
79 if (DisableWebAssemblyFallthroughReturnOpt
)
81 if (&MBB
!= &MF
.back())
84 MachineBasicBlock::iterator End
= MBB
.end();
86 assert(End
->getOpcode() == WebAssembly::END_FUNCTION
);
91 for (auto &MO
: MI
.explicit_operands()) {
92 // If the operand isn't stackified, insert a COPY to read the operands and
94 Register Reg
= MO
.getReg();
95 if (!MFI
.isVRegStackified(Reg
)) {
96 unsigned CopyLocalOpc
;
97 const TargetRegisterClass
*RegClass
= MRI
.getRegClass(Reg
);
98 switch (RegClass
->getID()) {
99 case WebAssembly::I32RegClassID
:
100 CopyLocalOpc
= WebAssembly::COPY_I32
;
102 case WebAssembly::I64RegClassID
:
103 CopyLocalOpc
= WebAssembly::COPY_I64
;
105 case WebAssembly::F32RegClassID
:
106 CopyLocalOpc
= WebAssembly::COPY_F32
;
108 case WebAssembly::F64RegClassID
:
109 CopyLocalOpc
= WebAssembly::COPY_F64
;
111 case WebAssembly::V128RegClassID
:
112 CopyLocalOpc
= WebAssembly::COPY_V128
;
114 case WebAssembly::FUNCREFRegClassID
:
115 CopyLocalOpc
= WebAssembly::COPY_FUNCREF
;
117 case WebAssembly::EXTERNREFRegClassID
:
118 CopyLocalOpc
= WebAssembly::COPY_EXTERNREF
;
121 llvm_unreachable("Unexpected register class for return operand");
123 Register NewReg
= MRI
.createVirtualRegister(RegClass
);
124 BuildMI(MBB
, MI
, MI
.getDebugLoc(), TII
.get(CopyLocalOpc
), NewReg
)
127 MFI
.stackifyVReg(MRI
, NewReg
);
131 MI
.setDesc(TII
.get(WebAssembly::FALLTHROUGH_RETURN
));
135 bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction
&MF
) {
137 dbgs() << "********** Peephole **********\n"
138 << "********** Function: " << MF
.getName() << '\n';
141 MachineRegisterInfo
&MRI
= MF
.getRegInfo();
142 WebAssemblyFunctionInfo
&MFI
= *MF
.getInfo
<WebAssemblyFunctionInfo
>();
143 const auto &TII
= *MF
.getSubtarget
<WebAssemblySubtarget
>().getInstrInfo();
144 const WebAssemblyTargetLowering
&TLI
=
145 *MF
.getSubtarget
<WebAssemblySubtarget
>().getTargetLowering();
147 getAnalysis
<TargetLibraryInfoWrapperPass
>().getTLI(MF
.getFunction());
148 bool Changed
= false;
152 switch (MI
.getOpcode()) {
155 case WebAssembly::CALL
: {
156 MachineOperand
&Op1
= MI
.getOperand(1);
157 if (Op1
.isSymbol()) {
158 StringRef
Name(Op1
.getSymbolName());
159 if (Name
== TLI
.getLibcallName(RTLIB::MEMCPY
) ||
160 Name
== TLI
.getLibcallName(RTLIB::MEMMOVE
) ||
161 Name
== TLI
.getLibcallName(RTLIB::MEMSET
)) {
163 if (LibInfo
.getLibFunc(Name
, Func
)) {
164 const auto &Op2
= MI
.getOperand(2);
166 report_fatal_error("Peephole: call to builtin function with "
167 "wrong signature, not consuming reg");
168 MachineOperand
&MO
= MI
.getOperand(0);
169 Register OldReg
= MO
.getReg();
170 Register NewReg
= Op2
.getReg();
172 if (MRI
.getRegClass(NewReg
) != MRI
.getRegClass(OldReg
))
173 report_fatal_error("Peephole: call to builtin function with "
174 "wrong signature, from/to mismatch");
175 Changed
|= maybeRewriteToDrop(OldReg
, NewReg
, MO
, MFI
, MRI
);
181 // Optimize away an explicit void return at the end of the function.
182 case WebAssembly::RETURN
:
183 Changed
|= maybeRewriteToFallthrough(MI
, MBB
, MF
, MFI
, MRI
, TII
);