Line data Source code
1 : //===-- WebAssemblyPeephole.cpp - WebAssembly Peephole Optimiztions -------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : ///
10 : /// \file
11 : /// Late peephole optimizations for WebAssembly.
12 : ///
13 : //===----------------------------------------------------------------------===//
14 :
15 : #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16 : #include "WebAssembly.h"
17 : #include "WebAssemblyMachineFunctionInfo.h"
18 : #include "WebAssemblySubtarget.h"
19 : #include "llvm/Analysis/TargetLibraryInfo.h"
20 : #include "llvm/CodeGen/MachineFunctionPass.h"
21 : #include "llvm/CodeGen/MachineInstrBuilder.h"
22 : #include "llvm/CodeGen/MachineRegisterInfo.h"
23 : using namespace llvm;
24 :
25 : #define DEBUG_TYPE "wasm-peephole"
26 :
27 : static cl::opt<bool> DisableWebAssemblyFallthroughReturnOpt(
28 : "disable-wasm-fallthrough-return-opt", cl::Hidden,
29 : cl::desc("WebAssembly: Disable fallthrough-return optimizations."),
30 : cl::init(false));
31 :
32 : namespace {
33 : class WebAssemblyPeephole final : public MachineFunctionPass {
34 297 : StringRef getPassName() const override {
35 297 : return "WebAssembly late peephole optimizer";
36 : }
37 :
38 297 : void getAnalysisUsage(AnalysisUsage &AU) const override {
39 297 : AU.setPreservesCFG();
40 : AU.addRequired<TargetLibraryInfoWrapperPass>();
41 297 : MachineFunctionPass::getAnalysisUsage(AU);
42 297 : }
43 :
44 : bool runOnMachineFunction(MachineFunction &MF) override;
45 :
46 : public:
47 : static char ID;
48 298 : WebAssemblyPeephole() : MachineFunctionPass(ID) {}
49 : };
50 : } // end anonymous namespace
51 :
52 : char WebAssemblyPeephole::ID = 0;
53 199030 : INITIALIZE_PASS(WebAssemblyPeephole, DEBUG_TYPE,
54 : "WebAssembly peephole optimizations", false, false)
55 :
56 298 : FunctionPass *llvm::createWebAssemblyPeephole() {
57 298 : return new WebAssemblyPeephole();
58 : }
59 :
60 : /// If desirable, rewrite NewReg to a drop register.
61 14 : static bool MaybeRewriteToDrop(unsigned OldReg, unsigned NewReg,
62 : MachineOperand &MO, WebAssemblyFunctionInfo &MFI,
63 : MachineRegisterInfo &MRI) {
64 : bool Changed = false;
65 14 : if (OldReg == NewReg) {
66 : Changed = true;
67 1 : unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg));
68 1 : MO.setReg(NewReg);
69 : MO.setIsDead();
70 1 : MFI.stackifyVReg(NewReg);
71 : }
72 14 : return Changed;
73 : }
74 :
75 2919 : static bool MaybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB,
76 : const MachineFunction &MF,
77 : WebAssemblyFunctionInfo &MFI,
78 : MachineRegisterInfo &MRI,
79 : const WebAssemblyInstrInfo &TII,
80 : unsigned FallthroughOpc,
81 : unsigned CopyLocalOpc) {
82 2919 : if (DisableWebAssemblyFallthroughReturnOpt)
83 : return false;
84 585 : if (&MBB != &MF.back())
85 : return false;
86 :
87 564 : MachineBasicBlock::iterator End = MBB.end();
88 : --End;
89 : assert(End->getOpcode() == WebAssembly::END_FUNCTION);
90 : --End;
91 564 : if (&MI != &*End)
92 : return false;
93 :
94 564 : if (FallthroughOpc != WebAssembly::FALLTHROUGH_RETURN_VOID) {
95 : // If the operand isn't stackified, insert a COPY to read the operand and
96 : // stackify it.
97 376 : MachineOperand &MO = MI.getOperand(0);
98 376 : unsigned Reg = MO.getReg();
99 372 : if (!MFI.isVRegStackified(Reg)) {
100 4 : unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg));
101 8 : BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg)
102 4 : .addReg(Reg);
103 4 : MO.setReg(NewReg);
104 4 : MFI.stackifyVReg(NewReg);
105 : }
106 : }
107 :
108 : // Rewrite the return.
109 564 : MI.setDesc(TII.get(FallthroughOpc));
110 564 : return true;
111 : }
112 :
113 2890 : bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
114 : LLVM_DEBUG({
115 : dbgs() << "********** Peephole **********\n"
116 : << "********** Function: " << MF.getName() << '\n';
117 : });
118 :
119 2890 : MachineRegisterInfo &MRI = MF.getRegInfo();
120 : WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
121 2890 : const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
122 : const WebAssemblyTargetLowering &TLI =
123 : *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
124 2890 : auto &LibInfo = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
125 : bool Changed = false;
126 :
127 6341 : for (auto &MBB : MF)
128 34105 : for (auto &MI : MBB)
129 61308 : switch (MI.getOpcode()) {
130 : default:
131 : break;
132 177 : case WebAssembly::CALL_I32:
133 : case WebAssembly::CALL_I64: {
134 177 : MachineOperand &Op1 = MI.getOperand(1);
135 177 : if (Op1.isSymbol()) {
136 18 : StringRef Name(Op1.getSymbolName());
137 : if (Name == TLI.getLibcallName(RTLIB::MEMCPY) ||
138 : Name == TLI.getLibcallName(RTLIB::MEMMOVE) ||
139 : Name == TLI.getLibcallName(RTLIB::MEMSET)) {
140 : LibFunc Func;
141 14 : if (LibInfo.getLibFunc(Name, Func)) {
142 14 : const auto &Op2 = MI.getOperand(2);
143 14 : if (!Op2.isReg())
144 0 : report_fatal_error("Peephole: call to builtin function with "
145 : "wrong signature, not consuming reg");
146 : MachineOperand &MO = MI.getOperand(0);
147 14 : unsigned OldReg = MO.getReg();
148 14 : unsigned NewReg = Op2.getReg();
149 :
150 14 : if (MRI.getRegClass(NewReg) != MRI.getRegClass(OldReg))
151 0 : report_fatal_error("Peephole: call to builtin function with "
152 : "wrong signature, from/to mismatch");
153 14 : Changed |= MaybeRewriteToDrop(OldReg, NewReg, MO, MFI, MRI);
154 : }
155 : }
156 : }
157 : break;
158 : }
159 : // Optimize away an explicit void return at the end of the function.
160 777 : case WebAssembly::RETURN_I32:
161 777 : Changed |= MaybeRewriteToFallthrough(
162 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_I32,
163 : WebAssembly::COPY_I32);
164 777 : break;
165 218 : case WebAssembly::RETURN_I64:
166 218 : Changed |= MaybeRewriteToFallthrough(
167 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_I64,
168 : WebAssembly::COPY_I64);
169 218 : break;
170 58 : case WebAssembly::RETURN_F32:
171 58 : Changed |= MaybeRewriteToFallthrough(
172 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_F32,
173 : WebAssembly::COPY_F32);
174 58 : break;
175 55 : case WebAssembly::RETURN_F64:
176 55 : Changed |= MaybeRewriteToFallthrough(
177 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_F64,
178 : WebAssembly::COPY_F64);
179 55 : break;
180 147 : case WebAssembly::RETURN_v16i8:
181 147 : Changed |= MaybeRewriteToFallthrough(
182 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v16i8,
183 : WebAssembly::COPY_V128);
184 147 : break;
185 133 : case WebAssembly::RETURN_v8i16:
186 133 : Changed |= MaybeRewriteToFallthrough(
187 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v8i16,
188 : WebAssembly::COPY_V128);
189 133 : break;
190 161 : case WebAssembly::RETURN_v4i32:
191 161 : Changed |= MaybeRewriteToFallthrough(
192 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v4i32,
193 : WebAssembly::COPY_V128);
194 161 : break;
195 89 : case WebAssembly::RETURN_v2i64:
196 89 : Changed |= MaybeRewriteToFallthrough(
197 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v2i64,
198 : WebAssembly::COPY_V128);
199 89 : break;
200 109 : case WebAssembly::RETURN_v4f32:
201 109 : Changed |= MaybeRewriteToFallthrough(
202 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v4f32,
203 : WebAssembly::COPY_V128);
204 109 : break;
205 62 : case WebAssembly::RETURN_v2f64:
206 62 : Changed |= MaybeRewriteToFallthrough(
207 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v2f64,
208 : WebAssembly::COPY_V128);
209 62 : break;
210 1110 : case WebAssembly::RETURN_VOID:
211 1110 : Changed |= MaybeRewriteToFallthrough(
212 : MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_VOID,
213 : WebAssembly::INSTRUCTION_LIST_END);
214 1110 : break;
215 : }
216 :
217 2890 : return Changed;
218 : }
|