1349cc55cSDimitry Andric //===------------------ AMDGPUCustomBehaviour.cpp ---------------*-C++ -* -===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric /// \file 9349cc55cSDimitry Andric /// 10349cc55cSDimitry Andric /// This file implements methods from the AMDGPUCustomBehaviour class. 11349cc55cSDimitry Andric /// 12349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 13349cc55cSDimitry Andric 14349cc55cSDimitry Andric #include "AMDGPUCustomBehaviour.h" 15349cc55cSDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 16349cc55cSDimitry Andric #include "SIInstrInfo.h" 17349cc55cSDimitry Andric #include "TargetInfo/AMDGPUTargetInfo.h" 18349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 19349cc55cSDimitry Andric #include "llvm/Support/WithColor.h" 20349cc55cSDimitry Andric 21349cc55cSDimitry Andric namespace llvm { 22349cc55cSDimitry Andric namespace mca { 23349cc55cSDimitry Andric 24349cc55cSDimitry Andric void AMDGPUInstrPostProcess::postProcessInstruction( 25349cc55cSDimitry Andric std::unique_ptr<Instruction> &Inst, const MCInst &MCI) { 26349cc55cSDimitry Andric switch (MCI.getOpcode()) { 27349cc55cSDimitry Andric case AMDGPU::S_WAITCNT: 28349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_EXPCNT: 29349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_LGKMCNT: 30349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VMCNT: 31349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VSCNT: 32349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_EXPCNT_gfx10: 33349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_LGKMCNT_gfx10: 34349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VMCNT_gfx10: 35349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VSCNT_gfx10: 36349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_gfx10: 37349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_gfx6_gfx7: 38349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_vi: 39349cc55cSDimitry Andric return processWaitCnt(Inst, MCI); 40349cc55cSDimitry Andric } 41349cc55cSDimitry Andric } 42349cc55cSDimitry Andric 43349cc55cSDimitry Andric // s_waitcnt instructions encode important information as immediate operands 44349cc55cSDimitry Andric // which are lost during the MCInst -> mca::Instruction lowering. 45349cc55cSDimitry Andric void AMDGPUInstrPostProcess::processWaitCnt(std::unique_ptr<Instruction> &Inst, 46349cc55cSDimitry Andric const MCInst &MCI) { 47349cc55cSDimitry Andric for (int Idx = 0, N = MCI.size(); Idx < N; Idx++) { 48349cc55cSDimitry Andric MCAOperand Op; 49349cc55cSDimitry Andric const MCOperand &MCOp = MCI.getOperand(Idx); 50349cc55cSDimitry Andric if (MCOp.isReg()) { 51349cc55cSDimitry Andric Op = MCAOperand::createReg(MCOp.getReg()); 52349cc55cSDimitry Andric } else if (MCOp.isImm()) { 53349cc55cSDimitry Andric Op = MCAOperand::createImm(MCOp.getImm()); 54349cc55cSDimitry Andric } 55349cc55cSDimitry Andric Op.setIndex(Idx); 56349cc55cSDimitry Andric Inst->addOperand(Op); 57349cc55cSDimitry Andric } 58349cc55cSDimitry Andric } 59349cc55cSDimitry Andric 60349cc55cSDimitry Andric AMDGPUCustomBehaviour::AMDGPUCustomBehaviour(const MCSubtargetInfo &STI, 61349cc55cSDimitry Andric const mca::SourceMgr &SrcMgr, 62349cc55cSDimitry Andric const MCInstrInfo &MCII) 63349cc55cSDimitry Andric : CustomBehaviour(STI, SrcMgr, MCII) { 64349cc55cSDimitry Andric generateWaitCntInfo(); 65349cc55cSDimitry Andric } 66349cc55cSDimitry Andric 67349cc55cSDimitry Andric unsigned AMDGPUCustomBehaviour::checkCustomHazard(ArrayRef<InstRef> IssuedInst, 68349cc55cSDimitry Andric const InstRef &IR) { 69349cc55cSDimitry Andric const Instruction &Inst = *IR.getInstruction(); 70349cc55cSDimitry Andric unsigned Opcode = Inst.getOpcode(); 71349cc55cSDimitry Andric 72349cc55cSDimitry Andric // llvm-mca is generally run on fully compiled assembly so we wouldn't see any 73349cc55cSDimitry Andric // pseudo instructions here. However, there are plans for the future to make 74349cc55cSDimitry Andric // it possible to use mca within backend passes. As such, I have left the 75349cc55cSDimitry Andric // pseudo version of s_waitcnt within this switch statement. 76349cc55cSDimitry Andric switch (Opcode) { 77349cc55cSDimitry Andric default: 78349cc55cSDimitry Andric return 0; 79349cc55cSDimitry Andric case AMDGPU::S_WAITCNT: // This instruction 80349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_EXPCNT: 81349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_LGKMCNT: 82349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VMCNT: 83349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VSCNT: // to this instruction are all pseudo. 84349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_EXPCNT_gfx10: 85349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_LGKMCNT_gfx10: 86349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VMCNT_gfx10: 87349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VSCNT_gfx10: 88349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_gfx10: 89349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_gfx6_gfx7: 90349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_vi: 91349cc55cSDimitry Andric // s_endpgm also behaves as if there is an implicit 92349cc55cSDimitry Andric // s_waitcnt 0, but I'm not sure if it would be appropriate 93349cc55cSDimitry Andric // to model this in llvm-mca based on how the iterations work 94349cc55cSDimitry Andric // while simulating the pipeline over and over. 95349cc55cSDimitry Andric return handleWaitCnt(IssuedInst, IR); 96349cc55cSDimitry Andric } 97349cc55cSDimitry Andric 98349cc55cSDimitry Andric return 0; 99349cc55cSDimitry Andric } 100349cc55cSDimitry Andric 101349cc55cSDimitry Andric unsigned AMDGPUCustomBehaviour::handleWaitCnt(ArrayRef<InstRef> IssuedInst, 102349cc55cSDimitry Andric const InstRef &IR) { 103349cc55cSDimitry Andric // Currently, all s_waitcnt instructions are handled except s_waitcnt_depctr. 104349cc55cSDimitry Andric // I do not know how that instruction works so I did not attempt to model it. 105349cc55cSDimitry Andric // set the max values to begin 106349cc55cSDimitry Andric unsigned Vmcnt = 63; 107349cc55cSDimitry Andric unsigned Expcnt = 7; 108349cc55cSDimitry Andric unsigned Lgkmcnt = 31; 109349cc55cSDimitry Andric unsigned Vscnt = 63; 110349cc55cSDimitry Andric unsigned CurrVmcnt = 0; 111349cc55cSDimitry Andric unsigned CurrExpcnt = 0; 112349cc55cSDimitry Andric unsigned CurrLgkmcnt = 0; 113349cc55cSDimitry Andric unsigned CurrVscnt = 0; 114349cc55cSDimitry Andric unsigned CyclesToWaitVm = ~0U; 115349cc55cSDimitry Andric unsigned CyclesToWaitExp = ~0U; 116349cc55cSDimitry Andric unsigned CyclesToWaitLgkm = ~0U; 117349cc55cSDimitry Andric unsigned CyclesToWaitVs = ~0U; 118349cc55cSDimitry Andric 119349cc55cSDimitry Andric computeWaitCnt(IR, Vmcnt, Expcnt, Lgkmcnt, Vscnt); 120349cc55cSDimitry Andric 121349cc55cSDimitry Andric // We will now look at each of the currently executing instructions 122349cc55cSDimitry Andric // to find out if this wait instruction still needs to wait. 1230eae32dcSDimitry Andric for (const InstRef &PrevIR : IssuedInst) { 124349cc55cSDimitry Andric const Instruction &PrevInst = *PrevIR.getInstruction(); 125349cc55cSDimitry Andric const unsigned PrevInstIndex = PrevIR.getSourceIndex() % SrcMgr.size(); 126349cc55cSDimitry Andric const WaitCntInfo &PrevInstWaitInfo = InstrWaitCntInfo[PrevInstIndex]; 127349cc55cSDimitry Andric const int CyclesLeft = PrevInst.getCyclesLeft(); 128349cc55cSDimitry Andric assert(CyclesLeft != UNKNOWN_CYCLES && 129349cc55cSDimitry Andric "We should know how many cycles are left for this instruction"); 130349cc55cSDimitry Andric if (PrevInstWaitInfo.VmCnt) { 131349cc55cSDimitry Andric CurrVmcnt++; 132349cc55cSDimitry Andric if ((unsigned)CyclesLeft < CyclesToWaitVm) 133349cc55cSDimitry Andric CyclesToWaitVm = CyclesLeft; 134349cc55cSDimitry Andric } 135349cc55cSDimitry Andric if (PrevInstWaitInfo.ExpCnt) { 136349cc55cSDimitry Andric CurrExpcnt++; 137349cc55cSDimitry Andric if ((unsigned)CyclesLeft < CyclesToWaitExp) 138349cc55cSDimitry Andric CyclesToWaitExp = CyclesLeft; 139349cc55cSDimitry Andric } 140349cc55cSDimitry Andric if (PrevInstWaitInfo.LgkmCnt) { 141349cc55cSDimitry Andric CurrLgkmcnt++; 142349cc55cSDimitry Andric if ((unsigned)CyclesLeft < CyclesToWaitLgkm) 143349cc55cSDimitry Andric CyclesToWaitLgkm = CyclesLeft; 144349cc55cSDimitry Andric } 145349cc55cSDimitry Andric if (PrevInstWaitInfo.VsCnt) { 146349cc55cSDimitry Andric CurrVscnt++; 147349cc55cSDimitry Andric if ((unsigned)CyclesLeft < CyclesToWaitVs) 148349cc55cSDimitry Andric CyclesToWaitVs = CyclesLeft; 149349cc55cSDimitry Andric } 150349cc55cSDimitry Andric } 151349cc55cSDimitry Andric 152349cc55cSDimitry Andric unsigned CyclesToWait = ~0U; 153349cc55cSDimitry Andric if (CurrVmcnt > Vmcnt && CyclesToWaitVm < CyclesToWait) 154349cc55cSDimitry Andric CyclesToWait = CyclesToWaitVm; 155349cc55cSDimitry Andric if (CurrExpcnt > Expcnt && CyclesToWaitExp < CyclesToWait) 156349cc55cSDimitry Andric CyclesToWait = CyclesToWaitExp; 157349cc55cSDimitry Andric if (CurrLgkmcnt > Lgkmcnt && CyclesToWaitLgkm < CyclesToWait) 158349cc55cSDimitry Andric CyclesToWait = CyclesToWaitLgkm; 159349cc55cSDimitry Andric if (CurrVscnt > Vscnt && CyclesToWaitVs < CyclesToWait) 160349cc55cSDimitry Andric CyclesToWait = CyclesToWaitVs; 161349cc55cSDimitry Andric 162349cc55cSDimitry Andric // We may underestimate how many cycles we need to wait, but this 163349cc55cSDimitry Andric // isn't a big deal. Our return value is just how many cycles until 164349cc55cSDimitry Andric // this function gets run again. So as long as we don't overestimate 165349cc55cSDimitry Andric // the wait time, we'll still end up stalling at this instruction 166349cc55cSDimitry Andric // for the correct number of cycles. 167349cc55cSDimitry Andric 168349cc55cSDimitry Andric if (CyclesToWait == ~0U) 169349cc55cSDimitry Andric return 0; 170349cc55cSDimitry Andric return CyclesToWait; 171349cc55cSDimitry Andric } 172349cc55cSDimitry Andric 173349cc55cSDimitry Andric void AMDGPUCustomBehaviour::computeWaitCnt(const InstRef &IR, unsigned &Vmcnt, 174349cc55cSDimitry Andric unsigned &Expcnt, unsigned &Lgkmcnt, 175349cc55cSDimitry Andric unsigned &Vscnt) { 176349cc55cSDimitry Andric AMDGPU::IsaVersion IV = AMDGPU::getIsaVersion(STI.getCPU()); 177349cc55cSDimitry Andric const Instruction &Inst = *IR.getInstruction(); 178349cc55cSDimitry Andric unsigned Opcode = Inst.getOpcode(); 179349cc55cSDimitry Andric 180349cc55cSDimitry Andric switch (Opcode) { 181349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_EXPCNT_gfx10: 182349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_LGKMCNT_gfx10: 183349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VMCNT_gfx10: 184349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VSCNT_gfx10: { 185349cc55cSDimitry Andric // Should probably be checking for nullptr 186349cc55cSDimitry Andric // here, but I'm not sure how I should handle the case 187349cc55cSDimitry Andric // where we see a nullptr. 188349cc55cSDimitry Andric const MCAOperand *OpReg = Inst.getOperand(0); 189349cc55cSDimitry Andric const MCAOperand *OpImm = Inst.getOperand(1); 190349cc55cSDimitry Andric assert(OpReg && OpReg->isReg() && "First operand should be a register."); 191349cc55cSDimitry Andric assert(OpImm && OpImm->isImm() && "Second operand should be an immediate."); 192349cc55cSDimitry Andric if (OpReg->getReg() != AMDGPU::SGPR_NULL) { 193349cc55cSDimitry Andric // Instruction is using a real register. 194349cc55cSDimitry Andric // Since we can't know what value this register will have, 195349cc55cSDimitry Andric // we can't compute what the value of this wait should be. 196349cc55cSDimitry Andric WithColor::warning() << "The register component of " 197349cc55cSDimitry Andric << MCII.getName(Opcode) << " will be completely " 198349cc55cSDimitry Andric << "ignored. So the wait may not be accurate.\n"; 199349cc55cSDimitry Andric } 200349cc55cSDimitry Andric switch (Opcode) { 201349cc55cSDimitry Andric // Redundant switch so I don't have to repeat the code above 202349cc55cSDimitry Andric // for each case. There are more clever ways to avoid this 203349cc55cSDimitry Andric // extra switch and anyone can feel free to implement one of them. 204349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_EXPCNT_gfx10: 205349cc55cSDimitry Andric Expcnt = OpImm->getImm(); 206349cc55cSDimitry Andric break; 207349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_LGKMCNT_gfx10: 208349cc55cSDimitry Andric Lgkmcnt = OpImm->getImm(); 209349cc55cSDimitry Andric break; 210349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VMCNT_gfx10: 211349cc55cSDimitry Andric Vmcnt = OpImm->getImm(); 212349cc55cSDimitry Andric break; 213349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_VSCNT_gfx10: 214349cc55cSDimitry Andric Vscnt = OpImm->getImm(); 215349cc55cSDimitry Andric break; 216349cc55cSDimitry Andric } 217349cc55cSDimitry Andric return; 218349cc55cSDimitry Andric } 219349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_gfx10: 220349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_gfx6_gfx7: 221349cc55cSDimitry Andric case AMDGPU::S_WAITCNT_vi: 222349cc55cSDimitry Andric unsigned WaitCnt = Inst.getOperand(0)->getImm(); 223349cc55cSDimitry Andric AMDGPU::decodeWaitcnt(IV, WaitCnt, Vmcnt, Expcnt, Lgkmcnt); 224349cc55cSDimitry Andric return; 225349cc55cSDimitry Andric } 226349cc55cSDimitry Andric } 227349cc55cSDimitry Andric 228349cc55cSDimitry Andric void AMDGPUCustomBehaviour::generateWaitCntInfo() { 229349cc55cSDimitry Andric // The core logic from this function is taken from 230349cc55cSDimitry Andric // SIInsertWaitcnts::updateEventWaitcntAfter() In that pass, the instructions 231349cc55cSDimitry Andric // that are being looked at are in the MachineInstr format, whereas we have 232349cc55cSDimitry Andric // access to the MCInst format. The side effects of this are that we can't use 233349cc55cSDimitry Andric // the mayAccessVMEMThroughFlat(Inst) or mayAccessLDSThroughFlat(Inst) 234349cc55cSDimitry Andric // functions. Therefore, we conservatively assume that these functions will 235349cc55cSDimitry Andric // return true. This may cause a few instructions to be incorrectly tagged 236349cc55cSDimitry Andric // with an extra CNT. However, these are instructions that do interact with at 237349cc55cSDimitry Andric // least one CNT so giving them an extra CNT shouldn't cause issues in most 238349cc55cSDimitry Andric // scenarios. 239349cc55cSDimitry Andric AMDGPU::IsaVersion IV = AMDGPU::getIsaVersion(STI.getCPU()); 240349cc55cSDimitry Andric InstrWaitCntInfo.resize(SrcMgr.size()); 241349cc55cSDimitry Andric 242*81ad6265SDimitry Andric for (const auto &EN : llvm::enumerate(SrcMgr.getInstructions())) { 243*81ad6265SDimitry Andric const std::unique_ptr<Instruction> &Inst = EN.value(); 244*81ad6265SDimitry Andric unsigned Index = EN.index(); 245349cc55cSDimitry Andric unsigned Opcode = Inst->getOpcode(); 246349cc55cSDimitry Andric const MCInstrDesc &MCID = MCII.get(Opcode); 247349cc55cSDimitry Andric if ((MCID.TSFlags & SIInstrFlags::DS) && 248349cc55cSDimitry Andric (MCID.TSFlags & SIInstrFlags::LGKM_CNT)) { 249349cc55cSDimitry Andric InstrWaitCntInfo[Index].LgkmCnt = true; 250349cc55cSDimitry Andric if (isAlwaysGDS(Opcode) || hasModifiersSet(Inst, AMDGPU::OpName::gds)) 251349cc55cSDimitry Andric InstrWaitCntInfo[Index].ExpCnt = true; 252349cc55cSDimitry Andric } else if (MCID.TSFlags & SIInstrFlags::FLAT) { 253349cc55cSDimitry Andric // We conservatively assume that mayAccessVMEMThroughFlat(Inst) 254349cc55cSDimitry Andric // and mayAccessLDSThroughFlat(Inst) would both return true for this 255349cc55cSDimitry Andric // instruction. We have to do this because those functions use 256349cc55cSDimitry Andric // information about the memory operands that we don't have access to. 257349cc55cSDimitry Andric InstrWaitCntInfo[Index].LgkmCnt = true; 258349cc55cSDimitry Andric if (!STI.hasFeature(AMDGPU::FeatureVscnt)) 259349cc55cSDimitry Andric InstrWaitCntInfo[Index].VmCnt = true; 260349cc55cSDimitry Andric else if (MCID.mayLoad() && !(MCID.TSFlags & SIInstrFlags::IsAtomicNoRet)) 261349cc55cSDimitry Andric InstrWaitCntInfo[Index].VmCnt = true; 262349cc55cSDimitry Andric else 263349cc55cSDimitry Andric InstrWaitCntInfo[Index].VsCnt = true; 264349cc55cSDimitry Andric } else if (isVMEM(MCID) && !AMDGPU::getMUBUFIsBufferInv(Opcode)) { 265349cc55cSDimitry Andric if (!STI.hasFeature(AMDGPU::FeatureVscnt)) 266349cc55cSDimitry Andric InstrWaitCntInfo[Index].VmCnt = true; 267349cc55cSDimitry Andric else if ((MCID.mayLoad() && 268349cc55cSDimitry Andric !(MCID.TSFlags & SIInstrFlags::IsAtomicNoRet)) || 269349cc55cSDimitry Andric ((MCID.TSFlags & SIInstrFlags::MIMG) && !MCID.mayLoad() && 270349cc55cSDimitry Andric !MCID.mayStore())) 271349cc55cSDimitry Andric InstrWaitCntInfo[Index].VmCnt = true; 272349cc55cSDimitry Andric else if (MCID.mayStore()) 273349cc55cSDimitry Andric InstrWaitCntInfo[Index].VsCnt = true; 274349cc55cSDimitry Andric 275349cc55cSDimitry Andric // (IV.Major < 7) is meant to represent 276349cc55cSDimitry Andric // GCNTarget.vmemWriteNeedsExpWaitcnt() 277349cc55cSDimitry Andric // which is defined as 278349cc55cSDimitry Andric // { return getGeneration() < SEA_ISLANDS; } 279349cc55cSDimitry Andric if (IV.Major < 7 && 280349cc55cSDimitry Andric (MCID.mayStore() || (MCID.TSFlags & SIInstrFlags::IsAtomicRet))) 281349cc55cSDimitry Andric InstrWaitCntInfo[Index].ExpCnt = true; 282349cc55cSDimitry Andric } else if (MCID.TSFlags & SIInstrFlags::SMRD) { 283349cc55cSDimitry Andric InstrWaitCntInfo[Index].LgkmCnt = true; 284349cc55cSDimitry Andric } else if (MCID.TSFlags & SIInstrFlags::EXP) { 285349cc55cSDimitry Andric InstrWaitCntInfo[Index].ExpCnt = true; 286349cc55cSDimitry Andric } else { 287349cc55cSDimitry Andric switch (Opcode) { 288349cc55cSDimitry Andric case AMDGPU::S_SENDMSG: 289349cc55cSDimitry Andric case AMDGPU::S_SENDMSGHALT: 290349cc55cSDimitry Andric case AMDGPU::S_MEMTIME: 291349cc55cSDimitry Andric case AMDGPU::S_MEMREALTIME: 292349cc55cSDimitry Andric InstrWaitCntInfo[Index].LgkmCnt = true; 293349cc55cSDimitry Andric break; 294349cc55cSDimitry Andric } 295349cc55cSDimitry Andric } 296349cc55cSDimitry Andric } 297349cc55cSDimitry Andric } 298349cc55cSDimitry Andric 299349cc55cSDimitry Andric // taken from SIInstrInfo::isVMEM() 300349cc55cSDimitry Andric bool AMDGPUCustomBehaviour::isVMEM(const MCInstrDesc &MCID) { 301349cc55cSDimitry Andric return MCID.TSFlags & SIInstrFlags::MUBUF || 302349cc55cSDimitry Andric MCID.TSFlags & SIInstrFlags::MTBUF || 303349cc55cSDimitry Andric MCID.TSFlags & SIInstrFlags::MIMG; 304349cc55cSDimitry Andric } 305349cc55cSDimitry Andric 306349cc55cSDimitry Andric // taken from SIInstrInfo::hasModifiersSet() 307349cc55cSDimitry Andric bool AMDGPUCustomBehaviour::hasModifiersSet( 308349cc55cSDimitry Andric const std::unique_ptr<Instruction> &Inst, unsigned OpName) const { 309349cc55cSDimitry Andric int Idx = AMDGPU::getNamedOperandIdx(Inst->getOpcode(), OpName); 310349cc55cSDimitry Andric if (Idx == -1) 311349cc55cSDimitry Andric return false; 312349cc55cSDimitry Andric 313349cc55cSDimitry Andric const MCAOperand *Op = Inst->getOperand(Idx); 314349cc55cSDimitry Andric if (Op == nullptr || !Op->isImm() || !Op->getImm()) 315349cc55cSDimitry Andric return false; 316349cc55cSDimitry Andric 317349cc55cSDimitry Andric return true; 318349cc55cSDimitry Andric } 319349cc55cSDimitry Andric 320349cc55cSDimitry Andric // taken from SIInstrInfo::isAlwaysGDS() 321349cc55cSDimitry Andric bool AMDGPUCustomBehaviour::isAlwaysGDS(uint16_t Opcode) const { 322349cc55cSDimitry Andric return Opcode == AMDGPU::DS_ORDERED_COUNT || Opcode == AMDGPU::DS_GWS_INIT || 323349cc55cSDimitry Andric Opcode == AMDGPU::DS_GWS_SEMA_V || Opcode == AMDGPU::DS_GWS_SEMA_BR || 324349cc55cSDimitry Andric Opcode == AMDGPU::DS_GWS_SEMA_P || 325349cc55cSDimitry Andric Opcode == AMDGPU::DS_GWS_SEMA_RELEASE_ALL || 326349cc55cSDimitry Andric Opcode == AMDGPU::DS_GWS_BARRIER; 327349cc55cSDimitry Andric } 328349cc55cSDimitry Andric 329349cc55cSDimitry Andric } // namespace mca 330349cc55cSDimitry Andric } // namespace llvm 331349cc55cSDimitry Andric 332349cc55cSDimitry Andric using namespace llvm; 333349cc55cSDimitry Andric using namespace mca; 334349cc55cSDimitry Andric 335349cc55cSDimitry Andric static CustomBehaviour * 336349cc55cSDimitry Andric createAMDGPUCustomBehaviour(const MCSubtargetInfo &STI, 337349cc55cSDimitry Andric const mca::SourceMgr &SrcMgr, 338349cc55cSDimitry Andric const MCInstrInfo &MCII) { 339349cc55cSDimitry Andric return new AMDGPUCustomBehaviour(STI, SrcMgr, MCII); 340349cc55cSDimitry Andric } 341349cc55cSDimitry Andric 342349cc55cSDimitry Andric static InstrPostProcess * 343349cc55cSDimitry Andric createAMDGPUInstrPostProcess(const MCSubtargetInfo &STI, 344349cc55cSDimitry Andric const MCInstrInfo &MCII) { 345349cc55cSDimitry Andric return new AMDGPUInstrPostProcess(STI, MCII); 346349cc55cSDimitry Andric } 347349cc55cSDimitry Andric 348349cc55cSDimitry Andric /// Extern function to initialize the targets for the AMDGPU backend 349349cc55cSDimitry Andric 350349cc55cSDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAMDGPUTargetMCA() { 351349cc55cSDimitry Andric TargetRegistry::RegisterCustomBehaviour(getTheAMDGPUTarget(), 352349cc55cSDimitry Andric createAMDGPUCustomBehaviour); 353349cc55cSDimitry Andric TargetRegistry::RegisterInstrPostProcess(getTheAMDGPUTarget(), 354349cc55cSDimitry Andric createAMDGPUInstrPostProcess); 355349cc55cSDimitry Andric 356349cc55cSDimitry Andric TargetRegistry::RegisterCustomBehaviour(getTheGCNTarget(), 357349cc55cSDimitry Andric createAMDGPUCustomBehaviour); 358349cc55cSDimitry Andric TargetRegistry::RegisterInstrPostProcess(getTheGCNTarget(), 359349cc55cSDimitry Andric createAMDGPUInstrPostProcess); 360349cc55cSDimitry Andric } 361