1 //===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===// 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 /// This file contains the WebAssembly implementation of the 11 /// TargetInstrInfo class. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "WebAssemblyInstrInfo.h" 16 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 17 #include "WebAssemblyMachineFunctionInfo.h" 18 #include "WebAssemblySubtarget.h" 19 #include "llvm/CodeGen/MachineFrameInfo.h" 20 #include "llvm/CodeGen/MachineInstrBuilder.h" 21 #include "llvm/CodeGen/MachineMemOperand.h" 22 #include "llvm/CodeGen/MachineRegisterInfo.h" 23 using namespace llvm; 24 25 #define DEBUG_TYPE "wasm-instr-info" 26 27 #define GET_INSTRINFO_CTOR_DTOR 28 #include "WebAssemblyGenInstrInfo.inc" 29 30 WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI) 31 : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN, 32 WebAssembly::ADJCALLSTACKUP, 33 WebAssembly::CATCHRET), 34 RI(STI.getTargetTriple()) {} 35 36 bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable( 37 const MachineInstr &MI, AliasAnalysis *AA) const { 38 switch (MI.getOpcode()) { 39 case WebAssembly::CONST_I32: 40 case WebAssembly::CONST_I64: 41 case WebAssembly::CONST_F32: 42 case WebAssembly::CONST_F64: 43 // isReallyTriviallyReMaterializableGeneric misses these because of the 44 // ARGUMENTS implicit def, so we manualy override it here. 45 return true; 46 default: 47 return false; 48 } 49 } 50 51 void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 52 MachineBasicBlock::iterator I, 53 const DebugLoc &DL, unsigned DestReg, 54 unsigned SrcReg, bool KillSrc) const { 55 // This method is called by post-RA expansion, which expects only pregs to 56 // exist. However we need to handle both here. 57 auto &MRI = MBB.getParent()->getRegInfo(); 58 const TargetRegisterClass *RC = 59 TargetRegisterInfo::isVirtualRegister(DestReg) 60 ? MRI.getRegClass(DestReg) 61 : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg); 62 63 unsigned CopyOpcode; 64 if (RC == &WebAssembly::I32RegClass) 65 CopyOpcode = WebAssembly::COPY_I32; 66 else if (RC == &WebAssembly::I64RegClass) 67 CopyOpcode = WebAssembly::COPY_I64; 68 else if (RC == &WebAssembly::F32RegClass) 69 CopyOpcode = WebAssembly::COPY_F32; 70 else if (RC == &WebAssembly::F64RegClass) 71 CopyOpcode = WebAssembly::COPY_F64; 72 else if (RC == &WebAssembly::V128RegClass) 73 CopyOpcode = WebAssembly::COPY_V128; 74 else 75 llvm_unreachable("Unexpected register class"); 76 77 BuildMI(MBB, I, DL, get(CopyOpcode), DestReg) 78 .addReg(SrcReg, KillSrc ? RegState::Kill : 0); 79 } 80 81 MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl( 82 MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const { 83 // If the operands are stackified, we can't reorder them. 84 WebAssemblyFunctionInfo &MFI = 85 *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>(); 86 if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) || 87 MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg())) 88 return nullptr; 89 90 // Otherwise use the default implementation. 91 return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2); 92 } 93 94 // Branch analysis. 95 bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 96 MachineBasicBlock *&TBB, 97 MachineBasicBlock *&FBB, 98 SmallVectorImpl<MachineOperand> &Cond, 99 bool /*AllowModify*/) const { 100 bool HaveCond = false; 101 for (MachineInstr &MI : MBB.terminators()) { 102 switch (MI.getOpcode()) { 103 default: 104 // Unhandled instruction; bail out. 105 return true; 106 case WebAssembly::BR_IF: 107 if (HaveCond) 108 return true; 109 // If we're running after CFGStackify, we can't optimize further. 110 if (!MI.getOperand(0).isMBB()) 111 return true; 112 Cond.push_back(MachineOperand::CreateImm(true)); 113 Cond.push_back(MI.getOperand(1)); 114 TBB = MI.getOperand(0).getMBB(); 115 HaveCond = true; 116 break; 117 case WebAssembly::BR_UNLESS: 118 if (HaveCond) 119 return true; 120 // If we're running after CFGStackify, we can't optimize further. 121 if (!MI.getOperand(0).isMBB()) 122 return true; 123 Cond.push_back(MachineOperand::CreateImm(false)); 124 Cond.push_back(MI.getOperand(1)); 125 TBB = MI.getOperand(0).getMBB(); 126 HaveCond = true; 127 break; 128 case WebAssembly::BR: 129 // If we're running after CFGStackify, we can't optimize further. 130 if (!MI.getOperand(0).isMBB()) 131 return true; 132 if (!HaveCond) 133 TBB = MI.getOperand(0).getMBB(); 134 else 135 FBB = MI.getOperand(0).getMBB(); 136 break; 137 case WebAssembly::BR_ON_EXN: 138 if (HaveCond) 139 return true; 140 // If we're running after CFGStackify, we can't optimize further. 141 if (!MI.getOperand(0).isMBB()) 142 return true; 143 Cond.push_back(MachineOperand::CreateImm(true)); 144 Cond.push_back(MI.getOperand(2)); 145 TBB = MI.getOperand(0).getMBB(); 146 HaveCond = true; 147 break; 148 } 149 if (MI.isBarrier()) 150 break; 151 } 152 153 return false; 154 } 155 156 unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB, 157 int *BytesRemoved) const { 158 assert(!BytesRemoved && "code size not handled"); 159 160 MachineBasicBlock::instr_iterator I = MBB.instr_end(); 161 unsigned Count = 0; 162 163 while (I != MBB.instr_begin()) { 164 --I; 165 if (I->isDebugInstr()) 166 continue; 167 if (!I->isTerminator()) 168 break; 169 // Remove the branch. 170 I->eraseFromParent(); 171 I = MBB.instr_end(); 172 ++Count; 173 } 174 175 return Count; 176 } 177 178 unsigned WebAssemblyInstrInfo::insertBranch( 179 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 180 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 181 assert(!BytesAdded && "code size not handled"); 182 183 if (Cond.empty()) { 184 if (!TBB) 185 return 0; 186 187 BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB); 188 return 1; 189 } 190 191 assert(Cond.size() == 2 && "Expected a flag and a successor block"); 192 193 MachineFunction &MF = *MBB.getParent(); 194 auto &MRI = MF.getRegInfo(); 195 bool IsBrOnExn = Cond[1].isReg() && MRI.getRegClass(Cond[1].getReg()) == 196 &WebAssembly::EXCEPT_REFRegClass; 197 198 if (Cond[0].getImm()) { 199 if (IsBrOnExn) { 200 const char *CPPExnSymbol = MF.createExternalSymbolName("__cpp_exception"); 201 BuildMI(&MBB, DL, get(WebAssembly::BR_ON_EXN)) 202 .addMBB(TBB) 203 .addExternalSymbol(CPPExnSymbol, WebAssemblyII::MO_SYMBOL_EVENT) 204 .add(Cond[1]); 205 } else 206 BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]); 207 } else { 208 assert(!IsBrOnExn && "br_on_exn does not have a reversed condition"); 209 BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]); 210 } 211 if (!FBB) 212 return 1; 213 214 BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB); 215 return 2; 216 } 217 218 bool WebAssemblyInstrInfo::reverseBranchCondition( 219 SmallVectorImpl<MachineOperand> &Cond) const { 220 assert(Cond.size() == 2 && "Expected a flag and a condition expression"); 221 222 // br_on_exn's condition cannot be reversed 223 MachineFunction &MF = *Cond[1].getParent()->getParent()->getParent(); 224 auto &MRI = MF.getRegInfo(); 225 if (Cond[1].isReg() && 226 MRI.getRegClass(Cond[1].getReg()) == &WebAssembly::EXCEPT_REFRegClass) 227 return true; 228 229 Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm()); 230 return false; 231 } 232