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 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::EXNREFRegClassID
:
115 CopyLocalOpc
= WebAssembly::COPY_EXNREF
;
118 llvm_unreachable("Unexpected register class for return operand");
120 Register NewReg
= MRI
.createVirtualRegister(RegClass
);
121 BuildMI(MBB
, MI
, MI
.getDebugLoc(), TII
.get(CopyLocalOpc
), NewReg
)
124 MFI
.stackifyVReg(NewReg
);
128 MI
.setDesc(TII
.get(WebAssembly::FALLTHROUGH_RETURN
));
132 bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction
&MF
) {
134 dbgs() << "********** Peephole **********\n"
135 << "********** Function: " << MF
.getName() << '\n';
138 MachineRegisterInfo
&MRI
= MF
.getRegInfo();
139 WebAssemblyFunctionInfo
&MFI
= *MF
.getInfo
<WebAssemblyFunctionInfo
>();
140 const auto &TII
= *MF
.getSubtarget
<WebAssemblySubtarget
>().getInstrInfo();
141 const WebAssemblyTargetLowering
&TLI
=
142 *MF
.getSubtarget
<WebAssemblySubtarget
>().getTargetLowering();
144 getAnalysis
<TargetLibraryInfoWrapperPass
>().getTLI(MF
.getFunction());
145 bool Changed
= false;
149 switch (MI
.getOpcode()) {
152 case WebAssembly::CALL_i32
:
153 case WebAssembly::CALL_i64
: {
154 MachineOperand
&Op1
= MI
.getOperand(1);
155 if (Op1
.isSymbol()) {
156 StringRef
Name(Op1
.getSymbolName());
157 if (Name
== TLI
.getLibcallName(RTLIB::MEMCPY
) ||
158 Name
== TLI
.getLibcallName(RTLIB::MEMMOVE
) ||
159 Name
== TLI
.getLibcallName(RTLIB::MEMSET
)) {
161 if (LibInfo
.getLibFunc(Name
, Func
)) {
162 const auto &Op2
= MI
.getOperand(2);
164 report_fatal_error("Peephole: call to builtin function with "
165 "wrong signature, not consuming reg");
166 MachineOperand
&MO
= MI
.getOperand(0);
167 Register OldReg
= MO
.getReg();
168 Register NewReg
= Op2
.getReg();
170 if (MRI
.getRegClass(NewReg
) != MRI
.getRegClass(OldReg
))
171 report_fatal_error("Peephole: call to builtin function with "
172 "wrong signature, from/to mismatch");
173 Changed
|= maybeRewriteToDrop(OldReg
, NewReg
, MO
, MFI
, MRI
);
179 // Optimize away an explicit void return at the end of the function.
180 case WebAssembly::RETURN
:
181 Changed
|= maybeRewriteToFallthrough(MI
, MBB
, MF
, MFI
, MRI
, TII
);