1 //===-- WebAssemblyPeephole.cpp - WebAssembly Peephole Optimiztions -------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// Late peephole optimizations for WebAssembly. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 15 #include "WebAssembly.h" 16 #include "WebAssemblyMachineFunctionInfo.h" 17 #include "WebAssemblySubtarget.h" 18 #include "llvm/Analysis/TargetLibraryInfo.h" 19 #include "llvm/CodeGen/MachineFunctionPass.h" 20 #include "llvm/CodeGen/MachineInstrBuilder.h" 21 #include "llvm/CodeGen/MachineRegisterInfo.h" 22 using namespace llvm; 23 24 #define DEBUG_TYPE "wasm-peephole" 25 26 static cl::opt<bool> DisableWebAssemblyFallthroughReturnOpt( 27 "disable-wasm-fallthrough-return-opt", cl::Hidden, 28 cl::desc("WebAssembly: Disable fallthrough-return optimizations."), 29 cl::init(false)); 30 31 namespace { 32 class WebAssemblyPeephole final : public MachineFunctionPass { 33 StringRef getPassName() const override { 34 return "WebAssembly late peephole optimizer"; 35 } 36 37 void getAnalysisUsage(AnalysisUsage &AU) const override { 38 AU.setPreservesCFG(); 39 AU.addRequired<TargetLibraryInfoWrapperPass>(); 40 MachineFunctionPass::getAnalysisUsage(AU); 41 } 42 43 bool runOnMachineFunction(MachineFunction &MF) override; 44 45 public: 46 static char ID; 47 WebAssemblyPeephole() : MachineFunctionPass(ID) {} 48 }; 49 } // end anonymous namespace 50 51 char WebAssemblyPeephole::ID = 0; 52 INITIALIZE_PASS(WebAssemblyPeephole, DEBUG_TYPE, 53 "WebAssembly peephole optimizations", false, false) 54 55 FunctionPass *llvm::createWebAssemblyPeephole() { 56 return new WebAssemblyPeephole(); 57 } 58 59 /// If desirable, rewrite NewReg to a drop register. 60 static bool maybeRewriteToDrop(unsigned OldReg, unsigned NewReg, 61 MachineOperand &MO, WebAssemblyFunctionInfo &MFI, 62 MachineRegisterInfo &MRI) { 63 bool Changed = false; 64 if (OldReg == NewReg) { 65 Changed = true; 66 Register NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg)); 67 MO.setReg(NewReg); 68 MO.setIsDead(); 69 MFI.stackifyVReg(MRI, NewReg); 70 } 71 return Changed; 72 } 73 74 static bool maybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB, 75 const MachineFunction &MF, 76 WebAssemblyFunctionInfo &MFI, 77 MachineRegisterInfo &MRI, 78 const WebAssemblyInstrInfo &TII) { 79 if (DisableWebAssemblyFallthroughReturnOpt) 80 return false; 81 if (&MBB != &MF.back()) 82 return false; 83 84 MachineBasicBlock::iterator End = MBB.end(); 85 --End; 86 assert(End->getOpcode() == WebAssembly::END_FUNCTION); 87 --End; 88 if (&MI != &*End) 89 return false; 90 91 for (auto &MO : MI.explicit_operands()) { 92 // If the operand isn't stackified, insert a COPY to read the operands and 93 // stackify them. 94 Register Reg = MO.getReg(); 95 if (!MFI.isVRegStackified(Reg)) { 96 unsigned CopyLocalOpc; 97 const TargetRegisterClass *RegClass = MRI.getRegClass(Reg); 98 switch (RegClass->getID()) { 99 case WebAssembly::I32RegClassID: 100 CopyLocalOpc = WebAssembly::COPY_I32; 101 break; 102 case WebAssembly::I64RegClassID: 103 CopyLocalOpc = WebAssembly::COPY_I64; 104 break; 105 case WebAssembly::F32RegClassID: 106 CopyLocalOpc = WebAssembly::COPY_F32; 107 break; 108 case WebAssembly::F64RegClassID: 109 CopyLocalOpc = WebAssembly::COPY_F64; 110 break; 111 case WebAssembly::V128RegClassID: 112 CopyLocalOpc = WebAssembly::COPY_V128; 113 break; 114 case WebAssembly::FUNCREFRegClassID: 115 CopyLocalOpc = WebAssembly::COPY_FUNCREF; 116 break; 117 case WebAssembly::EXTERNREFRegClassID: 118 CopyLocalOpc = WebAssembly::COPY_EXTERNREF; 119 break; 120 default: 121 llvm_unreachable("Unexpected register class for return operand"); 122 } 123 Register NewReg = MRI.createVirtualRegister(RegClass); 124 BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg) 125 .addReg(Reg); 126 MO.setReg(NewReg); 127 MFI.stackifyVReg(MRI, NewReg); 128 } 129 } 130 131 MI.setDesc(TII.get(WebAssembly::FALLTHROUGH_RETURN)); 132 return true; 133 } 134 135 bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) { 136 LLVM_DEBUG({ 137 dbgs() << "********** Peephole **********\n" 138 << "********** Function: " << MF.getName() << '\n'; 139 }); 140 141 MachineRegisterInfo &MRI = MF.getRegInfo(); 142 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 143 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 144 const WebAssemblyTargetLowering &TLI = 145 *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 146 auto &LibInfo = 147 getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(MF.getFunction()); 148 bool Changed = false; 149 150 for (auto &MBB : MF) 151 for (auto &MI : MBB) 152 switch (MI.getOpcode()) { 153 default: 154 break; 155 case WebAssembly::CALL: { 156 MachineOperand &Op1 = MI.getOperand(1); 157 if (Op1.isSymbol()) { 158 StringRef Name(Op1.getSymbolName()); 159 if (Name == TLI.getLibcallName(RTLIB::MEMCPY) || 160 Name == TLI.getLibcallName(RTLIB::MEMMOVE) || 161 Name == TLI.getLibcallName(RTLIB::MEMSET)) { 162 LibFunc Func; 163 if (LibInfo.getLibFunc(Name, Func)) { 164 const auto &Op2 = MI.getOperand(2); 165 if (!Op2.isReg()) 166 report_fatal_error("Peephole: call to builtin function with " 167 "wrong signature, not consuming reg"); 168 MachineOperand &MO = MI.getOperand(0); 169 Register OldReg = MO.getReg(); 170 Register NewReg = Op2.getReg(); 171 172 if (MRI.getRegClass(NewReg) != MRI.getRegClass(OldReg)) 173 report_fatal_error("Peephole: call to builtin function with " 174 "wrong signature, from/to mismatch"); 175 Changed |= maybeRewriteToDrop(OldReg, NewReg, MO, MFI, MRI); 176 } 177 } 178 } 179 break; 180 } 181 // Optimize away an explicit void return at the end of the function. 182 case WebAssembly::RETURN: 183 Changed |= maybeRewriteToFallthrough(MI, MBB, MF, MFI, MRI, TII); 184 break; 185 } 186 187 return Changed; 188 } 189