181719f85SDan Gohman //===-- WebAssemblyPeephole.cpp - WebAssembly Peephole Optimiztions -------===//
281719f85SDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681719f85SDan Gohman //
781719f85SDan Gohman //===----------------------------------------------------------------------===//
881719f85SDan Gohman ///
981719f85SDan Gohman /// \file
105f8f34e4SAdrian Prantl /// Late peephole optimizations for WebAssembly.
1181719f85SDan Gohman ///
1281719f85SDan Gohman //===----------------------------------------------------------------------===//
1381719f85SDan Gohman
1481719f85SDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
15*beec3e8cSAlex Bradbury #include "Utils/WebAssemblyUtilities.h"
16b7c2400fSDan Gohman #include "WebAssembly.h"
1781719f85SDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
18bdf08d5dSDan Gohman #include "WebAssemblySubtarget.h"
19bdf08d5dSDan Gohman #include "llvm/Analysis/TargetLibraryInfo.h"
2081719f85SDan Gohman #include "llvm/CodeGen/MachineFunctionPass.h"
21b7c2400fSDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h"
22bdf08d5dSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
2381719f85SDan Gohman using namespace llvm;
2481719f85SDan Gohman
2581719f85SDan Gohman #define DEBUG_TYPE "wasm-peephole"
2681719f85SDan Gohman
27b7c2400fSDan Gohman static cl::opt<bool> DisableWebAssemblyFallthroughReturnOpt(
28b7c2400fSDan Gohman "disable-wasm-fallthrough-return-opt", cl::Hidden,
29b7c2400fSDan Gohman cl::desc("WebAssembly: Disable fallthrough-return optimizations."),
30b7c2400fSDan Gohman cl::init(false));
31b7c2400fSDan Gohman
3281719f85SDan Gohman namespace {
3381719f85SDan Gohman class WebAssemblyPeephole final : public MachineFunctionPass {
getPassName() const34117296c0SMehdi Amini StringRef getPassName() const override {
3581719f85SDan Gohman return "WebAssembly late peephole optimizer";
3681719f85SDan Gohman }
3781719f85SDan Gohman
getAnalysisUsage(AnalysisUsage & AU) const38acc0941bSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override {
39acc0941bSDan Gohman AU.setPreservesCFG();
40bdf08d5dSDan Gohman AU.addRequired<TargetLibraryInfoWrapperPass>();
41acc0941bSDan Gohman MachineFunctionPass::getAnalysisUsage(AU);
42acc0941bSDan Gohman }
43acc0941bSDan Gohman
4481719f85SDan Gohman bool runOnMachineFunction(MachineFunction &MF) override;
4581719f85SDan Gohman
4681719f85SDan Gohman public:
4781719f85SDan Gohman static char ID;
WebAssemblyPeephole()4881719f85SDan Gohman WebAssemblyPeephole() : MachineFunctionPass(ID) {}
4981719f85SDan Gohman };
5081719f85SDan Gohman } // end anonymous namespace
5181719f85SDan Gohman
5281719f85SDan Gohman char WebAssemblyPeephole::ID = 0;
5340926451SJacob Gravelle INITIALIZE_PASS(WebAssemblyPeephole, DEBUG_TYPE,
5440926451SJacob Gravelle "WebAssembly peephole optimizations", false, false)
5540926451SJacob Gravelle
createWebAssemblyPeephole()5681719f85SDan Gohman FunctionPass *llvm::createWebAssemblyPeephole() {
5781719f85SDan Gohman return new WebAssemblyPeephole();
5881719f85SDan Gohman }
5981719f85SDan Gohman
6071008090SDan Gohman /// If desirable, rewrite NewReg to a drop register.
maybeRewriteToDrop(unsigned OldReg,unsigned NewReg,MachineOperand & MO,WebAssemblyFunctionInfo & MFI,MachineRegisterInfo & MRI)6118c56a07SHeejin Ahn static bool maybeRewriteToDrop(unsigned OldReg, unsigned NewReg,
62b7c2400fSDan Gohman MachineOperand &MO, WebAssemblyFunctionInfo &MFI,
63bdf08d5dSDan Gohman MachineRegisterInfo &MRI) {
6481719f85SDan Gohman bool Changed = false;
6527a11eefSDan Gohman if (OldReg == NewReg) {
66bdf08d5dSDan Gohman Changed = true;
6705c145d6SDaniel Sanders Register NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg));
68bdf08d5dSDan Gohman MO.setReg(NewReg);
69bdf08d5dSDan Gohman MO.setIsDead();
70c5d24009SMatt Arsenault MFI.stackifyVReg(MRI, NewReg);
71bdf08d5dSDan Gohman }
72bdf08d5dSDan Gohman return Changed;
73bdf08d5dSDan Gohman }
74bdf08d5dSDan Gohman
maybeRewriteToFallthrough(MachineInstr & MI,MachineBasicBlock & MBB,const MachineFunction & MF,WebAssemblyFunctionInfo & MFI,MachineRegisterInfo & MRI,const WebAssemblyInstrInfo & TII)7518c56a07SHeejin Ahn static bool maybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB,
76b7c2400fSDan Gohman const MachineFunction &MF,
77b7c2400fSDan Gohman WebAssemblyFunctionInfo &MFI,
78b7c2400fSDan Gohman MachineRegisterInfo &MRI,
7900f9e5aaSThomas Lively const WebAssemblyInstrInfo &TII) {
80b7c2400fSDan Gohman if (DisableWebAssemblyFallthroughReturnOpt)
81b7c2400fSDan Gohman return false;
82b7c2400fSDan Gohman if (&MBB != &MF.back())
83b7c2400fSDan Gohman return false;
84cf2a9e28SSam Clegg
85d934cb88SDan Gohman MachineBasicBlock::iterator End = MBB.end();
86d934cb88SDan Gohman --End;
87d934cb88SDan Gohman assert(End->getOpcode() == WebAssembly::END_FUNCTION);
88d934cb88SDan Gohman --End;
89d934cb88SDan Gohman if (&MI != &*End)
90d934cb88SDan Gohman return false;
91b7c2400fSDan Gohman
9200f9e5aaSThomas Lively for (auto &MO : MI.explicit_operands()) {
9300f9e5aaSThomas Lively // If the operand isn't stackified, insert a COPY to read the operands and
9400f9e5aaSThomas Lively // stackify them.
9505c145d6SDaniel Sanders Register Reg = MO.getReg();
96b7c2400fSDan Gohman if (!MFI.isVRegStackified(Reg)) {
9700f9e5aaSThomas Lively unsigned CopyLocalOpc;
9800f9e5aaSThomas Lively const TargetRegisterClass *RegClass = MRI.getRegClass(Reg);
99*beec3e8cSAlex Bradbury CopyLocalOpc = WebAssembly::getCopyOpcodeForRegClass(RegClass);
10000f9e5aaSThomas Lively Register NewReg = MRI.createVirtualRegister(RegClass);
101b7c2400fSDan Gohman BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg)
102b7c2400fSDan Gohman .addReg(Reg);
103b7c2400fSDan Gohman MO.setReg(NewReg);
104c5d24009SMatt Arsenault MFI.stackifyVReg(MRI, NewReg);
105b7c2400fSDan Gohman }
106b6afd207SDan Gohman }
107b7c2400fSDan Gohman
10800f9e5aaSThomas Lively MI.setDesc(TII.get(WebAssembly::FALLTHROUGH_RETURN));
109b7c2400fSDan Gohman return true;
110b7c2400fSDan Gohman }
111b7c2400fSDan Gohman
runOnMachineFunction(MachineFunction & MF)112bdf08d5dSDan Gohman bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
113d34e60caSNicola Zaghen LLVM_DEBUG({
114b7c2400fSDan Gohman dbgs() << "********** Peephole **********\n"
115bdf08d5dSDan Gohman << "********** Function: " << MF.getName() << '\n';
116bdf08d5dSDan Gohman });
11781719f85SDan Gohman
11881719f85SDan Gohman MachineRegisterInfo &MRI = MF.getRegInfo();
11981719f85SDan Gohman WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
1205629ec14SDerek Schuff const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
121bdf08d5dSDan Gohman const WebAssemblyTargetLowering &TLI =
122bdf08d5dSDan Gohman *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
1239c27b59cSTeresa Johnson auto &LibInfo =
1249c27b59cSTeresa Johnson getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(MF.getFunction());
125bdf08d5dSDan Gohman bool Changed = false;
12681719f85SDan Gohman
12781719f85SDan Gohman for (auto &MBB : MF)
12881719f85SDan Gohman for (auto &MI : MBB)
12981719f85SDan Gohman switch (MI.getOpcode()) {
13081719f85SDan Gohman default:
13181719f85SDan Gohman break;
132ca9ba764SThomas Lively case WebAssembly::CALL: {
133bdf08d5dSDan Gohman MachineOperand &Op1 = MI.getOperand(1);
134bdf08d5dSDan Gohman if (Op1.isSymbol()) {
135bdf08d5dSDan Gohman StringRef Name(Op1.getSymbolName());
136bdf08d5dSDan Gohman if (Name == TLI.getLibcallName(RTLIB::MEMCPY) ||
137bdf08d5dSDan Gohman Name == TLI.getLibcallName(RTLIB::MEMMOVE) ||
138bdf08d5dSDan Gohman Name == TLI.getLibcallName(RTLIB::MEMSET)) {
1394b320b72SDerek Schuff LibFunc Func;
140bdf08d5dSDan Gohman if (LibInfo.getLibFunc(Name, Func)) {
1411a6c7608SJF Bastien const auto &Op2 = MI.getOperand(2);
142e7305cc4SDerek Schuff if (!Op2.isReg())
143e7305cc4SDerek Schuff report_fatal_error("Peephole: call to builtin function with "
144e7305cc4SDerek Schuff "wrong signature, not consuming reg");
145bdf08d5dSDan Gohman MachineOperand &MO = MI.getOperand(0);
14605c145d6SDaniel Sanders Register OldReg = MO.getReg();
14705c145d6SDaniel Sanders Register NewReg = Op2.getReg();
14890d9e8d3SDerek Schuff
149847afa22SDan Gohman if (MRI.getRegClass(NewReg) != MRI.getRegClass(OldReg))
1501a6c7608SJF Bastien report_fatal_error("Peephole: call to builtin function with "
1511a6c7608SJF Bastien "wrong signature, from/to mismatch");
15218c56a07SHeejin Ahn Changed |= maybeRewriteToDrop(OldReg, NewReg, MO, MFI, MRI);
153bdf08d5dSDan Gohman }
154bdf08d5dSDan Gohman }
15581719f85SDan Gohman }
156b7c2400fSDan Gohman break;
15781719f85SDan Gohman }
158b7c2400fSDan Gohman // Optimize away an explicit void return at the end of the function.
15900f9e5aaSThomas Lively case WebAssembly::RETURN:
16000f9e5aaSThomas Lively Changed |= maybeRewriteToFallthrough(MI, MBB, MF, MFI, MRI, TII);
161b7c2400fSDan Gohman break;
16281719f85SDan Gohman }
16381719f85SDan Gohman
16481719f85SDan Gohman return Changed;
16581719f85SDan Gohman }
166