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