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 "WebAssemblyUtilities.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) 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 // TargetInstrInfo::isReallyTriviallyReMaterializable misses these 50 // because of the ARGUMENTS implicit def, so we manualy override it here. 51 return true; 52 default: 53 return TargetInstrInfo::isReallyTriviallyReMaterializable(MI); 54 } 55 } 56 57 void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 58 MachineBasicBlock::iterator I, 59 const DebugLoc &DL, MCRegister DestReg, 60 MCRegister SrcReg, bool KillSrc, 61 bool RenamableDest, 62 bool RenamableSrc) const { 63 // This method is called by post-RA expansion, which expects only pregs to 64 // exist. However we need to handle both here. 65 auto &MRI = MBB.getParent()->getRegInfo(); 66 const TargetRegisterClass *RC = 67 Register::isVirtualRegister(DestReg) 68 ? MRI.getRegClass(DestReg) 69 : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg); 70 71 unsigned CopyOpcode = WebAssembly::getCopyOpcodeForRegClass(RC); 72 73 BuildMI(MBB, I, DL, get(CopyOpcode), DestReg) 74 .addReg(SrcReg, KillSrc ? RegState::Kill : 0); 75 } 76 77 MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl( 78 MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const { 79 // If the operands are stackified, we can't reorder them. 80 WebAssemblyFunctionInfo &MFI = 81 *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>(); 82 if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) || 83 MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg())) 84 return nullptr; 85 86 // Otherwise use the default implementation. 87 return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2); 88 } 89 90 // Branch analysis. 91 bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 92 MachineBasicBlock *&TBB, 93 MachineBasicBlock *&FBB, 94 SmallVectorImpl<MachineOperand> &Cond, 95 bool /*AllowModify*/) const { 96 const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>(); 97 // WebAssembly has control flow that doesn't have explicit branches or direct 98 // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It 99 // is created after CFGStackify. 100 if (MFI.isCFGStackified()) 101 return true; 102 103 bool HaveCond = false; 104 for (MachineInstr &MI : MBB.terminators()) { 105 switch (MI.getOpcode()) { 106 default: 107 // Unhandled instruction; bail out. 108 return true; 109 case WebAssembly::BR_IF: 110 if (HaveCond) 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 Cond.push_back(MachineOperand::CreateImm(false)); 121 Cond.push_back(MI.getOperand(1)); 122 TBB = MI.getOperand(0).getMBB(); 123 HaveCond = true; 124 break; 125 case WebAssembly::BR: 126 if (!HaveCond) 127 TBB = MI.getOperand(0).getMBB(); 128 else 129 FBB = MI.getOperand(0).getMBB(); 130 break; 131 } 132 if (MI.isBarrier()) 133 break; 134 } 135 136 return false; 137 } 138 139 unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB, 140 int *BytesRemoved) const { 141 assert(!BytesRemoved && "code size not handled"); 142 143 MachineBasicBlock::instr_iterator I = MBB.instr_end(); 144 unsigned Count = 0; 145 146 while (I != MBB.instr_begin()) { 147 --I; 148 if (I->isDebugInstr()) 149 continue; 150 if (!I->isTerminator()) 151 break; 152 // Remove the branch. 153 I->eraseFromParent(); 154 I = MBB.instr_end(); 155 ++Count; 156 } 157 158 return Count; 159 } 160 161 unsigned WebAssemblyInstrInfo::insertBranch( 162 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 163 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 164 assert(!BytesAdded && "code size not handled"); 165 166 if (Cond.empty()) { 167 if (!TBB) 168 return 0; 169 170 BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB); 171 return 1; 172 } 173 174 assert(Cond.size() == 2 && "Expected a flag and a successor block"); 175 176 if (Cond[0].getImm()) 177 BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]); 178 else 179 BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]); 180 if (!FBB) 181 return 1; 182 183 BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB); 184 return 2; 185 } 186 187 bool WebAssemblyInstrInfo::reverseBranchCondition( 188 SmallVectorImpl<MachineOperand> &Cond) const { 189 assert(Cond.size() == 2 && "Expected a flag and a condition expression"); 190 Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm()); 191 return false; 192 } 193 194 ArrayRef<std::pair<int, const char *>> 195 WebAssemblyInstrInfo::getSerializableTargetIndices() const { 196 static const std::pair<int, const char *> TargetIndices[] = { 197 {WebAssembly::TI_LOCAL, "wasm-local"}, 198 {WebAssembly::TI_GLOBAL_FIXED, "wasm-global-fixed"}, 199 {WebAssembly::TI_OPERAND_STACK, "wasm-operand-stack"}, 200 {WebAssembly::TI_GLOBAL_RELOC, "wasm-global-reloc"}, 201 {WebAssembly::TI_LOCAL_INDIRECT, "wasm-local-indirect"}}; 202 return ArrayRef(TargetIndices); 203 } 204 205 const MachineOperand & 206 WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr &MI) const { 207 return WebAssembly::getCalleeOp(MI); 208 } 209 210 // This returns true when the instruction defines a value of a TargetIndex 211 // operand that can be tracked by offsets. For Wasm, this returns true for only 212 // local.set/local.tees. This is currently used by LiveDebugValues analysis. 213 // 214 // These are not included: 215 // - In theory we need to add global.set here too, but we don't have global 216 // indices at this point because they are relocatable and we address them by 217 // names until linking, so we don't have 'offsets' (which are used to store 218 // local/global indices) to deal with in LiveDebugValues. And we don't 219 // associate debug info in values in globals anyway. 220 // - All other value-producing instructions, i.e. instructions with defs, can 221 // define values in the Wasm stack, which is represented by TI_OPERAND_STACK 222 // TargetIndex. But they don't have offset info within the instruction itself, 223 // and debug info analysis for them is handled separately in 224 // WebAssemblyDebugFixup pass, so we don't worry about them here. 225 bool WebAssemblyInstrInfo::isExplicitTargetIndexDef(const MachineInstr &MI, 226 int &Index, 227 int64_t &Offset) const { 228 unsigned Opc = MI.getOpcode(); 229 if (WebAssembly::isLocalSet(Opc) || WebAssembly::isLocalTee(Opc)) { 230 Index = WebAssembly::TI_LOCAL; 231 Offset = MI.explicit_uses().begin()->getImm(); 232 return true; 233 } 234 return false; 235 } 236