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 /// If desirable, rewrite NewReg to a discard register. 52 static bool MaybeRewriteToDiscard(unsigned OldReg, unsigned NewReg, 53 MachineOperand &MO, 54 WebAssemblyFunctionInfo &MFI, 55 MachineRegisterInfo &MRI) { 56 bool Changed = false; 57 // TODO: Handle SP/physregs 58 if (OldReg == NewReg && TargetRegisterInfo::isVirtualRegister(NewReg)) { 59 Changed = true; 60 unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg)); 61 MO.setReg(NewReg); 62 MO.setIsDead(); 63 MFI.stackifyVReg(NewReg); 64 MFI.addWAReg(NewReg, WebAssemblyFunctionInfo::UnusedReg); 65 } 66 return Changed; 67 } 68 69 bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) { 70 DEBUG({ 71 dbgs() << "********** Store Results **********\n" 72 << "********** Function: " << MF.getName() << '\n'; 73 }); 74 75 MachineRegisterInfo &MRI = MF.getRegInfo(); 76 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 77 const WebAssemblyTargetLowering &TLI = 78 *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 79 auto &LibInfo = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); 80 bool Changed = false; 81 82 for (auto &MBB : MF) 83 for (auto &MI : MBB) 84 switch (MI.getOpcode()) { 85 default: 86 break; 87 case WebAssembly::STORE8_I32: 88 case WebAssembly::STORE16_I32: 89 case WebAssembly::STORE8_I64: 90 case WebAssembly::STORE16_I64: 91 case WebAssembly::STORE32_I64: 92 case WebAssembly::STORE_F32: 93 case WebAssembly::STORE_F64: 94 case WebAssembly::STORE_I32: 95 case WebAssembly::STORE_I64: { 96 // Store instructions return their value operand. If we ended up using 97 // the same register for both, replace it with a dead def so that it 98 // can use $discard instead. 99 MachineOperand &MO = MI.getOperand(0); 100 unsigned OldReg = MO.getReg(); 101 unsigned NewReg = 102 MI.getOperand(WebAssembly::StoreValueOperandNo).getReg(); 103 Changed |= MaybeRewriteToDiscard(OldReg, NewReg, MO, MFI, MRI); 104 break; 105 } 106 case WebAssembly::CALL_I32: 107 case WebAssembly::CALL_I64: { 108 MachineOperand &Op1 = MI.getOperand(1); 109 if (Op1.isSymbol()) { 110 StringRef Name(Op1.getSymbolName()); 111 if (Name == TLI.getLibcallName(RTLIB::MEMCPY) || 112 Name == TLI.getLibcallName(RTLIB::MEMMOVE) || 113 Name == TLI.getLibcallName(RTLIB::MEMSET)) { 114 LibFunc::Func Func; 115 if (LibInfo.getLibFunc(Name, Func)) { 116 const auto &Op2 = MI.getOperand(2); 117 if (!Op2.isReg()) 118 report_fatal_error("Peephole: call to builtin function with " 119 "wrong signature, not consuming reg"); 120 MachineOperand &MO = MI.getOperand(0); 121 unsigned OldReg = MO.getReg(); 122 unsigned NewReg = Op2.getReg(); 123 124 // TODO: Handle SP/physregs in MaybeRewriteToDiscard 125 if (TargetRegisterInfo::isVirtualRegister(NewReg) && 126 (MRI.getRegClass(NewReg) != MRI.getRegClass(OldReg))) 127 report_fatal_error("Peephole: call to builtin function with " 128 "wrong signature, from/to mismatch"); 129 Changed |= MaybeRewriteToDiscard(OldReg, NewReg, MO, MFI, MRI); 130 } 131 } 132 } 133 } 134 } 135 136 return Changed; 137 } 138