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 {
getPassName() const340b57cec5SDimitry Andric StringRef getPassName() const override {
350b57cec5SDimitry Andric return "WebAssembly late peephole optimizer";
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const380b57cec5SDimitry 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;
WebAssemblyPeephole()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
createWebAssemblyPeephole()560b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyPeephole() {
570b57cec5SDimitry Andric return new WebAssemblyPeephole();
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric /// If desirable, rewrite NewReg to a drop register.
maybeRewriteToDrop(unsigned OldReg,unsigned NewReg,MachineOperand & MO,WebAssemblyFunctionInfo & MFI,MachineRegisterInfo & MRI)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
maybeRewriteToFallthrough(MachineInstr & MI,MachineBasicBlock & MBB,const MachineFunction & MF,WebAssemblyFunctionInfo & MFI,MachineRegisterInfo & MRI,const WebAssemblyInstrInfo & TII)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
runOnMachineFunction(MachineFunction & MF)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