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 // Analyze the branching code at the end of MBB, returning 95 // true if it cannot be understood (e.g. it's a switch dispatch or isn't 96 // implemented for a target). Upon success, this returns false and returns 97 // with the following information in various cases: 98 // 99 // 1. If this block ends with no branches (it just falls through to its succ) 100 // just return false, leaving TBB/FBB null. 101 // 2. If this block ends with only an unconditional branch, it sets TBB to be 102 // the destination block. 103 // 3. If this block ends with a conditional branch and it falls through to a 104 // successor block, it sets TBB to be the branch destination block and a 105 // list of operands that evaluate the condition. These operands can be 106 // passed to other TargetInstrInfo methods to create new branches. 107 // 4. If this block ends with a conditional branch followed by an 108 // unconditional branch, it returns the 'true' destination in TBB, the 109 // 'false' destination in FBB, and a list of operands that evaluate the 110 // condition. These operands can be passed to other TargetInstrInfo 111 // methods to create new branches. 112 // 113 // Note that removeBranch and insertBranch must be implemented to support 114 // cases where this method returns success. 115 // 116 // If AllowModify is true, then this routine is allowed to modify the basic 117 // block (e.g. delete instructions after the unconditional branch). 118 // 119 // The CFG information in MBB.Predecessors and MBB.Successors must be valid 120 // before calling this function. 121 bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 122 MachineBasicBlock *&TBB, 123 MachineBasicBlock *&FBB, 124 SmallVectorImpl<MachineOperand> &Cond, 125 bool AllowModify) const { 126 TBB = nullptr; 127 FBB = nullptr; 128 if (MBB.empty()) 129 return false; 130 auto MI = MBB.getLastNonDebugInstr(); 131 if (!MI.isValid()) 132 return false; 133 if (MI->getOpcode() == SPIRV::OpBranch) { 134 TBB = MI->getOperand(0).getMBB(); 135 return false; 136 } else if (MI->getOpcode() == SPIRV::OpBranchConditional) { 137 Cond.push_back(MI->getOperand(0)); 138 TBB = MI->getOperand(1).getMBB(); 139 if (MI->getNumOperands() == 3) { 140 FBB = MI->getOperand(2).getMBB(); 141 } 142 return false; 143 } else { 144 return true; 145 } 146 } 147 148 // Remove the branching code at the end of the specific MBB. 149 // This is only invoked in cases where analyzeBranch returns success. It 150 // returns the number of instructions that were removed. 151 // If \p BytesRemoved is non-null, report the change in code size from the 152 // removed instructions. 153 unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB, 154 int *BytesRemoved) const { 155 report_fatal_error("Branch removal not supported, as MBB info not propagated" 156 " to OpPhi instructions. Try using -O0 instead."); 157 } 158 159 // Insert branch code into the end of the specified MachineBasicBlock. The 160 // operands to this method are the same as those returned by analyzeBranch. 161 // This is only invoked in cases where analyzeBranch returns success. It 162 // returns the number of instructions inserted. If \p BytesAdded is non-null, 163 // report the change in code size from the added instructions. 164 // 165 // It is also invoked by tail merging to add unconditional branches in 166 // cases where analyzeBranch doesn't apply because there was no original 167 // branch to analyze. At least this much must be implemented, else tail 168 // merging needs to be disabled. 169 // 170 // The CFG information in MBB.Predecessors and MBB.Successors must be valid 171 // before calling this function. 172 unsigned SPIRVInstrInfo::insertBranch( 173 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 174 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 175 report_fatal_error("Branch insertion not supported, as MBB info not " 176 "propagated to OpPhi instructions. Try using " 177 "-O0 instead."); 178 } 179 180 void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 181 MachineBasicBlock::iterator I, 182 const DebugLoc &DL, MCRegister DestReg, 183 MCRegister SrcReg, bool KillSrc) const { 184 // Actually we don't need this COPY instruction. However if we do nothing with 185 // it, post RA pseudo instrs expansion just removes it and we get the code 186 // with undef registers. Therefore, we need to replace all uses of dst with 187 // the src register. COPY instr itself will be safely removed later. 188 assert(I->isCopy() && "Copy instruction is expected"); 189 auto DstOp = I->getOperand(0); 190 auto SrcOp = I->getOperand(1); 191 assert(DstOp.isReg() && SrcOp.isReg() && 192 "Register operands are expected in COPY"); 193 auto &MRI = I->getMF()->getRegInfo(); 194 MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg()); 195 } 196 197 bool SPIRVInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { 198 if (MI.getOpcode() == SPIRV::GET_ID || MI.getOpcode() == SPIRV::GET_fID || 199 MI.getOpcode() == SPIRV::GET_pID || MI.getOpcode() == SPIRV::GET_vfID || 200 MI.getOpcode() == SPIRV::GET_vID) { 201 auto &MRI = MI.getMF()->getRegInfo(); 202 MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg()); 203 MI.eraseFromParent(); 204 return true; 205 } 206 return false; 207 } 208