181ad6265SDimitry Andric //===-- SPIRVInstrInfo.cpp - SPIR-V Instruction Information ------*- C++-*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file contains the SPIR-V implementation of the TargetInstrInfo class. 1081ad6265SDimitry Andric // 1181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1281ad6265SDimitry Andric 1381ad6265SDimitry Andric #include "SPIRVInstrInfo.h" 1481ad6265SDimitry Andric #include "SPIRV.h" 1581ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 1681ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 1781ad6265SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 1881ad6265SDimitry Andric #include "llvm/IR/DebugLoc.h" 1981ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h" 2081ad6265SDimitry Andric 2181ad6265SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR 2281ad6265SDimitry Andric #include "SPIRVGenInstrInfo.inc" 2381ad6265SDimitry Andric 2481ad6265SDimitry Andric using namespace llvm; 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {} 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const { 2981ad6265SDimitry Andric switch (MI.getOpcode()) { 3081ad6265SDimitry Andric case SPIRV::OpConstantTrue: 3181ad6265SDimitry Andric case SPIRV::OpConstantFalse: 3281ad6265SDimitry Andric case SPIRV::OpConstantI: 3381ad6265SDimitry Andric case SPIRV::OpConstantF: 3481ad6265SDimitry Andric case SPIRV::OpConstantComposite: 3581ad6265SDimitry Andric case SPIRV::OpConstantSampler: 3681ad6265SDimitry Andric case SPIRV::OpConstantNull: 3781ad6265SDimitry Andric case SPIRV::OpSpecConstantTrue: 3881ad6265SDimitry Andric case SPIRV::OpSpecConstantFalse: 3981ad6265SDimitry Andric case SPIRV::OpSpecConstant: 4081ad6265SDimitry Andric case SPIRV::OpSpecConstantComposite: 4181ad6265SDimitry Andric case SPIRV::OpSpecConstantOp: 4281ad6265SDimitry Andric case SPIRV::OpUndef: 43*0fca6ea1SDimitry Andric case SPIRV::OpConstantFunctionPointerINTEL: 44*0fca6ea1SDimitry Andric return true; 45*0fca6ea1SDimitry Andric default: 46*0fca6ea1SDimitry Andric return false; 47*0fca6ea1SDimitry Andric } 48*0fca6ea1SDimitry Andric } 49*0fca6ea1SDimitry Andric 50*0fca6ea1SDimitry Andric bool SPIRVInstrInfo::isInlineAsmDefInstr(const MachineInstr &MI) const { 51*0fca6ea1SDimitry Andric switch (MI.getOpcode()) { 52*0fca6ea1SDimitry Andric case SPIRV::OpAsmTargetINTEL: 53*0fca6ea1SDimitry Andric case SPIRV::OpAsmINTEL: 5481ad6265SDimitry Andric return true; 5581ad6265SDimitry Andric default: 5681ad6265SDimitry Andric return false; 5781ad6265SDimitry Andric } 5881ad6265SDimitry Andric } 5981ad6265SDimitry Andric 6081ad6265SDimitry Andric bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const { 6181ad6265SDimitry Andric auto &MRI = MI.getMF()->getRegInfo(); 6281ad6265SDimitry Andric if (MI.getNumDefs() >= 1 && MI.getOperand(0).isReg()) { 6381ad6265SDimitry Andric auto DefRegClass = MRI.getRegClassOrNull(MI.getOperand(0).getReg()); 6481ad6265SDimitry Andric return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID(); 6581ad6265SDimitry Andric } else { 66fcaf7f86SDimitry Andric return MI.getOpcode() == SPIRV::OpTypeForwardPointer; 6781ad6265SDimitry Andric } 6881ad6265SDimitry Andric } 6981ad6265SDimitry Andric 7081ad6265SDimitry Andric bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const { 7181ad6265SDimitry Andric switch (MI.getOpcode()) { 7281ad6265SDimitry Andric case SPIRV::OpDecorate: 7381ad6265SDimitry Andric case SPIRV::OpDecorateId: 7481ad6265SDimitry Andric case SPIRV::OpDecorateString: 7581ad6265SDimitry Andric case SPIRV::OpMemberDecorate: 7681ad6265SDimitry Andric case SPIRV::OpMemberDecorateString: 7781ad6265SDimitry Andric return true; 7881ad6265SDimitry Andric default: 7981ad6265SDimitry Andric return false; 8081ad6265SDimitry Andric } 8181ad6265SDimitry Andric } 8281ad6265SDimitry Andric 8381ad6265SDimitry Andric bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const { 8481ad6265SDimitry Andric switch (MI.getOpcode()) { 8581ad6265SDimitry Andric case SPIRV::OpCapability: 8681ad6265SDimitry Andric case SPIRV::OpExtension: 8781ad6265SDimitry Andric case SPIRV::OpExtInstImport: 8881ad6265SDimitry Andric case SPIRV::OpMemoryModel: 8981ad6265SDimitry Andric case SPIRV::OpEntryPoint: 9081ad6265SDimitry Andric case SPIRV::OpExecutionMode: 9181ad6265SDimitry Andric case SPIRV::OpExecutionModeId: 9281ad6265SDimitry Andric case SPIRV::OpString: 9381ad6265SDimitry Andric case SPIRV::OpSourceExtension: 9481ad6265SDimitry Andric case SPIRV::OpSource: 9581ad6265SDimitry Andric case SPIRV::OpSourceContinued: 9681ad6265SDimitry Andric case SPIRV::OpName: 9781ad6265SDimitry Andric case SPIRV::OpMemberName: 9881ad6265SDimitry Andric case SPIRV::OpModuleProcessed: 9981ad6265SDimitry Andric return true; 10081ad6265SDimitry Andric default: 10181ad6265SDimitry Andric return isTypeDeclInstr(MI) || isConstantInstr(MI) || isDecorationInstr(MI); 10281ad6265SDimitry Andric } 10381ad6265SDimitry Andric } 10481ad6265SDimitry Andric 105bdd1243dSDimitry Andric bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const { 106bdd1243dSDimitry Andric switch (MI.getOpcode()) { 107bdd1243dSDimitry Andric case SPIRV::OpFAddS: 108bdd1243dSDimitry Andric case SPIRV::OpFSubS: 109bdd1243dSDimitry Andric case SPIRV::OpFMulS: 110bdd1243dSDimitry Andric case SPIRV::OpFDivS: 111bdd1243dSDimitry Andric case SPIRV::OpFRemS: 112bdd1243dSDimitry Andric case SPIRV::OpFAddV: 113bdd1243dSDimitry Andric case SPIRV::OpFSubV: 114bdd1243dSDimitry Andric case SPIRV::OpFMulV: 115bdd1243dSDimitry Andric case SPIRV::OpFDivV: 116bdd1243dSDimitry Andric case SPIRV::OpFRemV: 117bdd1243dSDimitry Andric case SPIRV::OpFMod: 118bdd1243dSDimitry Andric return true; 119bdd1243dSDimitry Andric default: 120bdd1243dSDimitry Andric return false; 121bdd1243dSDimitry Andric } 122bdd1243dSDimitry Andric } 123bdd1243dSDimitry Andric 124bdd1243dSDimitry Andric bool SPIRVInstrInfo::canUseNSW(const MachineInstr &MI) const { 125bdd1243dSDimitry Andric switch (MI.getOpcode()) { 126bdd1243dSDimitry Andric case SPIRV::OpIAddS: 127bdd1243dSDimitry Andric case SPIRV::OpIAddV: 128bdd1243dSDimitry Andric case SPIRV::OpISubS: 129bdd1243dSDimitry Andric case SPIRV::OpISubV: 130bdd1243dSDimitry Andric case SPIRV::OpIMulS: 131bdd1243dSDimitry Andric case SPIRV::OpIMulV: 132bdd1243dSDimitry Andric case SPIRV::OpShiftLeftLogicalS: 133bdd1243dSDimitry Andric case SPIRV::OpShiftLeftLogicalV: 134bdd1243dSDimitry Andric case SPIRV::OpSNegate: 135bdd1243dSDimitry Andric return true; 136bdd1243dSDimitry Andric default: 137bdd1243dSDimitry Andric return false; 138bdd1243dSDimitry Andric } 139bdd1243dSDimitry Andric } 140bdd1243dSDimitry Andric 141bdd1243dSDimitry Andric bool SPIRVInstrInfo::canUseNUW(const MachineInstr &MI) const { 142bdd1243dSDimitry Andric switch (MI.getOpcode()) { 143bdd1243dSDimitry Andric case SPIRV::OpIAddS: 144bdd1243dSDimitry Andric case SPIRV::OpIAddV: 145bdd1243dSDimitry Andric case SPIRV::OpISubS: 146bdd1243dSDimitry Andric case SPIRV::OpISubV: 147bdd1243dSDimitry Andric case SPIRV::OpIMulS: 148bdd1243dSDimitry Andric case SPIRV::OpIMulV: 149bdd1243dSDimitry Andric return true; 150bdd1243dSDimitry Andric default: 151bdd1243dSDimitry Andric return false; 152bdd1243dSDimitry Andric } 153bdd1243dSDimitry Andric } 154bdd1243dSDimitry Andric 15581ad6265SDimitry Andric // Analyze the branching code at the end of MBB, returning 15681ad6265SDimitry Andric // true if it cannot be understood (e.g. it's a switch dispatch or isn't 15781ad6265SDimitry Andric // implemented for a target). Upon success, this returns false and returns 15881ad6265SDimitry Andric // with the following information in various cases: 15981ad6265SDimitry Andric // 16081ad6265SDimitry Andric // 1. If this block ends with no branches (it just falls through to its succ) 16181ad6265SDimitry Andric // just return false, leaving TBB/FBB null. 16281ad6265SDimitry Andric // 2. If this block ends with only an unconditional branch, it sets TBB to be 16381ad6265SDimitry Andric // the destination block. 16481ad6265SDimitry Andric // 3. If this block ends with a conditional branch and it falls through to a 16581ad6265SDimitry Andric // successor block, it sets TBB to be the branch destination block and a 16681ad6265SDimitry Andric // list of operands that evaluate the condition. These operands can be 16781ad6265SDimitry Andric // passed to other TargetInstrInfo methods to create new branches. 16881ad6265SDimitry Andric // 4. If this block ends with a conditional branch followed by an 16981ad6265SDimitry Andric // unconditional branch, it returns the 'true' destination in TBB, the 17081ad6265SDimitry Andric // 'false' destination in FBB, and a list of operands that evaluate the 17181ad6265SDimitry Andric // condition. These operands can be passed to other TargetInstrInfo 17281ad6265SDimitry Andric // methods to create new branches. 17381ad6265SDimitry Andric // 17481ad6265SDimitry Andric // Note that removeBranch and insertBranch must be implemented to support 17581ad6265SDimitry Andric // cases where this method returns success. 17681ad6265SDimitry Andric // 17781ad6265SDimitry Andric // If AllowModify is true, then this routine is allowed to modify the basic 17881ad6265SDimitry Andric // block (e.g. delete instructions after the unconditional branch). 17981ad6265SDimitry Andric // 18081ad6265SDimitry Andric // The CFG information in MBB.Predecessors and MBB.Successors must be valid 18181ad6265SDimitry Andric // before calling this function. 18281ad6265SDimitry Andric bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 18381ad6265SDimitry Andric MachineBasicBlock *&TBB, 18481ad6265SDimitry Andric MachineBasicBlock *&FBB, 18581ad6265SDimitry Andric SmallVectorImpl<MachineOperand> &Cond, 18681ad6265SDimitry Andric bool AllowModify) const { 18781ad6265SDimitry Andric TBB = nullptr; 18881ad6265SDimitry Andric FBB = nullptr; 18981ad6265SDimitry Andric if (MBB.empty()) 19081ad6265SDimitry Andric return false; 19181ad6265SDimitry Andric auto MI = MBB.getLastNonDebugInstr(); 19281ad6265SDimitry Andric if (!MI.isValid()) 19381ad6265SDimitry Andric return false; 19481ad6265SDimitry Andric if (MI->getOpcode() == SPIRV::OpBranch) { 19581ad6265SDimitry Andric TBB = MI->getOperand(0).getMBB(); 19681ad6265SDimitry Andric return false; 19781ad6265SDimitry Andric } else if (MI->getOpcode() == SPIRV::OpBranchConditional) { 19881ad6265SDimitry Andric Cond.push_back(MI->getOperand(0)); 19981ad6265SDimitry Andric TBB = MI->getOperand(1).getMBB(); 20081ad6265SDimitry Andric if (MI->getNumOperands() == 3) { 20181ad6265SDimitry Andric FBB = MI->getOperand(2).getMBB(); 20281ad6265SDimitry Andric } 20381ad6265SDimitry Andric return false; 20481ad6265SDimitry Andric } else { 20581ad6265SDimitry Andric return true; 20681ad6265SDimitry Andric } 20781ad6265SDimitry Andric } 20881ad6265SDimitry Andric 20981ad6265SDimitry Andric // Remove the branching code at the end of the specific MBB. 21081ad6265SDimitry Andric // This is only invoked in cases where analyzeBranch returns success. It 21181ad6265SDimitry Andric // returns the number of instructions that were removed. 21281ad6265SDimitry Andric // If \p BytesRemoved is non-null, report the change in code size from the 21381ad6265SDimitry Andric // removed instructions. 21481ad6265SDimitry Andric unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB, 21581ad6265SDimitry Andric int *BytesRemoved) const { 21681ad6265SDimitry Andric report_fatal_error("Branch removal not supported, as MBB info not propagated" 21781ad6265SDimitry Andric " to OpPhi instructions. Try using -O0 instead."); 21881ad6265SDimitry Andric } 21981ad6265SDimitry Andric 22081ad6265SDimitry Andric // Insert branch code into the end of the specified MachineBasicBlock. The 22181ad6265SDimitry Andric // operands to this method are the same as those returned by analyzeBranch. 22281ad6265SDimitry Andric // This is only invoked in cases where analyzeBranch returns success. It 22381ad6265SDimitry Andric // returns the number of instructions inserted. If \p BytesAdded is non-null, 22481ad6265SDimitry Andric // report the change in code size from the added instructions. 22581ad6265SDimitry Andric // 22681ad6265SDimitry Andric // It is also invoked by tail merging to add unconditional branches in 22781ad6265SDimitry Andric // cases where analyzeBranch doesn't apply because there was no original 22881ad6265SDimitry Andric // branch to analyze. At least this much must be implemented, else tail 22981ad6265SDimitry Andric // merging needs to be disabled. 23081ad6265SDimitry Andric // 23181ad6265SDimitry Andric // The CFG information in MBB.Predecessors and MBB.Successors must be valid 23281ad6265SDimitry Andric // before calling this function. 23381ad6265SDimitry Andric unsigned SPIRVInstrInfo::insertBranch( 23481ad6265SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 23581ad6265SDimitry Andric ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 23681ad6265SDimitry Andric report_fatal_error("Branch insertion not supported, as MBB info not " 23781ad6265SDimitry Andric "propagated to OpPhi instructions. Try using " 23881ad6265SDimitry Andric "-O0 instead."); 23981ad6265SDimitry Andric } 24081ad6265SDimitry Andric 24181ad6265SDimitry Andric void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 24281ad6265SDimitry Andric MachineBasicBlock::iterator I, 24381ad6265SDimitry Andric const DebugLoc &DL, MCRegister DestReg, 24481ad6265SDimitry Andric MCRegister SrcReg, bool KillSrc) const { 24581ad6265SDimitry Andric // Actually we don't need this COPY instruction. However if we do nothing with 24681ad6265SDimitry Andric // it, post RA pseudo instrs expansion just removes it and we get the code 24781ad6265SDimitry Andric // with undef registers. Therefore, we need to replace all uses of dst with 24881ad6265SDimitry Andric // the src register. COPY instr itself will be safely removed later. 24981ad6265SDimitry Andric assert(I->isCopy() && "Copy instruction is expected"); 25081ad6265SDimitry Andric auto DstOp = I->getOperand(0); 25181ad6265SDimitry Andric auto SrcOp = I->getOperand(1); 25281ad6265SDimitry Andric assert(DstOp.isReg() && SrcOp.isReg() && 25381ad6265SDimitry Andric "Register operands are expected in COPY"); 25481ad6265SDimitry Andric auto &MRI = I->getMF()->getRegInfo(); 25581ad6265SDimitry Andric MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg()); 25681ad6265SDimitry Andric } 257fcaf7f86SDimitry Andric 258fcaf7f86SDimitry Andric bool SPIRVInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { 259*0fca6ea1SDimitry Andric if (MI.getOpcode() == SPIRV::GET_ID || MI.getOpcode() == SPIRV::GET_ID64 || 260*0fca6ea1SDimitry Andric MI.getOpcode() == SPIRV::GET_fID || MI.getOpcode() == SPIRV::GET_fID64 || 261*0fca6ea1SDimitry Andric MI.getOpcode() == SPIRV::GET_pID32 || 262*0fca6ea1SDimitry Andric MI.getOpcode() == SPIRV::GET_pID64 || MI.getOpcode() == SPIRV::GET_vfID || 263*0fca6ea1SDimitry Andric MI.getOpcode() == SPIRV::GET_vID || MI.getOpcode() == SPIRV::GET_vpID32 || 264*0fca6ea1SDimitry Andric MI.getOpcode() == SPIRV::GET_vpID64) { 265fcaf7f86SDimitry Andric auto &MRI = MI.getMF()->getRegInfo(); 266fcaf7f86SDimitry Andric MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg()); 267fcaf7f86SDimitry Andric MI.eraseFromParent(); 268fcaf7f86SDimitry Andric return true; 269fcaf7f86SDimitry Andric } 270fcaf7f86SDimitry Andric return false; 271fcaf7f86SDimitry Andric } 272