xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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