xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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