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