Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
35268 views
//===-- SPIRVInstrInfo.cpp - SPIR-V Instruction Information ------*- C++-*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains the SPIR-V implementation of the TargetInstrInfo class.9//10//===----------------------------------------------------------------------===//1112#include "SPIRVInstrInfo.h"13#include "SPIRV.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"16#include "llvm/CodeGen/MachineBasicBlock.h"17#include "llvm/IR/DebugLoc.h"18#include "llvm/Support/ErrorHandling.h"1920#define GET_INSTRINFO_CTOR_DTOR21#include "SPIRVGenInstrInfo.inc"2223using namespace llvm;2425SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {}2627bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const {28switch (MI.getOpcode()) {29case SPIRV::OpConstantTrue:30case SPIRV::OpConstantFalse:31case SPIRV::OpConstantI:32case SPIRV::OpConstantF:33case SPIRV::OpConstantComposite:34case SPIRV::OpConstantSampler:35case SPIRV::OpConstantNull:36case SPIRV::OpSpecConstantTrue:37case SPIRV::OpSpecConstantFalse:38case SPIRV::OpSpecConstant:39case SPIRV::OpSpecConstantComposite:40case SPIRV::OpSpecConstantOp:41case SPIRV::OpUndef:42case SPIRV::OpConstantFunctionPointerINTEL:43return true;44default:45return false;46}47}4849bool SPIRVInstrInfo::isInlineAsmDefInstr(const MachineInstr &MI) const {50switch (MI.getOpcode()) {51case SPIRV::OpAsmTargetINTEL:52case SPIRV::OpAsmINTEL:53return true;54default:55return false;56}57}5859bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const {60auto &MRI = MI.getMF()->getRegInfo();61if (MI.getNumDefs() >= 1 && MI.getOperand(0).isReg()) {62auto DefRegClass = MRI.getRegClassOrNull(MI.getOperand(0).getReg());63return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID();64} else {65return MI.getOpcode() == SPIRV::OpTypeForwardPointer;66}67}6869bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const {70switch (MI.getOpcode()) {71case SPIRV::OpDecorate:72case SPIRV::OpDecorateId:73case SPIRV::OpDecorateString:74case SPIRV::OpMemberDecorate:75case SPIRV::OpMemberDecorateString:76return true;77default:78return false;79}80}8182bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const {83switch (MI.getOpcode()) {84case SPIRV::OpCapability:85case SPIRV::OpExtension:86case SPIRV::OpExtInstImport:87case SPIRV::OpMemoryModel:88case SPIRV::OpEntryPoint:89case SPIRV::OpExecutionMode:90case SPIRV::OpExecutionModeId:91case SPIRV::OpString:92case SPIRV::OpSourceExtension:93case SPIRV::OpSource:94case SPIRV::OpSourceContinued:95case SPIRV::OpName:96case SPIRV::OpMemberName:97case SPIRV::OpModuleProcessed:98return true;99default:100return isTypeDeclInstr(MI) || isConstantInstr(MI) || isDecorationInstr(MI);101}102}103104bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const {105switch (MI.getOpcode()) {106case SPIRV::OpFAddS:107case SPIRV::OpFSubS:108case SPIRV::OpFMulS:109case SPIRV::OpFDivS:110case SPIRV::OpFRemS:111case SPIRV::OpFAddV:112case SPIRV::OpFSubV:113case SPIRV::OpFMulV:114case SPIRV::OpFDivV:115case SPIRV::OpFRemV:116case SPIRV::OpFMod:117return true;118default:119return false;120}121}122123bool SPIRVInstrInfo::canUseNSW(const MachineInstr &MI) const {124switch (MI.getOpcode()) {125case SPIRV::OpIAddS:126case SPIRV::OpIAddV:127case SPIRV::OpISubS:128case SPIRV::OpISubV:129case SPIRV::OpIMulS:130case SPIRV::OpIMulV:131case SPIRV::OpShiftLeftLogicalS:132case SPIRV::OpShiftLeftLogicalV:133case SPIRV::OpSNegate:134return true;135default:136return false;137}138}139140bool SPIRVInstrInfo::canUseNUW(const MachineInstr &MI) const {141switch (MI.getOpcode()) {142case SPIRV::OpIAddS:143case SPIRV::OpIAddV:144case SPIRV::OpISubS:145case SPIRV::OpISubV:146case SPIRV::OpIMulS:147case SPIRV::OpIMulV:148return true;149default:150return false;151}152}153154// Analyze the branching code at the end of MBB, returning155// true if it cannot be understood (e.g. it's a switch dispatch or isn't156// implemented for a target). Upon success, this returns false and returns157// with the following information in various cases:158//159// 1. If this block ends with no branches (it just falls through to its succ)160// just return false, leaving TBB/FBB null.161// 2. If this block ends with only an unconditional branch, it sets TBB to be162// the destination block.163// 3. If this block ends with a conditional branch and it falls through to a164// successor block, it sets TBB to be the branch destination block and a165// list of operands that evaluate the condition. These operands can be166// passed to other TargetInstrInfo methods to create new branches.167// 4. If this block ends with a conditional branch followed by an168// unconditional branch, it returns the 'true' destination in TBB, the169// 'false' destination in FBB, and a list of operands that evaluate the170// condition. These operands can be passed to other TargetInstrInfo171// methods to create new branches.172//173// Note that removeBranch and insertBranch must be implemented to support174// cases where this method returns success.175//176// If AllowModify is true, then this routine is allowed to modify the basic177// block (e.g. delete instructions after the unconditional branch).178//179// The CFG information in MBB.Predecessors and MBB.Successors must be valid180// before calling this function.181bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB,182MachineBasicBlock *&TBB,183MachineBasicBlock *&FBB,184SmallVectorImpl<MachineOperand> &Cond,185bool AllowModify) const {186TBB = nullptr;187FBB = nullptr;188if (MBB.empty())189return false;190auto MI = MBB.getLastNonDebugInstr();191if (!MI.isValid())192return false;193if (MI->getOpcode() == SPIRV::OpBranch) {194TBB = MI->getOperand(0).getMBB();195return false;196} else if (MI->getOpcode() == SPIRV::OpBranchConditional) {197Cond.push_back(MI->getOperand(0));198TBB = MI->getOperand(1).getMBB();199if (MI->getNumOperands() == 3) {200FBB = MI->getOperand(2).getMBB();201}202return false;203} else {204return true;205}206}207208// Remove the branching code at the end of the specific MBB.209// This is only invoked in cases where analyzeBranch returns success. It210// returns the number of instructions that were removed.211// If \p BytesRemoved is non-null, report the change in code size from the212// removed instructions.213unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB,214int *BytesRemoved) const {215report_fatal_error("Branch removal not supported, as MBB info not propagated"216" to OpPhi instructions. Try using -O0 instead.");217}218219// Insert branch code into the end of the specified MachineBasicBlock. The220// operands to this method are the same as those returned by analyzeBranch.221// This is only invoked in cases where analyzeBranch returns success. It222// returns the number of instructions inserted. If \p BytesAdded is non-null,223// report the change in code size from the added instructions.224//225// It is also invoked by tail merging to add unconditional branches in226// cases where analyzeBranch doesn't apply because there was no original227// branch to analyze. At least this much must be implemented, else tail228// merging needs to be disabled.229//230// The CFG information in MBB.Predecessors and MBB.Successors must be valid231// before calling this function.232unsigned SPIRVInstrInfo::insertBranch(233MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,234ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {235report_fatal_error("Branch insertion not supported, as MBB info not "236"propagated to OpPhi instructions. Try using "237"-O0 instead.");238}239240void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,241MachineBasicBlock::iterator I,242const DebugLoc &DL, MCRegister DestReg,243MCRegister SrcReg, bool KillSrc) const {244// Actually we don't need this COPY instruction. However if we do nothing with245// it, post RA pseudo instrs expansion just removes it and we get the code246// with undef registers. Therefore, we need to replace all uses of dst with247// the src register. COPY instr itself will be safely removed later.248assert(I->isCopy() && "Copy instruction is expected");249auto DstOp = I->getOperand(0);250auto SrcOp = I->getOperand(1);251assert(DstOp.isReg() && SrcOp.isReg() &&252"Register operands are expected in COPY");253auto &MRI = I->getMF()->getRegInfo();254MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg());255}256257bool SPIRVInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {258if (MI.getOpcode() == SPIRV::GET_ID || MI.getOpcode() == SPIRV::GET_ID64 ||259MI.getOpcode() == SPIRV::GET_fID || MI.getOpcode() == SPIRV::GET_fID64 ||260MI.getOpcode() == SPIRV::GET_pID32 ||261MI.getOpcode() == SPIRV::GET_pID64 || MI.getOpcode() == SPIRV::GET_vfID ||262MI.getOpcode() == SPIRV::GET_vID || MI.getOpcode() == SPIRV::GET_vpID32 ||263MI.getOpcode() == SPIRV::GET_vpID64) {264auto &MRI = MI.getMF()->getRegInfo();265MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg());266MI.eraseFromParent();267return true;268}269return false;270}271272273