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 /// \brief Late peephole optimizations for WebAssembly.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "WebAssembly.h"
16 #include "MCTargetDesc/WebAssemblyMCTargetDesc.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/MachineRegisterInfo.h"
22 using namespace llvm;
23 
24 #define DEBUG_TYPE "wasm-peephole"
25 
26 namespace {
27 class WebAssemblyPeephole final : public MachineFunctionPass {
28   const char *getPassName() const override {
29     return "WebAssembly late peephole optimizer";
30   }
31 
32   void getAnalysisUsage(AnalysisUsage &AU) const override {
33     AU.setPreservesCFG();
34     AU.addRequired<TargetLibraryInfoWrapperPass>();
35     MachineFunctionPass::getAnalysisUsage(AU);
36   }
37 
38   bool runOnMachineFunction(MachineFunction &MF) override;
39 
40 public:
41   static char ID;
42   WebAssemblyPeephole() : MachineFunctionPass(ID) {}
43 };
44 } // end anonymous namespace
45 
46 char WebAssemblyPeephole::ID = 0;
47 FunctionPass *llvm::createWebAssemblyPeephole() {
48   return new WebAssemblyPeephole();
49 }
50 
51 static const TargetRegisterClass *GetRegClass(const MachineRegisterInfo &MRI,
52                                               unsigned RegNo) {
53   return TargetRegisterInfo::isVirtualRegister(RegNo)
54              ? MRI.getRegClass(RegNo)
55              : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(RegNo);
56 }
57 
58 /// If desirable, rewrite NewReg to a discard register.
59 static bool MaybeRewriteToDiscard(unsigned OldReg, unsigned NewReg,
60                                   MachineOperand &MO,
61                                   WebAssemblyFunctionInfo &MFI,
62                                   MachineRegisterInfo &MRI) {
63   bool Changed = false;
64   if (OldReg == NewReg) {
65     Changed = true;
66     unsigned NewReg = MRI.createVirtualRegister(GetRegClass(MRI, OldReg));
67     MO.setReg(NewReg);
68     MO.setIsDead();
69     MFI.stackifyVReg(NewReg);
70     MFI.addWAReg(NewReg, WebAssemblyFunctionInfo::UnusedReg);
71   }
72   return Changed;
73 }
74 
75 bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
76   DEBUG({
77     dbgs() << "********** Store Results **********\n"
78            << "********** Function: " << MF.getName() << '\n';
79   });
80 
81   MachineRegisterInfo &MRI = MF.getRegInfo();
82   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
83   const WebAssemblyTargetLowering &TLI =
84       *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
85   auto &LibInfo = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
86   bool Changed = false;
87 
88   for (auto &MBB : MF)
89     for (auto &MI : MBB)
90       switch (MI.getOpcode()) {
91       default:
92         break;
93       case WebAssembly::STORE8_I32:
94       case WebAssembly::STORE16_I32:
95       case WebAssembly::STORE8_I64:
96       case WebAssembly::STORE16_I64:
97       case WebAssembly::STORE32_I64:
98       case WebAssembly::STORE_F32:
99       case WebAssembly::STORE_F64:
100       case WebAssembly::STORE_I32:
101       case WebAssembly::STORE_I64: {
102         // Store instructions return their value operand. If we ended up using
103         // the same register for both, replace it with a dead def so that it
104         // can use $discard instead.
105         MachineOperand &MO = MI.getOperand(0);
106         unsigned OldReg = MO.getReg();
107         unsigned NewReg =
108             MI.getOperand(WebAssembly::StoreValueOperandNo).getReg();
109         Changed |= MaybeRewriteToDiscard(OldReg, NewReg, MO, MFI, MRI);
110         break;
111       }
112       case WebAssembly::CALL_I32:
113       case WebAssembly::CALL_I64: {
114         MachineOperand &Op1 = MI.getOperand(1);
115         if (Op1.isSymbol()) {
116           StringRef Name(Op1.getSymbolName());
117           if (Name == TLI.getLibcallName(RTLIB::MEMCPY) ||
118               Name == TLI.getLibcallName(RTLIB::MEMMOVE) ||
119               Name == TLI.getLibcallName(RTLIB::MEMSET)) {
120             LibFunc::Func Func;
121             if (LibInfo.getLibFunc(Name, Func)) {
122               const auto &Op2 = MI.getOperand(2);
123               if (!Op2.isReg())
124                 report_fatal_error("Peephole: call to builtin function with "
125                                    "wrong signature, not consuming reg");
126               MachineOperand &MO = MI.getOperand(0);
127               unsigned OldReg = MO.getReg();
128               unsigned NewReg = Op2.getReg();
129 
130               if (GetRegClass(MRI, NewReg) != GetRegClass(MRI, OldReg))
131                 report_fatal_error("Peephole: call to builtin function with "
132                                    "wrong signature, from/to mismatch");
133               Changed |= MaybeRewriteToDiscard(OldReg, NewReg, MO, MFI, MRI);
134             }
135           }
136         }
137       }
138       }
139 
140   return Changed;
141 }
142