1 //===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// This file contains the WebAssembly implementation of the 12 /// TargetInstrInfo class. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #include "WebAssemblyInstrInfo.h" 17 #include "MCTargetDesc/WebAssemblyMCTargetDesc.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 WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI) 32 : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN, 33 WebAssembly::ADJCALLSTACKUP, 34 WebAssembly::CATCHRET), 35 RI(STI.getTargetTriple()) {} 36 37 bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable( 38 const MachineInstr &MI, AliasAnalysis *AA) const { 39 switch (MI.getOpcode()) { 40 case WebAssembly::CONST_I32: 41 case WebAssembly::CONST_I64: 42 case WebAssembly::CONST_F32: 43 case WebAssembly::CONST_F64: 44 // isReallyTriviallyReMaterializableGeneric misses these because of the 45 // ARGUMENTS implicit def, so we manualy override it here. 46 return true; 47 default: 48 return false; 49 } 50 } 51 52 void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 53 MachineBasicBlock::iterator I, 54 const DebugLoc &DL, unsigned DestReg, 55 unsigned SrcReg, bool KillSrc) const { 56 // This method is called by post-RA expansion, which expects only pregs to 57 // exist. However we need to handle both here. 58 auto &MRI = MBB.getParent()->getRegInfo(); 59 const TargetRegisterClass *RC = 60 TargetRegisterInfo::isVirtualRegister(DestReg) 61 ? MRI.getRegClass(DestReg) 62 : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg); 63 64 unsigned CopyOpcode; 65 if (RC == &WebAssembly::I32RegClass) 66 CopyOpcode = WebAssembly::COPY_I32; 67 else if (RC == &WebAssembly::I64RegClass) 68 CopyOpcode = WebAssembly::COPY_I64; 69 else if (RC == &WebAssembly::F32RegClass) 70 CopyOpcode = WebAssembly::COPY_F32; 71 else if (RC == &WebAssembly::F64RegClass) 72 CopyOpcode = WebAssembly::COPY_F64; 73 else if (RC == &WebAssembly::V128RegClass) 74 CopyOpcode = WebAssembly::COPY_V128; 75 else 76 llvm_unreachable("Unexpected register class"); 77 78 BuildMI(MBB, I, DL, get(CopyOpcode), DestReg) 79 .addReg(SrcReg, KillSrc ? RegState::Kill : 0); 80 } 81 82 MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl( 83 MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const { 84 // If the operands are stackified, we can't reorder them. 85 WebAssemblyFunctionInfo &MFI = 86 *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>(); 87 if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) || 88 MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg())) 89 return nullptr; 90 91 // Otherwise use the default implementation. 92 return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2); 93 } 94 95 // Branch analysis. 96 bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 97 MachineBasicBlock *&TBB, 98 MachineBasicBlock *&FBB, 99 SmallVectorImpl<MachineOperand> &Cond, 100 bool /*AllowModify*/) const { 101 bool HaveCond = false; 102 for (MachineInstr &MI : MBB.terminators()) { 103 switch (MI.getOpcode()) { 104 default: 105 // Unhandled instruction; bail out. 106 return true; 107 case WebAssembly::BR_IF: 108 if (HaveCond) 109 return true; 110 // If we're running after CFGStackify, we can't optimize further. 111 if (!MI.getOperand(0).isMBB()) 112 return true; 113 Cond.push_back(MachineOperand::CreateImm(true)); 114 Cond.push_back(MI.getOperand(1)); 115 TBB = MI.getOperand(0).getMBB(); 116 HaveCond = true; 117 break; 118 case WebAssembly::BR_UNLESS: 119 if (HaveCond) 120 return true; 121 // If we're running after CFGStackify, we can't optimize further. 122 if (!MI.getOperand(0).isMBB()) 123 return true; 124 Cond.push_back(MachineOperand::CreateImm(false)); 125 Cond.push_back(MI.getOperand(1)); 126 TBB = MI.getOperand(0).getMBB(); 127 HaveCond = true; 128 break; 129 case WebAssembly::BR: 130 // If we're running after CFGStackify, we can't optimize further. 131 if (!MI.getOperand(0).isMBB()) 132 return true; 133 if (!HaveCond) 134 TBB = MI.getOperand(0).getMBB(); 135 else 136 FBB = MI.getOperand(0).getMBB(); 137 break; 138 } 139 if (MI.isBarrier()) 140 break; 141 } 142 143 return false; 144 } 145 146 unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB, 147 int *BytesRemoved) const { 148 assert(!BytesRemoved && "code size not handled"); 149 150 MachineBasicBlock::instr_iterator I = MBB.instr_end(); 151 unsigned Count = 0; 152 153 while (I != MBB.instr_begin()) { 154 --I; 155 if (I->isDebugInstr()) 156 continue; 157 if (!I->isTerminator()) 158 break; 159 // Remove the branch. 160 I->eraseFromParent(); 161 I = MBB.instr_end(); 162 ++Count; 163 } 164 165 return Count; 166 } 167 168 unsigned WebAssemblyInstrInfo::insertBranch( 169 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 170 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 171 assert(!BytesAdded && "code size not handled"); 172 173 if (Cond.empty()) { 174 if (!TBB) 175 return 0; 176 177 BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB); 178 return 1; 179 } 180 181 assert(Cond.size() == 2 && "Expected a flag and a successor block"); 182 183 if (Cond[0].getImm()) { 184 BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]); 185 } else { 186 BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]); 187 } 188 if (!FBB) 189 return 1; 190 191 BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB); 192 return 2; 193 } 194 195 bool WebAssemblyInstrInfo::reverseBranchCondition( 196 SmallVectorImpl<MachineOperand> &Cond) const { 197 assert(Cond.size() == 2 && "Expected a flag and a successor block"); 198 Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm()); 199 return false; 200 } 201