1 //===-- SPIRVInstrInfo.cpp - SPIR-V Instruction Information ------*- C++-*-===// 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 // This file contains the SPIR-V implementation of the TargetInstrInfo class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "SPIRVInstrInfo.h" 14 #include "SPIRV.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 17 #include "llvm/CodeGen/MachineBasicBlock.h" 18 #include "llvm/IR/DebugLoc.h" 19 #include "llvm/Support/ErrorHandling.h" 20 21 #define GET_INSTRINFO_CTOR_DTOR 22 #include "SPIRVGenInstrInfo.inc" 23 24 using namespace llvm; 25 26 SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {} 27 28 bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const { 29 switch (MI.getOpcode()) { 30 case SPIRV::OpConstantTrue: 31 case SPIRV::OpConstantFalse: 32 case SPIRV::OpConstantI: 33 case SPIRV::OpConstantF: 34 case SPIRV::OpConstantComposite: 35 case SPIRV::OpConstantSampler: 36 case SPIRV::OpConstantNull: 37 case SPIRV::OpSpecConstantTrue: 38 case SPIRV::OpSpecConstantFalse: 39 case SPIRV::OpSpecConstant: 40 case SPIRV::OpSpecConstantComposite: 41 case SPIRV::OpSpecConstantOp: 42 case SPIRV::OpUndef: 43 case SPIRV::OpConstantFunctionPointerINTEL: 44 return true; 45 default: 46 return false; 47 } 48 } 49 50 bool SPIRVInstrInfo::isSpecConstantInstr(const MachineInstr &MI) const { 51 switch (MI.getOpcode()) { 52 case SPIRV::OpSpecConstantTrue: 53 case SPIRV::OpSpecConstantFalse: 54 case SPIRV::OpSpecConstant: 55 case SPIRV::OpSpecConstantComposite: 56 case SPIRV::OpSpecConstantOp: 57 return true; 58 default: 59 return false; 60 } 61 } 62 63 bool SPIRVInstrInfo::isInlineAsmDefInstr(const MachineInstr &MI) const { 64 switch (MI.getOpcode()) { 65 case SPIRV::OpAsmTargetINTEL: 66 case SPIRV::OpAsmINTEL: 67 return true; 68 default: 69 return false; 70 } 71 } 72 73 bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const { 74 auto &MRI = MI.getMF()->getRegInfo(); 75 if (MI.getNumDefs() >= 1 && MI.getOperand(0).isReg()) { 76 auto DefRegClass = MRI.getRegClassOrNull(MI.getOperand(0).getReg()); 77 return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID(); 78 } else { 79 return MI.getOpcode() == SPIRV::OpTypeForwardPointer; 80 } 81 } 82 83 bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const { 84 switch (MI.getOpcode()) { 85 case SPIRV::OpDecorate: 86 case SPIRV::OpDecorateId: 87 case SPIRV::OpDecorateString: 88 case SPIRV::OpMemberDecorate: 89 case SPIRV::OpMemberDecorateString: 90 return true; 91 default: 92 return false; 93 } 94 } 95 96 bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const { 97 switch (MI.getOpcode()) { 98 case SPIRV::OpCapability: 99 case SPIRV::OpExtension: 100 case SPIRV::OpExtInstImport: 101 case SPIRV::OpMemoryModel: 102 case SPIRV::OpEntryPoint: 103 case SPIRV::OpExecutionMode: 104 case SPIRV::OpExecutionModeId: 105 case SPIRV::OpString: 106 case SPIRV::OpSourceExtension: 107 case SPIRV::OpSource: 108 case SPIRV::OpSourceContinued: 109 case SPIRV::OpName: 110 case SPIRV::OpMemberName: 111 case SPIRV::OpModuleProcessed: 112 return true; 113 default: 114 return isTypeDeclInstr(MI) || isConstantInstr(MI) || isDecorationInstr(MI); 115 } 116 } 117 118 bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const { 119 switch (MI.getOpcode()) { 120 case SPIRV::OpFAddS: 121 case SPIRV::OpFSubS: 122 case SPIRV::OpFMulS: 123 case SPIRV::OpFDivS: 124 case SPIRV::OpFRemS: 125 case SPIRV::OpFAddV: 126 case SPIRV::OpFSubV: 127 case SPIRV::OpFMulV: 128 case SPIRV::OpFDivV: 129 case SPIRV::OpFRemV: 130 case SPIRV::OpFMod: 131 return true; 132 default: 133 return false; 134 } 135 } 136 137 bool SPIRVInstrInfo::canUseNSW(const MachineInstr &MI) const { 138 switch (MI.getOpcode()) { 139 case SPIRV::OpIAddS: 140 case SPIRV::OpIAddV: 141 case SPIRV::OpISubS: 142 case SPIRV::OpISubV: 143 case SPIRV::OpIMulS: 144 case SPIRV::OpIMulV: 145 case SPIRV::OpShiftLeftLogicalS: 146 case SPIRV::OpShiftLeftLogicalV: 147 case SPIRV::OpSNegate: 148 return true; 149 default: 150 return false; 151 } 152 } 153 154 bool SPIRVInstrInfo::canUseNUW(const MachineInstr &MI) const { 155 switch (MI.getOpcode()) { 156 case SPIRV::OpIAddS: 157 case SPIRV::OpIAddV: 158 case SPIRV::OpISubS: 159 case SPIRV::OpISubV: 160 case SPIRV::OpIMulS: 161 case SPIRV::OpIMulV: 162 return true; 163 default: 164 return false; 165 } 166 } 167 168 // Analyze the branching code at the end of MBB, returning 169 // true if it cannot be understood (e.g. it's a switch dispatch or isn't 170 // implemented for a target). Upon success, this returns false and returns 171 // with the following information in various cases: 172 // 173 // 1. If this block ends with no branches (it just falls through to its succ) 174 // just return false, leaving TBB/FBB null. 175 // 2. If this block ends with only an unconditional branch, it sets TBB to be 176 // the destination block. 177 // 3. If this block ends with a conditional branch and it falls through to a 178 // successor block, it sets TBB to be the branch destination block and a 179 // list of operands that evaluate the condition. These operands can be 180 // passed to other TargetInstrInfo methods to create new branches. 181 // 4. If this block ends with a conditional branch followed by an 182 // unconditional branch, it returns the 'true' destination in TBB, the 183 // 'false' destination in FBB, and a list of operands that evaluate the 184 // condition. These operands can be passed to other TargetInstrInfo 185 // methods to create new branches. 186 // 187 // Note that removeBranch and insertBranch must be implemented to support 188 // cases where this method returns success. 189 // 190 // If AllowModify is true, then this routine is allowed to modify the basic 191 // block (e.g. delete instructions after the unconditional branch). 192 // 193 // The CFG information in MBB.Predecessors and MBB.Successors must be valid 194 // before calling this function. 195 bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 196 MachineBasicBlock *&TBB, 197 MachineBasicBlock *&FBB, 198 SmallVectorImpl<MachineOperand> &Cond, 199 bool AllowModify) const { 200 // We do not allow to restructure blocks by results of analyzeBranch(), 201 // because it may potentially break structured control flow and anyway 202 // doubtedly may be useful in SPIRV, including such reasons as, e.g.: 203 // 1) there is no way to encode `if (Cond) then Stmt` logic, only full 204 // if-then-else is supported by OpBranchConditional, so if we supported 205 // splitting of blocks ending with OpBranchConditional MachineBasicBlock.cpp 206 // would expect successfull implementation of calls to insertBranch() setting 207 // FBB to null that is not feasible; 2) it's not possible to delete 208 // instructions after the unconditional branch, because this instruction must 209 // be the last instruction in a block. 210 return true; 211 } 212 213 // Remove the branching code at the end of the specific MBB. 214 // This is only invoked in cases where analyzeBranch returns success. It 215 // returns the number of instructions that were removed. 216 // If \p BytesRemoved is non-null, report the change in code size from the 217 // removed instructions. 218 unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB, 219 int * /*BytesRemoved*/) const { 220 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 221 if (I == MBB.end()) 222 return 0; 223 224 if (I->getOpcode() == SPIRV::OpBranch) { 225 I->eraseFromParent(); 226 return 1; 227 } 228 return 0; 229 } 230 231 // Insert branch code into the end of the specified MachineBasicBlock. The 232 // operands to this method are the same as those returned by analyzeBranch. 233 // This is only invoked in cases where analyzeBranch returns success. It 234 // returns the number of instructions inserted. If \p BytesAdded is non-null, 235 // report the change in code size from the added instructions. 236 // 237 // It is also invoked by tail merging to add unconditional branches in 238 // cases where analyzeBranch doesn't apply because there was no original 239 // branch to analyze. At least this much must be implemented, else tail 240 // merging needs to be disabled. 241 // 242 // The CFG information in MBB.Predecessors and MBB.Successors must be valid 243 // before calling this function. 244 unsigned SPIRVInstrInfo::insertBranch(MachineBasicBlock &MBB, 245 MachineBasicBlock *TBB, 246 MachineBasicBlock *FBB, 247 ArrayRef<MachineOperand> Cond, 248 const DebugLoc &DL, 249 int * /*BytesAdded*/) const { 250 if (!TBB) 251 return 0; 252 BuildMI(&MBB, DL, get(SPIRV::OpBranch)).addMBB(TBB); 253 return 1; 254 } 255 256 void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 257 MachineBasicBlock::iterator I, 258 const DebugLoc &DL, MCRegister DestReg, 259 MCRegister SrcReg, bool KillSrc, 260 bool RenamableDest, bool RenamableSrc) const { 261 // Actually we don't need this COPY instruction. However if we do nothing with 262 // it, post RA pseudo instrs expansion just removes it and we get the code 263 // with undef registers. Therefore, we need to replace all uses of dst with 264 // the src register. COPY instr itself will be safely removed later. 265 assert(I->isCopy() && "Copy instruction is expected"); 266 auto DstOp = I->getOperand(0); 267 auto SrcOp = I->getOperand(1); 268 assert(DstOp.isReg() && SrcOp.isReg() && 269 "Register operands are expected in COPY"); 270 auto &MRI = I->getMF()->getRegInfo(); 271 MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg()); 272 } 273 274 bool SPIRVInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { 275 if (MI.getOpcode() == SPIRV::GET_ID || MI.getOpcode() == SPIRV::GET_fID || 276 MI.getOpcode() == SPIRV::GET_pID || MI.getOpcode() == SPIRV::GET_vfID || 277 MI.getOpcode() == SPIRV::GET_vID || MI.getOpcode() == SPIRV::GET_vpID) { 278 auto &MRI = MI.getMF()->getRegInfo(); 279 MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg()); 280 MI.eraseFromParent(); 281 return true; 282 } 283 return false; 284 } 285