10b57cec5SDimitry Andric //===-- WebAssemblyPeephole.cpp - WebAssembly Peephole Optimiztions -------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// Late peephole optimizations for WebAssembly. 110b57cec5SDimitry Andric /// 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 150b57cec5SDimitry Andric #include "WebAssembly.h" 160b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 170b57cec5SDimitry Andric #include "WebAssemblySubtarget.h" 18*5f757f3fSDimitry Andric #include "WebAssemblyUtilities.h" 190b57cec5SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 230b57cec5SDimitry Andric using namespace llvm; 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-peephole" 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric static cl::opt<bool> DisableWebAssemblyFallthroughReturnOpt( 280b57cec5SDimitry Andric "disable-wasm-fallthrough-return-opt", cl::Hidden, 290b57cec5SDimitry Andric cl::desc("WebAssembly: Disable fallthrough-return optimizations."), 300b57cec5SDimitry Andric cl::init(false)); 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric namespace { 330b57cec5SDimitry Andric class WebAssemblyPeephole final : public MachineFunctionPass { 340b57cec5SDimitry Andric StringRef getPassName() const override { 350b57cec5SDimitry Andric return "WebAssembly late peephole optimizer"; 360b57cec5SDimitry Andric } 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 390b57cec5SDimitry Andric AU.setPreservesCFG(); 400b57cec5SDimitry Andric AU.addRequired<TargetLibraryInfoWrapperPass>(); 410b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric public: 470b57cec5SDimitry Andric static char ID; 480b57cec5SDimitry Andric WebAssemblyPeephole() : MachineFunctionPass(ID) {} 490b57cec5SDimitry Andric }; 500b57cec5SDimitry Andric } // end anonymous namespace 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric char WebAssemblyPeephole::ID = 0; 530b57cec5SDimitry Andric INITIALIZE_PASS(WebAssemblyPeephole, DEBUG_TYPE, 540b57cec5SDimitry Andric "WebAssembly peephole optimizations", false, false) 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyPeephole() { 570b57cec5SDimitry Andric return new WebAssemblyPeephole(); 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric /// If desirable, rewrite NewReg to a drop register. 610b57cec5SDimitry Andric static bool maybeRewriteToDrop(unsigned OldReg, unsigned NewReg, 620b57cec5SDimitry Andric MachineOperand &MO, WebAssemblyFunctionInfo &MFI, 630b57cec5SDimitry Andric MachineRegisterInfo &MRI) { 640b57cec5SDimitry Andric bool Changed = false; 650b57cec5SDimitry Andric if (OldReg == NewReg) { 660b57cec5SDimitry Andric Changed = true; 678bcb0991SDimitry Andric Register NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg)); 680b57cec5SDimitry Andric MO.setReg(NewReg); 690b57cec5SDimitry Andric MO.setIsDead(); 705ffd83dbSDimitry Andric MFI.stackifyVReg(MRI, NewReg); 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric return Changed; 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric static bool maybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB, 760b57cec5SDimitry Andric const MachineFunction &MF, 770b57cec5SDimitry Andric WebAssemblyFunctionInfo &MFI, 780b57cec5SDimitry Andric MachineRegisterInfo &MRI, 798bcb0991SDimitry Andric const WebAssemblyInstrInfo &TII) { 800b57cec5SDimitry Andric if (DisableWebAssemblyFallthroughReturnOpt) 810b57cec5SDimitry Andric return false; 820b57cec5SDimitry Andric if (&MBB != &MF.back()) 830b57cec5SDimitry Andric return false; 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric MachineBasicBlock::iterator End = MBB.end(); 860b57cec5SDimitry Andric --End; 870b57cec5SDimitry Andric assert(End->getOpcode() == WebAssembly::END_FUNCTION); 880b57cec5SDimitry Andric --End; 890b57cec5SDimitry Andric if (&MI != &*End) 900b57cec5SDimitry Andric return false; 910b57cec5SDimitry Andric 928bcb0991SDimitry Andric for (auto &MO : MI.explicit_operands()) { 938bcb0991SDimitry Andric // If the operand isn't stackified, insert a COPY to read the operands and 948bcb0991SDimitry Andric // stackify them. 958bcb0991SDimitry Andric Register Reg = MO.getReg(); 960b57cec5SDimitry Andric if (!MFI.isVRegStackified(Reg)) { 978bcb0991SDimitry Andric unsigned CopyLocalOpc; 988bcb0991SDimitry Andric const TargetRegisterClass *RegClass = MRI.getRegClass(Reg); 99753f127fSDimitry Andric CopyLocalOpc = WebAssembly::getCopyOpcodeForRegClass(RegClass); 1008bcb0991SDimitry Andric Register NewReg = MRI.createVirtualRegister(RegClass); 1010b57cec5SDimitry Andric BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg) 1020b57cec5SDimitry Andric .addReg(Reg); 1030b57cec5SDimitry Andric MO.setReg(NewReg); 1045ffd83dbSDimitry Andric MFI.stackifyVReg(MRI, NewReg); 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1088bcb0991SDimitry Andric MI.setDesc(TII.get(WebAssembly::FALLTHROUGH_RETURN)); 1090b57cec5SDimitry Andric return true; 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) { 1130b57cec5SDimitry Andric LLVM_DEBUG({ 1140b57cec5SDimitry Andric dbgs() << "********** Peephole **********\n" 1150b57cec5SDimitry Andric << "********** Function: " << MF.getName() << '\n'; 1160b57cec5SDimitry Andric }); 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 1190b57cec5SDimitry Andric WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 1200b57cec5SDimitry Andric const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1210b57cec5SDimitry Andric const WebAssemblyTargetLowering &TLI = 1220b57cec5SDimitry Andric *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 1238bcb0991SDimitry Andric auto &LibInfo = 1248bcb0991SDimitry Andric getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(MF.getFunction()); 1250b57cec5SDimitry Andric bool Changed = false; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric for (auto &MBB : MF) 1280b57cec5SDimitry Andric for (auto &MI : MBB) 1290b57cec5SDimitry Andric switch (MI.getOpcode()) { 1300b57cec5SDimitry Andric default: 1310b57cec5SDimitry Andric break; 1325ffd83dbSDimitry Andric case WebAssembly::CALL: { 1330b57cec5SDimitry Andric MachineOperand &Op1 = MI.getOperand(1); 1340b57cec5SDimitry Andric if (Op1.isSymbol()) { 1350b57cec5SDimitry Andric StringRef Name(Op1.getSymbolName()); 1360b57cec5SDimitry Andric if (Name == TLI.getLibcallName(RTLIB::MEMCPY) || 1370b57cec5SDimitry Andric Name == TLI.getLibcallName(RTLIB::MEMMOVE) || 1380b57cec5SDimitry Andric Name == TLI.getLibcallName(RTLIB::MEMSET)) { 1390b57cec5SDimitry Andric LibFunc Func; 1400b57cec5SDimitry Andric if (LibInfo.getLibFunc(Name, Func)) { 1410b57cec5SDimitry Andric const auto &Op2 = MI.getOperand(2); 1420b57cec5SDimitry Andric if (!Op2.isReg()) 1430b57cec5SDimitry Andric report_fatal_error("Peephole: call to builtin function with " 1440b57cec5SDimitry Andric "wrong signature, not consuming reg"); 1450b57cec5SDimitry Andric MachineOperand &MO = MI.getOperand(0); 1468bcb0991SDimitry Andric Register OldReg = MO.getReg(); 1478bcb0991SDimitry Andric Register NewReg = Op2.getReg(); 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric if (MRI.getRegClass(NewReg) != MRI.getRegClass(OldReg)) 1500b57cec5SDimitry Andric report_fatal_error("Peephole: call to builtin function with " 1510b57cec5SDimitry Andric "wrong signature, from/to mismatch"); 1520b57cec5SDimitry Andric Changed |= maybeRewriteToDrop(OldReg, NewReg, MO, MFI, MRI); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric break; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric // Optimize away an explicit void return at the end of the function. 1598bcb0991SDimitry Andric case WebAssembly::RETURN: 1608bcb0991SDimitry Andric Changed |= maybeRewriteToFallthrough(MI, MBB, MF, MFI, MRI, TII); 1610b57cec5SDimitry Andric break; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric return Changed; 1650b57cec5SDimitry Andric } 166