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