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 return true; 44 default: 45 return false; 46 } 47 } 48 49 bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const { 50 auto &MRI = MI.getMF()->getRegInfo(); 51 if (MI.getNumDefs() >= 1 && MI.getOperand(0).isReg()) { 52 auto DefRegClass = MRI.getRegClassOrNull(MI.getOperand(0).getReg()); 53 return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID(); 54 } else { 55 return MI.getOpcode() == SPIRV::OpTypeForwardPointer; 56 } 57 } 58 59 bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const { 60 switch (MI.getOpcode()) { 61 case SPIRV::OpDecorate: 62 case SPIRV::OpDecorateId: 63 case SPIRV::OpDecorateString: 64 case SPIRV::OpMemberDecorate: 65 case SPIRV::OpMemberDecorateString: 66 return true; 67 default: 68 return false; 69 } 70 } 71 72 bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const { 73 switch (MI.getOpcode()) { 74 case SPIRV::OpCapability: 75 case SPIRV::OpExtension: 76 case SPIRV::OpExtInstImport: 77 case SPIRV::OpMemoryModel: 78 case SPIRV::OpEntryPoint: 79 case SPIRV::OpExecutionMode: 80 case SPIRV::OpExecutionModeId: 81 case SPIRV::OpString: 82 case SPIRV::OpSourceExtension: 83 case SPIRV::OpSource: 84 case SPIRV::OpSourceContinued: 85 case SPIRV::OpName: 86 case SPIRV::OpMemberName: 87 case SPIRV::OpModuleProcessed: 88 return true; 89 default: 90 return isTypeDeclInstr(MI) || isConstantInstr(MI) || isDecorationInstr(MI); 91 } 92 } 93 94 bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const { 95 switch (MI.getOpcode()) { 96 case SPIRV::OpFAddS: 97 case SPIRV::OpFSubS: 98 case SPIRV::OpFMulS: 99 case SPIRV::OpFDivS: 100 case SPIRV::OpFRemS: 101 case SPIRV::OpFAddV: 102 case SPIRV::OpFSubV: 103 case SPIRV::OpFMulV: 104 case SPIRV::OpFDivV: 105 case SPIRV::OpFRemV: 106 case SPIRV::OpFMod: 107 return true; 108 default: 109 return false; 110 } 111 } 112 113 bool SPIRVInstrInfo::canUseNSW(const MachineInstr &MI) const { 114 switch (MI.getOpcode()) { 115 case SPIRV::OpIAddS: 116 case SPIRV::OpIAddV: 117 case SPIRV::OpISubS: 118 case SPIRV::OpISubV: 119 case SPIRV::OpIMulS: 120 case SPIRV::OpIMulV: 121 case SPIRV::OpShiftLeftLogicalS: 122 case SPIRV::OpShiftLeftLogicalV: 123 case SPIRV::OpSNegate: 124 return true; 125 default: 126 return false; 127 } 128 } 129 130 bool SPIRVInstrInfo::canUseNUW(const MachineInstr &MI) const { 131 switch (MI.getOpcode()) { 132 case SPIRV::OpIAddS: 133 case SPIRV::OpIAddV: 134 case SPIRV::OpISubS: 135 case SPIRV::OpISubV: 136 case SPIRV::OpIMulS: 137 case SPIRV::OpIMulV: 138 return true; 139 default: 140 return false; 141 } 142 } 143 144 // Analyze the branching code at the end of MBB, returning 145 // true if it cannot be understood (e.g. it's a switch dispatch or isn't 146 // implemented for a target). Upon success, this returns false and returns 147 // with the following information in various cases: 148 // 149 // 1. If this block ends with no branches (it just falls through to its succ) 150 // just return false, leaving TBB/FBB null. 151 // 2. If this block ends with only an unconditional branch, it sets TBB to be 152 // the destination block. 153 // 3. If this block ends with a conditional branch and it falls through to a 154 // successor block, it sets TBB to be the branch destination block and a 155 // list of operands that evaluate the condition. These operands can be 156 // passed to other TargetInstrInfo methods to create new branches. 157 // 4. If this block ends with a conditional branch followed by an 158 // unconditional branch, it returns the 'true' destination in TBB, the 159 // 'false' destination in FBB, and a list of operands that evaluate the 160 // condition. These operands can be passed to other TargetInstrInfo 161 // methods to create new branches. 162 // 163 // Note that removeBranch and insertBranch must be implemented to support 164 // cases where this method returns success. 165 // 166 // If AllowModify is true, then this routine is allowed to modify the basic 167 // block (e.g. delete instructions after the unconditional branch). 168 // 169 // The CFG information in MBB.Predecessors and MBB.Successors must be valid 170 // before calling this function. 171 bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 172 MachineBasicBlock *&TBB, 173 MachineBasicBlock *&FBB, 174 SmallVectorImpl<MachineOperand> &Cond, 175 bool AllowModify) const { 176 TBB = nullptr; 177 FBB = nullptr; 178 if (MBB.empty()) 179 return false; 180 auto MI = MBB.getLastNonDebugInstr(); 181 if (!MI.isValid()) 182 return false; 183 if (MI->getOpcode() == SPIRV::OpBranch) { 184 TBB = MI->getOperand(0).getMBB(); 185 return false; 186 } else if (MI->getOpcode() == SPIRV::OpBranchConditional) { 187 Cond.push_back(MI->getOperand(0)); 188 TBB = MI->getOperand(1).getMBB(); 189 if (MI->getNumOperands() == 3) { 190 FBB = MI->getOperand(2).getMBB(); 191 } 192 return false; 193 } else { 194 return true; 195 } 196 } 197 198 // Remove the branching code at the end of the specific MBB. 199 // This is only invoked in cases where analyzeBranch returns success. It 200 // returns the number of instructions that were removed. 201 // If \p BytesRemoved is non-null, report the change in code size from the 202 // removed instructions. 203 unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB, 204 int *BytesRemoved) const { 205 report_fatal_error("Branch removal not supported, as MBB info not propagated" 206 " to OpPhi instructions. Try using -O0 instead."); 207 } 208 209 // Insert branch code into the end of the specified MachineBasicBlock. The 210 // operands to this method are the same as those returned by analyzeBranch. 211 // This is only invoked in cases where analyzeBranch returns success. It 212 // returns the number of instructions inserted. If \p BytesAdded is non-null, 213 // report the change in code size from the added instructions. 214 // 215 // It is also invoked by tail merging to add unconditional branches in 216 // cases where analyzeBranch doesn't apply because there was no original 217 // branch to analyze. At least this much must be implemented, else tail 218 // merging needs to be disabled. 219 // 220 // The CFG information in MBB.Predecessors and MBB.Successors must be valid 221 // before calling this function. 222 unsigned SPIRVInstrInfo::insertBranch( 223 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 224 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 225 report_fatal_error("Branch insertion not supported, as MBB info not " 226 "propagated to OpPhi instructions. Try using " 227 "-O0 instead."); 228 } 229 230 void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 231 MachineBasicBlock::iterator I, 232 const DebugLoc &DL, MCRegister DestReg, 233 MCRegister SrcReg, bool KillSrc) const { 234 // Actually we don't need this COPY instruction. However if we do nothing with 235 // it, post RA pseudo instrs expansion just removes it and we get the code 236 // with undef registers. Therefore, we need to replace all uses of dst with 237 // the src register. COPY instr itself will be safely removed later. 238 assert(I->isCopy() && "Copy instruction is expected"); 239 auto DstOp = I->getOperand(0); 240 auto SrcOp = I->getOperand(1); 241 assert(DstOp.isReg() && SrcOp.isReg() && 242 "Register operands are expected in COPY"); 243 auto &MRI = I->getMF()->getRegInfo(); 244 MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg()); 245 } 246 247 bool SPIRVInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { 248 if (MI.getOpcode() == SPIRV::GET_ID || MI.getOpcode() == SPIRV::GET_fID || 249 MI.getOpcode() == SPIRV::GET_pID || MI.getOpcode() == SPIRV::GET_vfID || 250 MI.getOpcode() == SPIRV::GET_vID) { 251 auto &MRI = MI.getMF()->getRegInfo(); 252 MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg()); 253 MI.eraseFromParent(); 254 return true; 255 } 256 return false; 257 } 258