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