1*81ad6265SDimitry Andric //===-- SPIRVInstrInfo.cpp - SPIR-V Instruction Information ------*- C++-*-===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // This file contains the SPIR-V implementation of the TargetInstrInfo class. 10*81ad6265SDimitry Andric // 11*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 12*81ad6265SDimitry Andric 13*81ad6265SDimitry Andric #include "SPIRVInstrInfo.h" 14*81ad6265SDimitry Andric #include "SPIRV.h" 15*81ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 16*81ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 17*81ad6265SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 18*81ad6265SDimitry Andric #include "llvm/IR/DebugLoc.h" 19*81ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h" 20*81ad6265SDimitry Andric 21*81ad6265SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR 22*81ad6265SDimitry Andric #include "SPIRVGenInstrInfo.inc" 23*81ad6265SDimitry Andric 24*81ad6265SDimitry Andric using namespace llvm; 25*81ad6265SDimitry Andric 26*81ad6265SDimitry Andric SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {} 27*81ad6265SDimitry Andric 28*81ad6265SDimitry Andric bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const { 29*81ad6265SDimitry Andric switch (MI.getOpcode()) { 30*81ad6265SDimitry Andric case SPIRV::OpConstantTrue: 31*81ad6265SDimitry Andric case SPIRV::OpConstantFalse: 32*81ad6265SDimitry Andric case SPIRV::OpConstantI: 33*81ad6265SDimitry Andric case SPIRV::OpConstantF: 34*81ad6265SDimitry Andric case SPIRV::OpConstantComposite: 35*81ad6265SDimitry Andric case SPIRV::OpConstantSampler: 36*81ad6265SDimitry Andric case SPIRV::OpConstantNull: 37*81ad6265SDimitry Andric case SPIRV::OpSpecConstantTrue: 38*81ad6265SDimitry Andric case SPIRV::OpSpecConstantFalse: 39*81ad6265SDimitry Andric case SPIRV::OpSpecConstant: 40*81ad6265SDimitry Andric case SPIRV::OpSpecConstantComposite: 41*81ad6265SDimitry Andric case SPIRV::OpSpecConstantOp: 42*81ad6265SDimitry Andric case SPIRV::OpUndef: 43*81ad6265SDimitry Andric return true; 44*81ad6265SDimitry Andric default: 45*81ad6265SDimitry Andric return false; 46*81ad6265SDimitry Andric } 47*81ad6265SDimitry Andric } 48*81ad6265SDimitry Andric 49*81ad6265SDimitry Andric bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const { 50*81ad6265SDimitry Andric auto &MRI = MI.getMF()->getRegInfo(); 51*81ad6265SDimitry Andric if (MI.getNumDefs() >= 1 && MI.getOperand(0).isReg()) { 52*81ad6265SDimitry Andric auto DefRegClass = MRI.getRegClassOrNull(MI.getOperand(0).getReg()); 53*81ad6265SDimitry Andric return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID(); 54*81ad6265SDimitry Andric } else { 55*81ad6265SDimitry Andric return false; 56*81ad6265SDimitry Andric } 57*81ad6265SDimitry Andric } 58*81ad6265SDimitry Andric 59*81ad6265SDimitry Andric bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const { 60*81ad6265SDimitry Andric switch (MI.getOpcode()) { 61*81ad6265SDimitry Andric case SPIRV::OpDecorate: 62*81ad6265SDimitry Andric case SPIRV::OpDecorateId: 63*81ad6265SDimitry Andric case SPIRV::OpDecorateString: 64*81ad6265SDimitry Andric case SPIRV::OpMemberDecorate: 65*81ad6265SDimitry Andric case SPIRV::OpMemberDecorateString: 66*81ad6265SDimitry Andric return true; 67*81ad6265SDimitry Andric default: 68*81ad6265SDimitry Andric return false; 69*81ad6265SDimitry Andric } 70*81ad6265SDimitry Andric } 71*81ad6265SDimitry Andric 72*81ad6265SDimitry Andric bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const { 73*81ad6265SDimitry Andric switch (MI.getOpcode()) { 74*81ad6265SDimitry Andric case SPIRV::OpCapability: 75*81ad6265SDimitry Andric case SPIRV::OpExtension: 76*81ad6265SDimitry Andric case SPIRV::OpExtInstImport: 77*81ad6265SDimitry Andric case SPIRV::OpMemoryModel: 78*81ad6265SDimitry Andric case SPIRV::OpEntryPoint: 79*81ad6265SDimitry Andric case SPIRV::OpExecutionMode: 80*81ad6265SDimitry Andric case SPIRV::OpExecutionModeId: 81*81ad6265SDimitry Andric case SPIRV::OpString: 82*81ad6265SDimitry Andric case SPIRV::OpSourceExtension: 83*81ad6265SDimitry Andric case SPIRV::OpSource: 84*81ad6265SDimitry Andric case SPIRV::OpSourceContinued: 85*81ad6265SDimitry Andric case SPIRV::OpName: 86*81ad6265SDimitry Andric case SPIRV::OpMemberName: 87*81ad6265SDimitry Andric case SPIRV::OpModuleProcessed: 88*81ad6265SDimitry Andric return true; 89*81ad6265SDimitry Andric default: 90*81ad6265SDimitry Andric return isTypeDeclInstr(MI) || isConstantInstr(MI) || isDecorationInstr(MI); 91*81ad6265SDimitry Andric } 92*81ad6265SDimitry Andric } 93*81ad6265SDimitry Andric 94*81ad6265SDimitry Andric // Analyze the branching code at the end of MBB, returning 95*81ad6265SDimitry Andric // true if it cannot be understood (e.g. it's a switch dispatch or isn't 96*81ad6265SDimitry Andric // implemented for a target). Upon success, this returns false and returns 97*81ad6265SDimitry Andric // with the following information in various cases: 98*81ad6265SDimitry Andric // 99*81ad6265SDimitry Andric // 1. If this block ends with no branches (it just falls through to its succ) 100*81ad6265SDimitry Andric // just return false, leaving TBB/FBB null. 101*81ad6265SDimitry Andric // 2. If this block ends with only an unconditional branch, it sets TBB to be 102*81ad6265SDimitry Andric // the destination block. 103*81ad6265SDimitry Andric // 3. If this block ends with a conditional branch and it falls through to a 104*81ad6265SDimitry Andric // successor block, it sets TBB to be the branch destination block and a 105*81ad6265SDimitry Andric // list of operands that evaluate the condition. These operands can be 106*81ad6265SDimitry Andric // passed to other TargetInstrInfo methods to create new branches. 107*81ad6265SDimitry Andric // 4. If this block ends with a conditional branch followed by an 108*81ad6265SDimitry Andric // unconditional branch, it returns the 'true' destination in TBB, the 109*81ad6265SDimitry Andric // 'false' destination in FBB, and a list of operands that evaluate the 110*81ad6265SDimitry Andric // condition. These operands can be passed to other TargetInstrInfo 111*81ad6265SDimitry Andric // methods to create new branches. 112*81ad6265SDimitry Andric // 113*81ad6265SDimitry Andric // Note that removeBranch and insertBranch must be implemented to support 114*81ad6265SDimitry Andric // cases where this method returns success. 115*81ad6265SDimitry Andric // 116*81ad6265SDimitry Andric // If AllowModify is true, then this routine is allowed to modify the basic 117*81ad6265SDimitry Andric // block (e.g. delete instructions after the unconditional branch). 118*81ad6265SDimitry Andric // 119*81ad6265SDimitry Andric // The CFG information in MBB.Predecessors and MBB.Successors must be valid 120*81ad6265SDimitry Andric // before calling this function. 121*81ad6265SDimitry Andric bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 122*81ad6265SDimitry Andric MachineBasicBlock *&TBB, 123*81ad6265SDimitry Andric MachineBasicBlock *&FBB, 124*81ad6265SDimitry Andric SmallVectorImpl<MachineOperand> &Cond, 125*81ad6265SDimitry Andric bool AllowModify) const { 126*81ad6265SDimitry Andric TBB = nullptr; 127*81ad6265SDimitry Andric FBB = nullptr; 128*81ad6265SDimitry Andric if (MBB.empty()) 129*81ad6265SDimitry Andric return false; 130*81ad6265SDimitry Andric auto MI = MBB.getLastNonDebugInstr(); 131*81ad6265SDimitry Andric if (!MI.isValid()) 132*81ad6265SDimitry Andric return false; 133*81ad6265SDimitry Andric if (MI->getOpcode() == SPIRV::OpBranch) { 134*81ad6265SDimitry Andric TBB = MI->getOperand(0).getMBB(); 135*81ad6265SDimitry Andric return false; 136*81ad6265SDimitry Andric } else if (MI->getOpcode() == SPIRV::OpBranchConditional) { 137*81ad6265SDimitry Andric Cond.push_back(MI->getOperand(0)); 138*81ad6265SDimitry Andric TBB = MI->getOperand(1).getMBB(); 139*81ad6265SDimitry Andric if (MI->getNumOperands() == 3) { 140*81ad6265SDimitry Andric FBB = MI->getOperand(2).getMBB(); 141*81ad6265SDimitry Andric } 142*81ad6265SDimitry Andric return false; 143*81ad6265SDimitry Andric } else { 144*81ad6265SDimitry Andric return true; 145*81ad6265SDimitry Andric } 146*81ad6265SDimitry Andric } 147*81ad6265SDimitry Andric 148*81ad6265SDimitry Andric // Remove the branching code at the end of the specific MBB. 149*81ad6265SDimitry Andric // This is only invoked in cases where analyzeBranch returns success. It 150*81ad6265SDimitry Andric // returns the number of instructions that were removed. 151*81ad6265SDimitry Andric // If \p BytesRemoved is non-null, report the change in code size from the 152*81ad6265SDimitry Andric // removed instructions. 153*81ad6265SDimitry Andric unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB, 154*81ad6265SDimitry Andric int *BytesRemoved) const { 155*81ad6265SDimitry Andric report_fatal_error("Branch removal not supported, as MBB info not propagated" 156*81ad6265SDimitry Andric " to OpPhi instructions. Try using -O0 instead."); 157*81ad6265SDimitry Andric } 158*81ad6265SDimitry Andric 159*81ad6265SDimitry Andric // Insert branch code into the end of the specified MachineBasicBlock. The 160*81ad6265SDimitry Andric // operands to this method are the same as those returned by analyzeBranch. 161*81ad6265SDimitry Andric // This is only invoked in cases where analyzeBranch returns success. It 162*81ad6265SDimitry Andric // returns the number of instructions inserted. If \p BytesAdded is non-null, 163*81ad6265SDimitry Andric // report the change in code size from the added instructions. 164*81ad6265SDimitry Andric // 165*81ad6265SDimitry Andric // It is also invoked by tail merging to add unconditional branches in 166*81ad6265SDimitry Andric // cases where analyzeBranch doesn't apply because there was no original 167*81ad6265SDimitry Andric // branch to analyze. At least this much must be implemented, else tail 168*81ad6265SDimitry Andric // merging needs to be disabled. 169*81ad6265SDimitry Andric // 170*81ad6265SDimitry Andric // The CFG information in MBB.Predecessors and MBB.Successors must be valid 171*81ad6265SDimitry Andric // before calling this function. 172*81ad6265SDimitry Andric unsigned SPIRVInstrInfo::insertBranch( 173*81ad6265SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 174*81ad6265SDimitry Andric ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 175*81ad6265SDimitry Andric report_fatal_error("Branch insertion not supported, as MBB info not " 176*81ad6265SDimitry Andric "propagated to OpPhi instructions. Try using " 177*81ad6265SDimitry Andric "-O0 instead."); 178*81ad6265SDimitry Andric } 179*81ad6265SDimitry Andric 180*81ad6265SDimitry Andric void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 181*81ad6265SDimitry Andric MachineBasicBlock::iterator I, 182*81ad6265SDimitry Andric const DebugLoc &DL, MCRegister DestReg, 183*81ad6265SDimitry Andric MCRegister SrcReg, bool KillSrc) const { 184*81ad6265SDimitry Andric // Actually we don't need this COPY instruction. However if we do nothing with 185*81ad6265SDimitry Andric // it, post RA pseudo instrs expansion just removes it and we get the code 186*81ad6265SDimitry Andric // with undef registers. Therefore, we need to replace all uses of dst with 187*81ad6265SDimitry Andric // the src register. COPY instr itself will be safely removed later. 188*81ad6265SDimitry Andric assert(I->isCopy() && "Copy instruction is expected"); 189*81ad6265SDimitry Andric auto DstOp = I->getOperand(0); 190*81ad6265SDimitry Andric auto SrcOp = I->getOperand(1); 191*81ad6265SDimitry Andric assert(DstOp.isReg() && SrcOp.isReg() && 192*81ad6265SDimitry Andric "Register operands are expected in COPY"); 193*81ad6265SDimitry Andric auto &MRI = I->getMF()->getRegInfo(); 194*81ad6265SDimitry Andric MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg()); 195*81ad6265SDimitry Andric } 196