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 24using namespace llvm; 25 26SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {} 27 28bool 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 49bool 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 59bool 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 72bool 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 94bool 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 113bool 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 130bool 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. 171bool 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. 203unsigned 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. 222unsigned 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 230void 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 247bool 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