WebAssemblyPeephole.cpp revision 314564
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 "MCTargetDesc/WebAssemblyMCTargetDesc.h" 16#include "WebAssembly.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/MachineInstrBuilder.h" 22#include "llvm/CodeGen/MachineRegisterInfo.h" 23using namespace llvm; 24 25#define DEBUG_TYPE "wasm-peephole" 26 27static cl::opt<bool> DisableWebAssemblyFallthroughReturnOpt( 28 "disable-wasm-fallthrough-return-opt", cl::Hidden, 29 cl::desc("WebAssembly: Disable fallthrough-return optimizations."), 30 cl::init(false)); 31 32namespace { 33class WebAssemblyPeephole final : public MachineFunctionPass { 34 StringRef getPassName() const override { 35 return "WebAssembly late peephole optimizer"; 36 } 37 38 void getAnalysisUsage(AnalysisUsage &AU) const override { 39 AU.setPreservesCFG(); 40 AU.addRequired<TargetLibraryInfoWrapperPass>(); 41 MachineFunctionPass::getAnalysisUsage(AU); 42 } 43 44 bool runOnMachineFunction(MachineFunction &MF) override; 45 46public: 47 static char ID; 48 WebAssemblyPeephole() : MachineFunctionPass(ID) {} 49}; 50} // end anonymous namespace 51 52char WebAssemblyPeephole::ID = 0; 53FunctionPass *llvm::createWebAssemblyPeephole() { 54 return new WebAssemblyPeephole(); 55} 56 57/// If desirable, rewrite NewReg to a drop register. 58static bool MaybeRewriteToDrop(unsigned OldReg, unsigned NewReg, 59 MachineOperand &MO, WebAssemblyFunctionInfo &MFI, 60 MachineRegisterInfo &MRI) { 61 bool Changed = false; 62 if (OldReg == NewReg) { 63 Changed = true; 64 unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg)); 65 MO.setReg(NewReg); 66 MO.setIsDead(); 67 MFI.stackifyVReg(NewReg); 68 } 69 return Changed; 70} 71 72static bool MaybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB, 73 const MachineFunction &MF, 74 WebAssemblyFunctionInfo &MFI, 75 MachineRegisterInfo &MRI, 76 const WebAssemblyInstrInfo &TII, 77 unsigned FallthroughOpc, 78 unsigned CopyLocalOpc) { 79 if (DisableWebAssemblyFallthroughReturnOpt) 80 return false; 81 if (&MBB != &MF.back()) 82 return false; 83 if (&MI != &MBB.back()) 84 return false; 85 86 // If the operand isn't stackified, insert a COPY to read the operand and 87 // stackify it. 88 MachineOperand &MO = MI.getOperand(0); 89 unsigned Reg = MO.getReg(); 90 if (!MFI.isVRegStackified(Reg)) { 91 unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); 92 BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg) 93 .addReg(Reg); 94 MO.setReg(NewReg); 95 MFI.stackifyVReg(NewReg); 96 } 97 98 // Rewrite the return. 99 MI.setDesc(TII.get(FallthroughOpc)); 100 return true; 101} 102 103bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) { 104 DEBUG({ 105 dbgs() << "********** Peephole **********\n" 106 << "********** Function: " << MF.getName() << '\n'; 107 }); 108 109 MachineRegisterInfo &MRI = MF.getRegInfo(); 110 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 111 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 112 const WebAssemblyTargetLowering &TLI = 113 *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 114 auto &LibInfo = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); 115 bool Changed = false; 116 117 for (auto &MBB : MF) 118 for (auto &MI : MBB) 119 switch (MI.getOpcode()) { 120 default: 121 break; 122 case WebAssembly::CALL_I32: 123 case WebAssembly::CALL_I64: { 124 MachineOperand &Op1 = MI.getOperand(1); 125 if (Op1.isSymbol()) { 126 StringRef Name(Op1.getSymbolName()); 127 if (Name == TLI.getLibcallName(RTLIB::MEMCPY) || 128 Name == TLI.getLibcallName(RTLIB::MEMMOVE) || 129 Name == TLI.getLibcallName(RTLIB::MEMSET)) { 130 LibFunc::Func Func; 131 if (LibInfo.getLibFunc(Name, Func)) { 132 const auto &Op2 = MI.getOperand(2); 133 if (!Op2.isReg()) 134 report_fatal_error("Peephole: call to builtin function with " 135 "wrong signature, not consuming reg"); 136 MachineOperand &MO = MI.getOperand(0); 137 unsigned OldReg = MO.getReg(); 138 unsigned NewReg = Op2.getReg(); 139 140 if (MRI.getRegClass(NewReg) != MRI.getRegClass(OldReg)) 141 report_fatal_error("Peephole: call to builtin function with " 142 "wrong signature, from/to mismatch"); 143 Changed |= MaybeRewriteToDrop(OldReg, NewReg, MO, MFI, MRI); 144 } 145 } 146 } 147 break; 148 } 149 // Optimize away an explicit void return at the end of the function. 150 case WebAssembly::RETURN_I32: 151 Changed |= MaybeRewriteToFallthrough( 152 MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_I32, 153 WebAssembly::COPY_I32); 154 break; 155 case WebAssembly::RETURN_I64: 156 Changed |= MaybeRewriteToFallthrough( 157 MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_I64, 158 WebAssembly::COPY_I64); 159 break; 160 case WebAssembly::RETURN_F32: 161 Changed |= MaybeRewriteToFallthrough( 162 MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_F32, 163 WebAssembly::COPY_F32); 164 break; 165 case WebAssembly::RETURN_F64: 166 Changed |= MaybeRewriteToFallthrough( 167 MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_F64, 168 WebAssembly::COPY_F64); 169 break; 170 case WebAssembly::RETURN_v16i8: 171 Changed |= MaybeRewriteToFallthrough( 172 MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v16i8, 173 WebAssembly::COPY_V128); 174 break; 175 case WebAssembly::RETURN_v8i16: 176 Changed |= MaybeRewriteToFallthrough( 177 MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v8i16, 178 WebAssembly::COPY_V128); 179 break; 180 case WebAssembly::RETURN_v4i32: 181 Changed |= MaybeRewriteToFallthrough( 182 MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v4i32, 183 WebAssembly::COPY_V128); 184 break; 185 case WebAssembly::RETURN_v4f32: 186 Changed |= MaybeRewriteToFallthrough( 187 MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_v4f32, 188 WebAssembly::COPY_V128); 189 break; 190 case WebAssembly::RETURN_VOID: 191 if (!DisableWebAssemblyFallthroughReturnOpt && 192 &MBB == &MF.back() && &MI == &MBB.back()) 193 MI.setDesc(TII.get(WebAssembly::FALLTHROUGH_RETURN_VOID)); 194 break; 195 } 196 197 return Changed; 198} 199