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