10b57cec5SDimitry Andric //===-- R600InstrInfo.cpp - R600 Instruction Information ------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// R600 Implementation of TargetInstrInfo.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "R600InstrInfo.h"
150b57cec5SDimitry Andric #include "AMDGPU.h"
16349cc55cSDimitry Andric #include "MCTargetDesc/R600MCTargetDesc.h"
17349cc55cSDimitry Andric #include "R600.h"
18e8d8bef9SDimitry Andric #include "R600Defines.h"
19e8d8bef9SDimitry Andric #include "R600Subtarget.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
2181ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR
260b57cec5SDimitry Andric #include "R600GenDFAPacketizer.inc"
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR
290b57cec5SDimitry Andric #define GET_INSTRMAP_INFO
300b57cec5SDimitry Andric #define GET_INSTRINFO_NAMED_OPS
310b57cec5SDimitry Andric #include "R600GenInstrInfo.inc"
320b57cec5SDimitry Andric 
R600InstrInfo(const R600Subtarget & ST)330b57cec5SDimitry Andric R600InstrInfo::R600InstrInfo(const R600Subtarget &ST)
340b57cec5SDimitry Andric   : R600GenInstrInfo(-1, -1), RI(), ST(ST) {}
350b57cec5SDimitry Andric 
isVector(const MachineInstr & MI) const360b57cec5SDimitry Andric bool R600InstrInfo::isVector(const MachineInstr &MI) const {
370b57cec5SDimitry Andric   return get(MI.getOpcode()).TSFlags & R600_InstFlag::VECTOR;
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric 
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator MI,const DebugLoc & DL,MCRegister DestReg,MCRegister SrcReg,bool KillSrc) const400b57cec5SDimitry Andric void R600InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
410b57cec5SDimitry Andric                                 MachineBasicBlock::iterator MI,
42480093f4SDimitry Andric                                 const DebugLoc &DL, MCRegister DestReg,
43480093f4SDimitry Andric                                 MCRegister SrcReg, bool KillSrc) const {
440b57cec5SDimitry Andric   unsigned VectorComponents = 0;
450b57cec5SDimitry Andric   if ((R600::R600_Reg128RegClass.contains(DestReg) ||
460b57cec5SDimitry Andric       R600::R600_Reg128VerticalRegClass.contains(DestReg)) &&
470b57cec5SDimitry Andric       (R600::R600_Reg128RegClass.contains(SrcReg) ||
480b57cec5SDimitry Andric        R600::R600_Reg128VerticalRegClass.contains(SrcReg))) {
490b57cec5SDimitry Andric     VectorComponents = 4;
500b57cec5SDimitry Andric   } else if((R600::R600_Reg64RegClass.contains(DestReg) ||
510b57cec5SDimitry Andric             R600::R600_Reg64VerticalRegClass.contains(DestReg)) &&
520b57cec5SDimitry Andric             (R600::R600_Reg64RegClass.contains(SrcReg) ||
530b57cec5SDimitry Andric              R600::R600_Reg64VerticalRegClass.contains(SrcReg))) {
540b57cec5SDimitry Andric     VectorComponents = 2;
550b57cec5SDimitry Andric   }
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   if (VectorComponents > 0) {
580b57cec5SDimitry Andric     for (unsigned I = 0; I < VectorComponents; I++) {
595ffd83dbSDimitry Andric       unsigned SubRegIndex = R600RegisterInfo::getSubRegFromChannel(I);
600b57cec5SDimitry Andric       buildDefaultInstruction(MBB, MI, R600::MOV,
610b57cec5SDimitry Andric                               RI.getSubReg(DestReg, SubRegIndex),
620b57cec5SDimitry Andric                               RI.getSubReg(SrcReg, SubRegIndex))
630b57cec5SDimitry Andric                               .addReg(DestReg,
640b57cec5SDimitry Andric                                       RegState::Define | RegState::Implicit);
650b57cec5SDimitry Andric     }
660b57cec5SDimitry Andric   } else {
670b57cec5SDimitry Andric     MachineInstr *NewMI = buildDefaultInstruction(MBB, MI, R600::MOV,
680b57cec5SDimitry Andric                                                   DestReg, SrcReg);
690b57cec5SDimitry Andric     NewMI->getOperand(getOperandIdx(*NewMI, R600::OpName::src0))
700b57cec5SDimitry Andric                                     .setIsKill(KillSrc);
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric /// \returns true if \p MBBI can be moved into a new basic.
isLegalToSplitMBBAt(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI) const750b57cec5SDimitry Andric bool R600InstrInfo::isLegalToSplitMBBAt(MachineBasicBlock &MBB,
760b57cec5SDimitry Andric                                        MachineBasicBlock::iterator MBBI) const {
770b57cec5SDimitry Andric   for (MachineInstr::const_mop_iterator I = MBBI->operands_begin(),
780b57cec5SDimitry Andric                                         E = MBBI->operands_end(); I != E; ++I) {
79e8d8bef9SDimitry Andric     if (I->isReg() && !I->getReg().isVirtual() && I->isUse() &&
808bcb0991SDimitry Andric         RI.isPhysRegLiveAcrossClauses(I->getReg()))
810b57cec5SDimitry Andric       return false;
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric   return true;
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
isMov(unsigned Opcode) const860b57cec5SDimitry Andric bool R600InstrInfo::isMov(unsigned Opcode) const {
870b57cec5SDimitry Andric   switch(Opcode) {
880b57cec5SDimitry Andric   default:
890b57cec5SDimitry Andric     return false;
900b57cec5SDimitry Andric   case R600::MOV:
910b57cec5SDimitry Andric   case R600::MOV_IMM_F32:
920b57cec5SDimitry Andric   case R600::MOV_IMM_I32:
930b57cec5SDimitry Andric     return true;
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
isReductionOp(unsigned Opcode) const970b57cec5SDimitry Andric bool R600InstrInfo::isReductionOp(unsigned Opcode) const {
980b57cec5SDimitry Andric   return false;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
isCubeOp(unsigned Opcode) const1010b57cec5SDimitry Andric bool R600InstrInfo::isCubeOp(unsigned Opcode) const {
1020b57cec5SDimitry Andric   switch(Opcode) {
1030b57cec5SDimitry Andric     default: return false;
1040b57cec5SDimitry Andric     case R600::CUBE_r600_pseudo:
1050b57cec5SDimitry Andric     case R600::CUBE_r600_real:
1060b57cec5SDimitry Andric     case R600::CUBE_eg_pseudo:
1070b57cec5SDimitry Andric     case R600::CUBE_eg_real:
1080b57cec5SDimitry Andric       return true;
1090b57cec5SDimitry Andric   }
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric 
isALUInstr(unsigned Opcode) const1120b57cec5SDimitry Andric bool R600InstrInfo::isALUInstr(unsigned Opcode) const {
1130b57cec5SDimitry Andric   unsigned TargetFlags = get(Opcode).TSFlags;
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   return (TargetFlags & R600_InstFlag::ALU_INST);
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
hasInstrModifiers(unsigned Opcode) const1180b57cec5SDimitry Andric bool R600InstrInfo::hasInstrModifiers(unsigned Opcode) const {
1190b57cec5SDimitry Andric   unsigned TargetFlags = get(Opcode).TSFlags;
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   return ((TargetFlags & R600_InstFlag::OP1) |
1220b57cec5SDimitry Andric           (TargetFlags & R600_InstFlag::OP2) |
1230b57cec5SDimitry Andric           (TargetFlags & R600_InstFlag::OP3));
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric 
isLDSInstr(unsigned Opcode) const1260b57cec5SDimitry Andric bool R600InstrInfo::isLDSInstr(unsigned Opcode) const {
1270b57cec5SDimitry Andric   unsigned TargetFlags = get(Opcode).TSFlags;
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   return ((TargetFlags & R600_InstFlag::LDS_1A) |
1300b57cec5SDimitry Andric           (TargetFlags & R600_InstFlag::LDS_1A1D) |
1310b57cec5SDimitry Andric           (TargetFlags & R600_InstFlag::LDS_1A2D));
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
isLDSRetInstr(unsigned Opcode) const1340b57cec5SDimitry Andric bool R600InstrInfo::isLDSRetInstr(unsigned Opcode) const {
1350b57cec5SDimitry Andric   return isLDSInstr(Opcode) && getOperandIdx(Opcode, R600::OpName::dst) != -1;
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric 
canBeConsideredALU(const MachineInstr & MI) const1380b57cec5SDimitry Andric bool R600InstrInfo::canBeConsideredALU(const MachineInstr &MI) const {
1390b57cec5SDimitry Andric   if (isALUInstr(MI.getOpcode()))
1400b57cec5SDimitry Andric     return true;
1410b57cec5SDimitry Andric   if (isVector(MI) || isCubeOp(MI.getOpcode()))
1420b57cec5SDimitry Andric     return true;
1430b57cec5SDimitry Andric   switch (MI.getOpcode()) {
1440b57cec5SDimitry Andric   case R600::PRED_X:
1450b57cec5SDimitry Andric   case R600::INTERP_PAIR_XY:
1460b57cec5SDimitry Andric   case R600::INTERP_PAIR_ZW:
1470b57cec5SDimitry Andric   case R600::INTERP_VEC_LOAD:
1480b57cec5SDimitry Andric   case R600::COPY:
1490b57cec5SDimitry Andric   case R600::DOT_4:
1500b57cec5SDimitry Andric     return true;
1510b57cec5SDimitry Andric   default:
1520b57cec5SDimitry Andric     return false;
1530b57cec5SDimitry Andric   }
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric 
isTransOnly(unsigned Opcode) const1560b57cec5SDimitry Andric bool R600InstrInfo::isTransOnly(unsigned Opcode) const {
1570b57cec5SDimitry Andric   if (ST.hasCaymanISA())
1580b57cec5SDimitry Andric     return false;
1590b57cec5SDimitry Andric   return (get(Opcode).getSchedClass() == R600::Sched::TransALU);
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
isTransOnly(const MachineInstr & MI) const1620b57cec5SDimitry Andric bool R600InstrInfo::isTransOnly(const MachineInstr &MI) const {
1630b57cec5SDimitry Andric   return isTransOnly(MI.getOpcode());
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
isVectorOnly(unsigned Opcode) const1660b57cec5SDimitry Andric bool R600InstrInfo::isVectorOnly(unsigned Opcode) const {
1670b57cec5SDimitry Andric   return (get(Opcode).getSchedClass() == R600::Sched::VecALU);
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
isVectorOnly(const MachineInstr & MI) const1700b57cec5SDimitry Andric bool R600InstrInfo::isVectorOnly(const MachineInstr &MI) const {
1710b57cec5SDimitry Andric   return isVectorOnly(MI.getOpcode());
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric 
isExport(unsigned Opcode) const1740b57cec5SDimitry Andric bool R600InstrInfo::isExport(unsigned Opcode) const {
1750b57cec5SDimitry Andric   return (get(Opcode).TSFlags & R600_InstFlag::IS_EXPORT);
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric 
usesVertexCache(unsigned Opcode) const1780b57cec5SDimitry Andric bool R600InstrInfo::usesVertexCache(unsigned Opcode) const {
1790b57cec5SDimitry Andric   return ST.hasVertexCache() && IS_VTX(get(Opcode));
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
usesVertexCache(const MachineInstr & MI) const1820b57cec5SDimitry Andric bool R600InstrInfo::usesVertexCache(const MachineInstr &MI) const {
1830b57cec5SDimitry Andric   const MachineFunction *MF = MI.getParent()->getParent();
1840b57cec5SDimitry Andric   return !AMDGPU::isCompute(MF->getFunction().getCallingConv()) &&
1850b57cec5SDimitry Andric          usesVertexCache(MI.getOpcode());
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
usesTextureCache(unsigned Opcode) const1880b57cec5SDimitry Andric bool R600InstrInfo::usesTextureCache(unsigned Opcode) const {
1890b57cec5SDimitry Andric   return (!ST.hasVertexCache() && IS_VTX(get(Opcode))) || IS_TEX(get(Opcode));
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
usesTextureCache(const MachineInstr & MI) const1920b57cec5SDimitry Andric bool R600InstrInfo::usesTextureCache(const MachineInstr &MI) const {
1930b57cec5SDimitry Andric   const MachineFunction *MF = MI.getParent()->getParent();
1940b57cec5SDimitry Andric   return (AMDGPU::isCompute(MF->getFunction().getCallingConv()) &&
1950b57cec5SDimitry Andric           usesVertexCache(MI.getOpcode())) ||
1960b57cec5SDimitry Andric           usesTextureCache(MI.getOpcode());
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
mustBeLastInClause(unsigned Opcode) const1990b57cec5SDimitry Andric bool R600InstrInfo::mustBeLastInClause(unsigned Opcode) const {
2000b57cec5SDimitry Andric   switch (Opcode) {
2010b57cec5SDimitry Andric   case R600::KILLGT:
2020b57cec5SDimitry Andric   case R600::GROUP_BARRIER:
2030b57cec5SDimitry Andric     return true;
2040b57cec5SDimitry Andric   default:
2050b57cec5SDimitry Andric     return false;
2060b57cec5SDimitry Andric   }
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
usesAddressRegister(MachineInstr & MI) const2090b57cec5SDimitry Andric bool R600InstrInfo::usesAddressRegister(MachineInstr &MI) const {
2100b57cec5SDimitry Andric   return MI.findRegisterUseOperandIdx(R600::AR_X, false, &RI) != -1;
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
definesAddressRegister(MachineInstr & MI) const2130b57cec5SDimitry Andric bool R600InstrInfo::definesAddressRegister(MachineInstr &MI) const {
2140b57cec5SDimitry Andric   return MI.findRegisterDefOperandIdx(R600::AR_X, false, false, &RI) != -1;
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric 
readsLDSSrcReg(const MachineInstr & MI) const2170b57cec5SDimitry Andric bool R600InstrInfo::readsLDSSrcReg(const MachineInstr &MI) const {
2180b57cec5SDimitry Andric   if (!isALUInstr(MI.getOpcode())) {
2190b57cec5SDimitry Andric     return false;
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric   for (MachineInstr::const_mop_iterator I = MI.operands_begin(),
2220b57cec5SDimitry Andric                                         E = MI.operands_end();
2230b57cec5SDimitry Andric        I != E; ++I) {
224e8d8bef9SDimitry Andric     if (!I->isReg() || !I->isUse() || I->getReg().isVirtual())
2250b57cec5SDimitry Andric       continue;
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric     if (R600::R600_LDS_SRC_REGRegClass.contains(I->getReg()))
2280b57cec5SDimitry Andric       return true;
2290b57cec5SDimitry Andric   }
2300b57cec5SDimitry Andric   return false;
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
getSelIdx(unsigned Opcode,unsigned SrcIdx) const2330b57cec5SDimitry Andric int R600InstrInfo::getSelIdx(unsigned Opcode, unsigned SrcIdx) const {
2340b57cec5SDimitry Andric   static const unsigned SrcSelTable[][2] = {
2350b57cec5SDimitry Andric     {R600::OpName::src0, R600::OpName::src0_sel},
2360b57cec5SDimitry Andric     {R600::OpName::src1, R600::OpName::src1_sel},
2370b57cec5SDimitry Andric     {R600::OpName::src2, R600::OpName::src2_sel},
2380b57cec5SDimitry Andric     {R600::OpName::src0_X, R600::OpName::src0_sel_X},
2390b57cec5SDimitry Andric     {R600::OpName::src0_Y, R600::OpName::src0_sel_Y},
2400b57cec5SDimitry Andric     {R600::OpName::src0_Z, R600::OpName::src0_sel_Z},
2410b57cec5SDimitry Andric     {R600::OpName::src0_W, R600::OpName::src0_sel_W},
2420b57cec5SDimitry Andric     {R600::OpName::src1_X, R600::OpName::src1_sel_X},
2430b57cec5SDimitry Andric     {R600::OpName::src1_Y, R600::OpName::src1_sel_Y},
2440b57cec5SDimitry Andric     {R600::OpName::src1_Z, R600::OpName::src1_sel_Z},
2450b57cec5SDimitry Andric     {R600::OpName::src1_W, R600::OpName::src1_sel_W}
2460b57cec5SDimitry Andric   };
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   for (const auto &Row : SrcSelTable) {
2490b57cec5SDimitry Andric     if (getOperandIdx(Opcode, Row[0]) == (int)SrcIdx) {
2500b57cec5SDimitry Andric       return getOperandIdx(Opcode, Row[1]);
2510b57cec5SDimitry Andric     }
2520b57cec5SDimitry Andric   }
2530b57cec5SDimitry Andric   return -1;
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric SmallVector<std::pair<MachineOperand *, int64_t>, 3>
getSrcs(MachineInstr & MI) const2570b57cec5SDimitry Andric R600InstrInfo::getSrcs(MachineInstr &MI) const {
2580b57cec5SDimitry Andric   SmallVector<std::pair<MachineOperand *, int64_t>, 3> Result;
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   if (MI.getOpcode() == R600::DOT_4) {
2610b57cec5SDimitry Andric     static const unsigned OpTable[8][2] = {
2620b57cec5SDimitry Andric       {R600::OpName::src0_X, R600::OpName::src0_sel_X},
2630b57cec5SDimitry Andric       {R600::OpName::src0_Y, R600::OpName::src0_sel_Y},
2640b57cec5SDimitry Andric       {R600::OpName::src0_Z, R600::OpName::src0_sel_Z},
2650b57cec5SDimitry Andric       {R600::OpName::src0_W, R600::OpName::src0_sel_W},
2660b57cec5SDimitry Andric       {R600::OpName::src1_X, R600::OpName::src1_sel_X},
2670b57cec5SDimitry Andric       {R600::OpName::src1_Y, R600::OpName::src1_sel_Y},
2680b57cec5SDimitry Andric       {R600::OpName::src1_Z, R600::OpName::src1_sel_Z},
2690b57cec5SDimitry Andric       {R600::OpName::src1_W, R600::OpName::src1_sel_W},
2700b57cec5SDimitry Andric     };
2710b57cec5SDimitry Andric 
2720eae32dcSDimitry Andric     for (const auto &Op : OpTable) {
2730eae32dcSDimitry Andric       MachineOperand &MO = MI.getOperand(getOperandIdx(MI.getOpcode(), Op[0]));
2748bcb0991SDimitry Andric       Register Reg = MO.getReg();
2750b57cec5SDimitry Andric       if (Reg == R600::ALU_CONST) {
2760b57cec5SDimitry Andric         MachineOperand &Sel =
2770eae32dcSDimitry Andric             MI.getOperand(getOperandIdx(MI.getOpcode(), Op[1]));
278bdd1243dSDimitry Andric         Result.push_back(std::pair(&MO, Sel.getImm()));
2790b57cec5SDimitry Andric         continue;
2800b57cec5SDimitry Andric       }
2810b57cec5SDimitry Andric     }
2820b57cec5SDimitry Andric     return Result;
2830b57cec5SDimitry Andric   }
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric   static const unsigned OpTable[3][2] = {
2860b57cec5SDimitry Andric     {R600::OpName::src0, R600::OpName::src0_sel},
2870b57cec5SDimitry Andric     {R600::OpName::src1, R600::OpName::src1_sel},
2880b57cec5SDimitry Andric     {R600::OpName::src2, R600::OpName::src2_sel},
2890b57cec5SDimitry Andric   };
2900b57cec5SDimitry Andric 
2910eae32dcSDimitry Andric   for (const auto &Op : OpTable) {
2920eae32dcSDimitry Andric     int SrcIdx = getOperandIdx(MI.getOpcode(), Op[0]);
2930b57cec5SDimitry Andric     if (SrcIdx < 0)
2940b57cec5SDimitry Andric       break;
2950b57cec5SDimitry Andric     MachineOperand &MO = MI.getOperand(SrcIdx);
2968bcb0991SDimitry Andric     Register Reg = MO.getReg();
2970b57cec5SDimitry Andric     if (Reg == R600::ALU_CONST) {
2980eae32dcSDimitry Andric       MachineOperand &Sel = MI.getOperand(getOperandIdx(MI.getOpcode(), Op[1]));
299bdd1243dSDimitry Andric       Result.push_back(std::pair(&MO, Sel.getImm()));
3000b57cec5SDimitry Andric       continue;
3010b57cec5SDimitry Andric     }
3020b57cec5SDimitry Andric     if (Reg == R600::ALU_LITERAL_X) {
3030b57cec5SDimitry Andric       MachineOperand &Operand =
3040b57cec5SDimitry Andric           MI.getOperand(getOperandIdx(MI.getOpcode(), R600::OpName::literal));
3050b57cec5SDimitry Andric       if (Operand.isImm()) {
306bdd1243dSDimitry Andric         Result.push_back(std::pair(&MO, Operand.getImm()));
3070b57cec5SDimitry Andric         continue;
3080b57cec5SDimitry Andric       }
3090b57cec5SDimitry Andric       assert(Operand.isGlobal());
3100b57cec5SDimitry Andric     }
311bdd1243dSDimitry Andric     Result.push_back(std::pair(&MO, 0));
3120b57cec5SDimitry Andric   }
3130b57cec5SDimitry Andric   return Result;
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric std::vector<std::pair<int, unsigned>>
ExtractSrcs(MachineInstr & MI,const DenseMap<unsigned,unsigned> & PV,unsigned & ConstCount) const3170b57cec5SDimitry Andric R600InstrInfo::ExtractSrcs(MachineInstr &MI,
3180b57cec5SDimitry Andric                            const DenseMap<unsigned, unsigned> &PV,
3190b57cec5SDimitry Andric                            unsigned &ConstCount) const {
3200b57cec5SDimitry Andric   ConstCount = 0;
3210b57cec5SDimitry Andric   const std::pair<int, unsigned> DummyPair(-1, 0);
3220b57cec5SDimitry Andric   std::vector<std::pair<int, unsigned>> Result;
3230b57cec5SDimitry Andric   unsigned i = 0;
3240b57cec5SDimitry Andric   for (const auto &Src : getSrcs(MI)) {
3250b57cec5SDimitry Andric     ++i;
3268bcb0991SDimitry Andric     Register Reg = Src.first->getReg();
3270b57cec5SDimitry Andric     int Index = RI.getEncodingValue(Reg) & 0xff;
3280b57cec5SDimitry Andric     if (Reg == R600::OQAP) {
329bdd1243dSDimitry Andric       Result.push_back(std::pair(Index, 0U));
3300b57cec5SDimitry Andric     }
33106c3fb27SDimitry Andric     if (PV.contains(Reg)) {
3320b57cec5SDimitry Andric       // 255 is used to tells its a PS/PV reg
333bdd1243dSDimitry Andric       Result.push_back(std::pair(255, 0U));
3340b57cec5SDimitry Andric       continue;
3350b57cec5SDimitry Andric     }
3360b57cec5SDimitry Andric     if (Index > 127) {
3370b57cec5SDimitry Andric       ConstCount++;
3380b57cec5SDimitry Andric       Result.push_back(DummyPair);
3390b57cec5SDimitry Andric       continue;
3400b57cec5SDimitry Andric     }
3410b57cec5SDimitry Andric     unsigned Chan = RI.getHWRegChan(Reg);
342bdd1243dSDimitry Andric     Result.push_back(std::pair(Index, Chan));
3430b57cec5SDimitry Andric   }
3440b57cec5SDimitry Andric   for (; i < 3; ++i)
3450b57cec5SDimitry Andric     Result.push_back(DummyPair);
3460b57cec5SDimitry Andric   return Result;
3470b57cec5SDimitry Andric }
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric static std::vector<std::pair<int, unsigned>>
Swizzle(std::vector<std::pair<int,unsigned>> Src,R600InstrInfo::BankSwizzle Swz)3500b57cec5SDimitry Andric Swizzle(std::vector<std::pair<int, unsigned>> Src,
3510b57cec5SDimitry Andric         R600InstrInfo::BankSwizzle Swz) {
3520b57cec5SDimitry Andric   if (Src[0] == Src[1])
3530b57cec5SDimitry Andric     Src[1].first = -1;
3540b57cec5SDimitry Andric   switch (Swz) {
3550b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_012_SCL_210:
3560b57cec5SDimitry Andric     break;
3570b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_021_SCL_122:
3580b57cec5SDimitry Andric     std::swap(Src[1], Src[2]);
3590b57cec5SDimitry Andric     break;
3600b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_102_SCL_221:
3610b57cec5SDimitry Andric     std::swap(Src[0], Src[1]);
3620b57cec5SDimitry Andric     break;
3630b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_120_SCL_212:
3640b57cec5SDimitry Andric     std::swap(Src[0], Src[1]);
3650b57cec5SDimitry Andric     std::swap(Src[0], Src[2]);
3660b57cec5SDimitry Andric     break;
3670b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_201:
3680b57cec5SDimitry Andric     std::swap(Src[0], Src[2]);
3690b57cec5SDimitry Andric     std::swap(Src[0], Src[1]);
3700b57cec5SDimitry Andric     break;
3710b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_210:
3720b57cec5SDimitry Andric     std::swap(Src[0], Src[2]);
3730b57cec5SDimitry Andric     break;
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric   return Src;
3760b57cec5SDimitry Andric }
3770b57cec5SDimitry Andric 
getTransSwizzle(R600InstrInfo::BankSwizzle Swz,unsigned Op)3780b57cec5SDimitry Andric static unsigned getTransSwizzle(R600InstrInfo::BankSwizzle Swz, unsigned Op) {
3790b57cec5SDimitry Andric   assert(Op < 3 && "Out of range swizzle index");
3800b57cec5SDimitry Andric   switch (Swz) {
3810b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_012_SCL_210: {
3820b57cec5SDimitry Andric     unsigned Cycles[3] = { 2, 1, 0};
3830b57cec5SDimitry Andric     return Cycles[Op];
3840b57cec5SDimitry Andric   }
3850b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_021_SCL_122: {
3860b57cec5SDimitry Andric     unsigned Cycles[3] = { 1, 2, 2};
3870b57cec5SDimitry Andric     return Cycles[Op];
3880b57cec5SDimitry Andric   }
3890b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_120_SCL_212: {
3900b57cec5SDimitry Andric     unsigned Cycles[3] = { 2, 1, 2};
3910b57cec5SDimitry Andric     return Cycles[Op];
3920b57cec5SDimitry Andric   }
3930b57cec5SDimitry Andric   case R600InstrInfo::ALU_VEC_102_SCL_221: {
3940b57cec5SDimitry Andric     unsigned Cycles[3] = { 2, 2, 1};
3950b57cec5SDimitry Andric     return Cycles[Op];
3960b57cec5SDimitry Andric   }
3970b57cec5SDimitry Andric   default:
3980b57cec5SDimitry Andric     llvm_unreachable("Wrong Swizzle for Trans Slot");
3990b57cec5SDimitry Andric   }
4000b57cec5SDimitry Andric }
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric /// returns how many MIs (whose inputs are represented by IGSrcs) can be packed
4030b57cec5SDimitry Andric /// in the same Instruction Group while meeting read port limitations given a
4040b57cec5SDimitry Andric /// Swz swizzle sequence.
isLegalUpTo(const std::vector<std::vector<std::pair<int,unsigned>>> & IGSrcs,const std::vector<R600InstrInfo::BankSwizzle> & Swz,const std::vector<std::pair<int,unsigned>> & TransSrcs,R600InstrInfo::BankSwizzle TransSwz) const4050b57cec5SDimitry Andric unsigned  R600InstrInfo::isLegalUpTo(
4060b57cec5SDimitry Andric     const std::vector<std::vector<std::pair<int, unsigned>>> &IGSrcs,
4070b57cec5SDimitry Andric     const std::vector<R600InstrInfo::BankSwizzle> &Swz,
4080b57cec5SDimitry Andric     const std::vector<std::pair<int, unsigned>> &TransSrcs,
4090b57cec5SDimitry Andric     R600InstrInfo::BankSwizzle TransSwz) const {
4100b57cec5SDimitry Andric   int Vector[4][3];
4110b57cec5SDimitry Andric   memset(Vector, -1, sizeof(Vector));
4120b57cec5SDimitry Andric   for (unsigned i = 0, e = IGSrcs.size(); i < e; i++) {
4130b57cec5SDimitry Andric     const std::vector<std::pair<int, unsigned>> &Srcs =
4140b57cec5SDimitry Andric         Swizzle(IGSrcs[i], Swz[i]);
4150b57cec5SDimitry Andric     for (unsigned j = 0; j < 3; j++) {
4160b57cec5SDimitry Andric       const std::pair<int, unsigned> &Src = Srcs[j];
4170b57cec5SDimitry Andric       if (Src.first < 0 || Src.first == 255)
4180b57cec5SDimitry Andric         continue;
4190b57cec5SDimitry Andric       if (Src.first == GET_REG_INDEX(RI.getEncodingValue(R600::OQAP))) {
4200b57cec5SDimitry Andric         if (Swz[i] != R600InstrInfo::ALU_VEC_012_SCL_210 &&
4210b57cec5SDimitry Andric             Swz[i] != R600InstrInfo::ALU_VEC_021_SCL_122) {
4220b57cec5SDimitry Andric             // The value from output queue A (denoted by register OQAP) can
4230b57cec5SDimitry Andric             // only be fetched during the first cycle.
4240b57cec5SDimitry Andric             return false;
4250b57cec5SDimitry Andric         }
4260b57cec5SDimitry Andric         // OQAP does not count towards the normal read port restrictions
4270b57cec5SDimitry Andric         continue;
4280b57cec5SDimitry Andric       }
4290b57cec5SDimitry Andric       if (Vector[Src.second][j] < 0)
4300b57cec5SDimitry Andric         Vector[Src.second][j] = Src.first;
4310b57cec5SDimitry Andric       if (Vector[Src.second][j] != Src.first)
4320b57cec5SDimitry Andric         return i;
4330b57cec5SDimitry Andric     }
4340b57cec5SDimitry Andric   }
4350b57cec5SDimitry Andric   // Now check Trans Alu
4360b57cec5SDimitry Andric   for (unsigned i = 0, e = TransSrcs.size(); i < e; ++i) {
4370b57cec5SDimitry Andric     const std::pair<int, unsigned> &Src = TransSrcs[i];
4380b57cec5SDimitry Andric     unsigned Cycle = getTransSwizzle(TransSwz, i);
4390b57cec5SDimitry Andric     if (Src.first < 0)
4400b57cec5SDimitry Andric       continue;
4410b57cec5SDimitry Andric     if (Src.first == 255)
4420b57cec5SDimitry Andric       continue;
4430b57cec5SDimitry Andric     if (Vector[Src.second][Cycle] < 0)
4440b57cec5SDimitry Andric       Vector[Src.second][Cycle] = Src.first;
4450b57cec5SDimitry Andric     if (Vector[Src.second][Cycle] != Src.first)
4460b57cec5SDimitry Andric       return IGSrcs.size() - 1;
4470b57cec5SDimitry Andric   }
4480b57cec5SDimitry Andric   return IGSrcs.size();
4490b57cec5SDimitry Andric }
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric /// Given a swizzle sequence SwzCandidate and an index Idx, returns the next
4520b57cec5SDimitry Andric /// (in lexicographic term) swizzle sequence assuming that all swizzles after
4530b57cec5SDimitry Andric /// Idx can be skipped
4540b57cec5SDimitry Andric static bool
NextPossibleSolution(std::vector<R600InstrInfo::BankSwizzle> & SwzCandidate,unsigned Idx)4550b57cec5SDimitry Andric NextPossibleSolution(
4560b57cec5SDimitry Andric     std::vector<R600InstrInfo::BankSwizzle> &SwzCandidate,
4570b57cec5SDimitry Andric     unsigned Idx) {
4580b57cec5SDimitry Andric   assert(Idx < SwzCandidate.size());
4590b57cec5SDimitry Andric   int ResetIdx = Idx;
4600b57cec5SDimitry Andric   while (ResetIdx > -1 && SwzCandidate[ResetIdx] == R600InstrInfo::ALU_VEC_210)
4610b57cec5SDimitry Andric     ResetIdx --;
4620b57cec5SDimitry Andric   for (unsigned i = ResetIdx + 1, e = SwzCandidate.size(); i < e; i++) {
4630b57cec5SDimitry Andric     SwzCandidate[i] = R600InstrInfo::ALU_VEC_012_SCL_210;
4640b57cec5SDimitry Andric   }
4650b57cec5SDimitry Andric   if (ResetIdx == -1)
4660b57cec5SDimitry Andric     return false;
4670b57cec5SDimitry Andric   int NextSwizzle = SwzCandidate[ResetIdx] + 1;
4680b57cec5SDimitry Andric   SwzCandidate[ResetIdx] = (R600InstrInfo::BankSwizzle)NextSwizzle;
4690b57cec5SDimitry Andric   return true;
4700b57cec5SDimitry Andric }
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric /// Enumerate all possible Swizzle sequence to find one that can meet all
4730b57cec5SDimitry Andric /// read port requirements.
FindSwizzleForVectorSlot(const std::vector<std::vector<std::pair<int,unsigned>>> & IGSrcs,std::vector<R600InstrInfo::BankSwizzle> & SwzCandidate,const std::vector<std::pair<int,unsigned>> & TransSrcs,R600InstrInfo::BankSwizzle TransSwz) const4740b57cec5SDimitry Andric bool R600InstrInfo::FindSwizzleForVectorSlot(
4750b57cec5SDimitry Andric     const std::vector<std::vector<std::pair<int, unsigned>>> &IGSrcs,
4760b57cec5SDimitry Andric     std::vector<R600InstrInfo::BankSwizzle> &SwzCandidate,
4770b57cec5SDimitry Andric     const std::vector<std::pair<int, unsigned>> &TransSrcs,
4780b57cec5SDimitry Andric     R600InstrInfo::BankSwizzle TransSwz) const {
4790b57cec5SDimitry Andric   unsigned ValidUpTo = 0;
4800b57cec5SDimitry Andric   do {
4810b57cec5SDimitry Andric     ValidUpTo = isLegalUpTo(IGSrcs, SwzCandidate, TransSrcs, TransSwz);
4820b57cec5SDimitry Andric     if (ValidUpTo == IGSrcs.size())
4830b57cec5SDimitry Andric       return true;
4840b57cec5SDimitry Andric   } while (NextPossibleSolution(SwzCandidate, ValidUpTo));
4850b57cec5SDimitry Andric   return false;
4860b57cec5SDimitry Andric }
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric /// Instructions in Trans slot can't read gpr at cycle 0 if they also read
4890b57cec5SDimitry Andric /// a const, and can't read a gpr at cycle 1 if they read 2 const.
4900b57cec5SDimitry Andric static bool
isConstCompatible(R600InstrInfo::BankSwizzle TransSwz,const std::vector<std::pair<int,unsigned>> & TransOps,unsigned ConstCount)4910b57cec5SDimitry Andric isConstCompatible(R600InstrInfo::BankSwizzle TransSwz,
4920b57cec5SDimitry Andric                   const std::vector<std::pair<int, unsigned>> &TransOps,
4930b57cec5SDimitry Andric                   unsigned ConstCount) {
4940b57cec5SDimitry Andric   // TransALU can't read 3 constants
4950b57cec5SDimitry Andric   if (ConstCount > 2)
4960b57cec5SDimitry Andric     return false;
4970b57cec5SDimitry Andric   for (unsigned i = 0, e = TransOps.size(); i < e; ++i) {
4980b57cec5SDimitry Andric     const std::pair<int, unsigned> &Src = TransOps[i];
4990b57cec5SDimitry Andric     unsigned Cycle = getTransSwizzle(TransSwz, i);
5000b57cec5SDimitry Andric     if (Src.first < 0)
5010b57cec5SDimitry Andric       continue;
5020b57cec5SDimitry Andric     if (ConstCount > 0 && Cycle == 0)
5030b57cec5SDimitry Andric       return false;
5040b57cec5SDimitry Andric     if (ConstCount > 1 && Cycle == 1)
5050b57cec5SDimitry Andric       return false;
5060b57cec5SDimitry Andric   }
5070b57cec5SDimitry Andric   return true;
5080b57cec5SDimitry Andric }
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric bool
fitsReadPortLimitations(const std::vector<MachineInstr * > & IG,const DenseMap<unsigned,unsigned> & PV,std::vector<BankSwizzle> & ValidSwizzle,bool isLastAluTrans) const5110b57cec5SDimitry Andric R600InstrInfo::fitsReadPortLimitations(const std::vector<MachineInstr *> &IG,
5120b57cec5SDimitry Andric                                        const DenseMap<unsigned, unsigned> &PV,
5130b57cec5SDimitry Andric                                        std::vector<BankSwizzle> &ValidSwizzle,
5140b57cec5SDimitry Andric                                        bool isLastAluTrans)
5150b57cec5SDimitry Andric     const {
5160b57cec5SDimitry Andric   //Todo : support shared src0 - src1 operand
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric   std::vector<std::vector<std::pair<int, unsigned>>> IGSrcs;
5190b57cec5SDimitry Andric   ValidSwizzle.clear();
5205ffd83dbSDimitry Andric   unsigned ConstCount;
5210b57cec5SDimitry Andric   BankSwizzle TransBS = ALU_VEC_012_SCL_210;
5220eae32dcSDimitry Andric   for (MachineInstr *MI : IG) {
5230eae32dcSDimitry Andric     IGSrcs.push_back(ExtractSrcs(*MI, PV, ConstCount));
5240eae32dcSDimitry Andric     unsigned Op = getOperandIdx(MI->getOpcode(), R600::OpName::bank_swizzle);
5250eae32dcSDimitry Andric     ValidSwizzle.push_back(
5260eae32dcSDimitry Andric         (R600InstrInfo::BankSwizzle)MI->getOperand(Op).getImm());
5270b57cec5SDimitry Andric   }
5280b57cec5SDimitry Andric   std::vector<std::pair<int, unsigned>> TransOps;
5290b57cec5SDimitry Andric   if (!isLastAluTrans)
5300b57cec5SDimitry Andric     return FindSwizzleForVectorSlot(IGSrcs, ValidSwizzle, TransOps, TransBS);
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric   TransOps = std::move(IGSrcs.back());
5330b57cec5SDimitry Andric   IGSrcs.pop_back();
5340b57cec5SDimitry Andric   ValidSwizzle.pop_back();
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric   static const R600InstrInfo::BankSwizzle TransSwz[] = {
5370b57cec5SDimitry Andric     ALU_VEC_012_SCL_210,
5380b57cec5SDimitry Andric     ALU_VEC_021_SCL_122,
5390b57cec5SDimitry Andric     ALU_VEC_120_SCL_212,
5400b57cec5SDimitry Andric     ALU_VEC_102_SCL_221
5410b57cec5SDimitry Andric   };
5420eae32dcSDimitry Andric   for (R600InstrInfo::BankSwizzle TransBS : TransSwz) {
5430b57cec5SDimitry Andric     if (!isConstCompatible(TransBS, TransOps, ConstCount))
5440b57cec5SDimitry Andric       continue;
5450b57cec5SDimitry Andric     bool Result = FindSwizzleForVectorSlot(IGSrcs, ValidSwizzle, TransOps,
5460b57cec5SDimitry Andric         TransBS);
5470b57cec5SDimitry Andric     if (Result) {
5480b57cec5SDimitry Andric       ValidSwizzle.push_back(TransBS);
5490b57cec5SDimitry Andric       return true;
5500b57cec5SDimitry Andric     }
5510b57cec5SDimitry Andric   }
5520b57cec5SDimitry Andric 
5530b57cec5SDimitry Andric   return false;
5540b57cec5SDimitry Andric }
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric bool
fitsConstReadLimitations(const std::vector<unsigned> & Consts) const5570b57cec5SDimitry Andric R600InstrInfo::fitsConstReadLimitations(const std::vector<unsigned> &Consts)
5580b57cec5SDimitry Andric     const {
5590b57cec5SDimitry Andric   assert (Consts.size() <= 12 && "Too many operands in instructions group");
5600b57cec5SDimitry Andric   unsigned Pair1 = 0, Pair2 = 0;
5610eae32dcSDimitry Andric   for (unsigned Const : Consts) {
5620eae32dcSDimitry Andric     unsigned ReadConstHalf = Const & 2;
5630eae32dcSDimitry Andric     unsigned ReadConstIndex = Const & (~3);
5640b57cec5SDimitry Andric     unsigned ReadHalfConst = ReadConstIndex | ReadConstHalf;
5650b57cec5SDimitry Andric     if (!Pair1) {
5660b57cec5SDimitry Andric       Pair1 = ReadHalfConst;
5670b57cec5SDimitry Andric       continue;
5680b57cec5SDimitry Andric     }
5690b57cec5SDimitry Andric     if (Pair1 == ReadHalfConst)
5700b57cec5SDimitry Andric       continue;
5710b57cec5SDimitry Andric     if (!Pair2) {
5720b57cec5SDimitry Andric       Pair2 = ReadHalfConst;
5730b57cec5SDimitry Andric       continue;
5740b57cec5SDimitry Andric     }
5750b57cec5SDimitry Andric     if (Pair2 != ReadHalfConst)
5760b57cec5SDimitry Andric       return false;
5770b57cec5SDimitry Andric   }
5780b57cec5SDimitry Andric   return true;
5790b57cec5SDimitry Andric }
5800b57cec5SDimitry Andric 
5810b57cec5SDimitry Andric bool
fitsConstReadLimitations(const std::vector<MachineInstr * > & MIs) const5820b57cec5SDimitry Andric R600InstrInfo::fitsConstReadLimitations(const std::vector<MachineInstr *> &MIs)
5830b57cec5SDimitry Andric     const {
5840b57cec5SDimitry Andric   std::vector<unsigned> Consts;
5850b57cec5SDimitry Andric   SmallSet<int64_t, 4> Literals;
5860eae32dcSDimitry Andric   for (MachineInstr *MI : MIs) {
5870eae32dcSDimitry Andric     if (!isALUInstr(MI->getOpcode()))
5880b57cec5SDimitry Andric       continue;
5890b57cec5SDimitry Andric 
5900eae32dcSDimitry Andric     for (const auto &Src : getSrcs(*MI)) {
5910b57cec5SDimitry Andric       if (Src.first->getReg() == R600::ALU_LITERAL_X)
5920b57cec5SDimitry Andric         Literals.insert(Src.second);
5930b57cec5SDimitry Andric       if (Literals.size() > 4)
5940b57cec5SDimitry Andric         return false;
5950b57cec5SDimitry Andric       if (Src.first->getReg() == R600::ALU_CONST)
5960b57cec5SDimitry Andric         Consts.push_back(Src.second);
5970b57cec5SDimitry Andric       if (R600::R600_KC0RegClass.contains(Src.first->getReg()) ||
5980b57cec5SDimitry Andric           R600::R600_KC1RegClass.contains(Src.first->getReg())) {
5990b57cec5SDimitry Andric         unsigned Index = RI.getEncodingValue(Src.first->getReg()) & 0xff;
6000b57cec5SDimitry Andric         unsigned Chan = RI.getHWRegChan(Src.first->getReg());
6010b57cec5SDimitry Andric         Consts.push_back((Index << 2) | Chan);
6020b57cec5SDimitry Andric       }
6030b57cec5SDimitry Andric     }
6040b57cec5SDimitry Andric   }
6050b57cec5SDimitry Andric   return fitsConstReadLimitations(Consts);
6060b57cec5SDimitry Andric }
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric DFAPacketizer *
CreateTargetScheduleState(const TargetSubtargetInfo & STI) const6090b57cec5SDimitry Andric R600InstrInfo::CreateTargetScheduleState(const TargetSubtargetInfo &STI) const {
6100b57cec5SDimitry Andric   const InstrItineraryData *II = STI.getInstrItineraryData();
6110b57cec5SDimitry Andric   return static_cast<const R600Subtarget &>(STI).createDFAPacketizer(II);
6120b57cec5SDimitry Andric }
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric static bool
isPredicateSetter(unsigned Opcode)6150b57cec5SDimitry Andric isPredicateSetter(unsigned Opcode) {
6160b57cec5SDimitry Andric   switch (Opcode) {
6170b57cec5SDimitry Andric   case R600::PRED_X:
6180b57cec5SDimitry Andric     return true;
6190b57cec5SDimitry Andric   default:
6200b57cec5SDimitry Andric     return false;
6210b57cec5SDimitry Andric   }
6220b57cec5SDimitry Andric }
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric static MachineInstr *
findFirstPredicateSetterFrom(MachineBasicBlock & MBB,MachineBasicBlock::iterator I)6250b57cec5SDimitry Andric findFirstPredicateSetterFrom(MachineBasicBlock &MBB,
6260b57cec5SDimitry Andric                              MachineBasicBlock::iterator I) {
6270b57cec5SDimitry Andric   while (I != MBB.begin()) {
6280b57cec5SDimitry Andric     --I;
6290b57cec5SDimitry Andric     MachineInstr &MI = *I;
6300b57cec5SDimitry Andric     if (isPredicateSetter(MI.getOpcode()))
6310b57cec5SDimitry Andric       return &MI;
6320b57cec5SDimitry Andric   }
6330b57cec5SDimitry Andric 
6340b57cec5SDimitry Andric   return nullptr;
6350b57cec5SDimitry Andric }
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric static
isJump(unsigned Opcode)6380b57cec5SDimitry Andric bool isJump(unsigned Opcode) {
6390b57cec5SDimitry Andric   return Opcode == R600::JUMP || Opcode == R600::JUMP_COND;
6400b57cec5SDimitry Andric }
6410b57cec5SDimitry Andric 
isBranch(unsigned Opcode)6420b57cec5SDimitry Andric static bool isBranch(unsigned Opcode) {
6430b57cec5SDimitry Andric   return Opcode == R600::BRANCH || Opcode == R600::BRANCH_COND_i32 ||
6440b57cec5SDimitry Andric       Opcode == R600::BRANCH_COND_f32;
6450b57cec5SDimitry Andric }
6460b57cec5SDimitry Andric 
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool AllowModify) const6470b57cec5SDimitry Andric bool R600InstrInfo::analyzeBranch(MachineBasicBlock &MBB,
6480b57cec5SDimitry Andric                                   MachineBasicBlock *&TBB,
6490b57cec5SDimitry Andric                                   MachineBasicBlock *&FBB,
6500b57cec5SDimitry Andric                                   SmallVectorImpl<MachineOperand> &Cond,
6510b57cec5SDimitry Andric                                   bool AllowModify) const {
6525ffd83dbSDimitry Andric   // Most of the following comes from the ARM implementation of analyzeBranch
6530b57cec5SDimitry Andric 
6540b57cec5SDimitry Andric   // If the block has no terminators, it just falls into the block after it.
6550b57cec5SDimitry Andric   MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
6560b57cec5SDimitry Andric   if (I == MBB.end())
6570b57cec5SDimitry Andric     return false;
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric   // R600::BRANCH* instructions are only available after isel and are not
6600b57cec5SDimitry Andric   // handled
6610b57cec5SDimitry Andric   if (isBranch(I->getOpcode()))
6620b57cec5SDimitry Andric     return true;
6630b57cec5SDimitry Andric   if (!isJump(I->getOpcode())) {
6640b57cec5SDimitry Andric     return false;
6650b57cec5SDimitry Andric   }
6660b57cec5SDimitry Andric 
6670b57cec5SDimitry Andric   // Remove successive JUMP
6680b57cec5SDimitry Andric   while (I != MBB.begin() && std::prev(I)->getOpcode() == R600::JUMP) {
6690b57cec5SDimitry Andric       MachineBasicBlock::iterator PriorI = std::prev(I);
6700b57cec5SDimitry Andric       if (AllowModify)
6710b57cec5SDimitry Andric         I->removeFromParent();
6720b57cec5SDimitry Andric       I = PriorI;
6730b57cec5SDimitry Andric   }
6740b57cec5SDimitry Andric   MachineInstr &LastInst = *I;
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric   // If there is only one terminator instruction, process it.
6770b57cec5SDimitry Andric   unsigned LastOpc = LastInst.getOpcode();
6780b57cec5SDimitry Andric   if (I == MBB.begin() || !isJump((--I)->getOpcode())) {
6790b57cec5SDimitry Andric     if (LastOpc == R600::JUMP) {
6800b57cec5SDimitry Andric       TBB = LastInst.getOperand(0).getMBB();
6810b57cec5SDimitry Andric       return false;
6820b57cec5SDimitry Andric     } else if (LastOpc == R600::JUMP_COND) {
6830b57cec5SDimitry Andric       auto predSet = I;
6840b57cec5SDimitry Andric       while (!isPredicateSetter(predSet->getOpcode())) {
6850b57cec5SDimitry Andric         predSet = --I;
6860b57cec5SDimitry Andric       }
6870b57cec5SDimitry Andric       TBB = LastInst.getOperand(0).getMBB();
6880b57cec5SDimitry Andric       Cond.push_back(predSet->getOperand(1));
6890b57cec5SDimitry Andric       Cond.push_back(predSet->getOperand(2));
6900b57cec5SDimitry Andric       Cond.push_back(MachineOperand::CreateReg(R600::PRED_SEL_ONE, false));
6910b57cec5SDimitry Andric       return false;
6920b57cec5SDimitry Andric     }
6930b57cec5SDimitry Andric     return true;  // Can't handle indirect branch.
6940b57cec5SDimitry Andric   }
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric   // Get the instruction before it if it is a terminator.
6970b57cec5SDimitry Andric   MachineInstr &SecondLastInst = *I;
6980b57cec5SDimitry Andric   unsigned SecondLastOpc = SecondLastInst.getOpcode();
6990b57cec5SDimitry Andric 
7000b57cec5SDimitry Andric   // If the block ends with a B and a Bcc, handle it.
7010b57cec5SDimitry Andric   if (SecondLastOpc == R600::JUMP_COND && LastOpc == R600::JUMP) {
7020b57cec5SDimitry Andric     auto predSet = --I;
7030b57cec5SDimitry Andric     while (!isPredicateSetter(predSet->getOpcode())) {
7040b57cec5SDimitry Andric       predSet = --I;
7050b57cec5SDimitry Andric     }
7060b57cec5SDimitry Andric     TBB = SecondLastInst.getOperand(0).getMBB();
7070b57cec5SDimitry Andric     FBB = LastInst.getOperand(0).getMBB();
7080b57cec5SDimitry Andric     Cond.push_back(predSet->getOperand(1));
7090b57cec5SDimitry Andric     Cond.push_back(predSet->getOperand(2));
7100b57cec5SDimitry Andric     Cond.push_back(MachineOperand::CreateReg(R600::PRED_SEL_ONE, false));
7110b57cec5SDimitry Andric     return false;
7120b57cec5SDimitry Andric   }
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric   // Otherwise, can't handle this.
7150b57cec5SDimitry Andric   return true;
7160b57cec5SDimitry Andric }
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric static
FindLastAluClause(MachineBasicBlock & MBB)7190b57cec5SDimitry Andric MachineBasicBlock::iterator FindLastAluClause(MachineBasicBlock &MBB) {
7200b57cec5SDimitry Andric   for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend();
7210b57cec5SDimitry Andric       It != E; ++It) {
7220b57cec5SDimitry Andric     if (It->getOpcode() == R600::CF_ALU ||
7230b57cec5SDimitry Andric         It->getOpcode() == R600::CF_ALU_PUSH_BEFORE)
7240b57cec5SDimitry Andric       return It.getReverse();
7250b57cec5SDimitry Andric   }
7260b57cec5SDimitry Andric   return MBB.end();
7270b57cec5SDimitry Andric }
7280b57cec5SDimitry Andric 
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int * BytesAdded) const7290b57cec5SDimitry Andric unsigned R600InstrInfo::insertBranch(MachineBasicBlock &MBB,
7300b57cec5SDimitry Andric                                      MachineBasicBlock *TBB,
7310b57cec5SDimitry Andric                                      MachineBasicBlock *FBB,
7320b57cec5SDimitry Andric                                      ArrayRef<MachineOperand> Cond,
7330b57cec5SDimitry Andric                                      const DebugLoc &DL,
7340b57cec5SDimitry Andric                                      int *BytesAdded) const {
7350b57cec5SDimitry Andric   assert(TBB && "insertBranch must not be told to insert a fallthrough");
7360b57cec5SDimitry Andric   assert(!BytesAdded && "code size not handled");
7370b57cec5SDimitry Andric 
7380b57cec5SDimitry Andric   if (!FBB) {
7390b57cec5SDimitry Andric     if (Cond.empty()) {
7400b57cec5SDimitry Andric       BuildMI(&MBB, DL, get(R600::JUMP)).addMBB(TBB);
7410b57cec5SDimitry Andric       return 1;
7420b57cec5SDimitry Andric     } else {
7430b57cec5SDimitry Andric       MachineInstr *PredSet = findFirstPredicateSetterFrom(MBB, MBB.end());
7440b57cec5SDimitry Andric       assert(PredSet && "No previous predicate !");
7450b57cec5SDimitry Andric       addFlag(*PredSet, 0, MO_FLAG_PUSH);
7460b57cec5SDimitry Andric       PredSet->getOperand(2).setImm(Cond[1].getImm());
7470b57cec5SDimitry Andric 
7480b57cec5SDimitry Andric       BuildMI(&MBB, DL, get(R600::JUMP_COND))
7490b57cec5SDimitry Andric              .addMBB(TBB)
7500b57cec5SDimitry Andric              .addReg(R600::PREDICATE_BIT, RegState::Kill);
7510b57cec5SDimitry Andric       MachineBasicBlock::iterator CfAlu = FindLastAluClause(MBB);
7520b57cec5SDimitry Andric       if (CfAlu == MBB.end())
7530b57cec5SDimitry Andric         return 1;
7540b57cec5SDimitry Andric       assert (CfAlu->getOpcode() == R600::CF_ALU);
7550b57cec5SDimitry Andric       CfAlu->setDesc(get(R600::CF_ALU_PUSH_BEFORE));
7560b57cec5SDimitry Andric       return 1;
7570b57cec5SDimitry Andric     }
7580b57cec5SDimitry Andric   } else {
7590b57cec5SDimitry Andric     MachineInstr *PredSet = findFirstPredicateSetterFrom(MBB, MBB.end());
7600b57cec5SDimitry Andric     assert(PredSet && "No previous predicate !");
7610b57cec5SDimitry Andric     addFlag(*PredSet, 0, MO_FLAG_PUSH);
7620b57cec5SDimitry Andric     PredSet->getOperand(2).setImm(Cond[1].getImm());
7630b57cec5SDimitry Andric     BuildMI(&MBB, DL, get(R600::JUMP_COND))
7640b57cec5SDimitry Andric             .addMBB(TBB)
7650b57cec5SDimitry Andric             .addReg(R600::PREDICATE_BIT, RegState::Kill);
7660b57cec5SDimitry Andric     BuildMI(&MBB, DL, get(R600::JUMP)).addMBB(FBB);
7670b57cec5SDimitry Andric     MachineBasicBlock::iterator CfAlu = FindLastAluClause(MBB);
7680b57cec5SDimitry Andric     if (CfAlu == MBB.end())
7690b57cec5SDimitry Andric       return 2;
7700b57cec5SDimitry Andric     assert (CfAlu->getOpcode() == R600::CF_ALU);
7710b57cec5SDimitry Andric     CfAlu->setDesc(get(R600::CF_ALU_PUSH_BEFORE));
7720b57cec5SDimitry Andric     return 2;
7730b57cec5SDimitry Andric   }
7740b57cec5SDimitry Andric }
7750b57cec5SDimitry Andric 
removeBranch(MachineBasicBlock & MBB,int * BytesRemoved) const7760b57cec5SDimitry Andric unsigned R600InstrInfo::removeBranch(MachineBasicBlock &MBB,
7770b57cec5SDimitry Andric                                      int *BytesRemoved) const {
7780b57cec5SDimitry Andric   assert(!BytesRemoved && "code size not handled");
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric   // Note : we leave PRED* instructions there.
7810b57cec5SDimitry Andric   // They may be needed when predicating instructions.
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric   MachineBasicBlock::iterator I = MBB.end();
7840b57cec5SDimitry Andric 
7850b57cec5SDimitry Andric   if (I == MBB.begin()) {
7860b57cec5SDimitry Andric     return 0;
7870b57cec5SDimitry Andric   }
7880b57cec5SDimitry Andric   --I;
7890b57cec5SDimitry Andric   switch (I->getOpcode()) {
7900b57cec5SDimitry Andric   default:
7910b57cec5SDimitry Andric     return 0;
7920b57cec5SDimitry Andric   case R600::JUMP_COND: {
7930b57cec5SDimitry Andric     MachineInstr *predSet = findFirstPredicateSetterFrom(MBB, I);
7940b57cec5SDimitry Andric     clearFlag(*predSet, 0, MO_FLAG_PUSH);
7950b57cec5SDimitry Andric     I->eraseFromParent();
7960b57cec5SDimitry Andric     MachineBasicBlock::iterator CfAlu = FindLastAluClause(MBB);
7970b57cec5SDimitry Andric     if (CfAlu == MBB.end())
7980b57cec5SDimitry Andric       break;
7990b57cec5SDimitry Andric     assert (CfAlu->getOpcode() == R600::CF_ALU_PUSH_BEFORE);
8000b57cec5SDimitry Andric     CfAlu->setDesc(get(R600::CF_ALU));
8010b57cec5SDimitry Andric     break;
8020b57cec5SDimitry Andric   }
8030b57cec5SDimitry Andric   case R600::JUMP:
8040b57cec5SDimitry Andric     I->eraseFromParent();
8050b57cec5SDimitry Andric     break;
8060b57cec5SDimitry Andric   }
8070b57cec5SDimitry Andric   I = MBB.end();
8080b57cec5SDimitry Andric 
8090b57cec5SDimitry Andric   if (I == MBB.begin()) {
8100b57cec5SDimitry Andric     return 1;
8110b57cec5SDimitry Andric   }
8120b57cec5SDimitry Andric   --I;
8130b57cec5SDimitry Andric   switch (I->getOpcode()) {
8140b57cec5SDimitry Andric     // FIXME: only one case??
8150b57cec5SDimitry Andric   default:
8160b57cec5SDimitry Andric     return 1;
8170b57cec5SDimitry Andric   case R600::JUMP_COND: {
8180b57cec5SDimitry Andric     MachineInstr *predSet = findFirstPredicateSetterFrom(MBB, I);
8190b57cec5SDimitry Andric     clearFlag(*predSet, 0, MO_FLAG_PUSH);
8200b57cec5SDimitry Andric     I->eraseFromParent();
8210b57cec5SDimitry Andric     MachineBasicBlock::iterator CfAlu = FindLastAluClause(MBB);
8220b57cec5SDimitry Andric     if (CfAlu == MBB.end())
8230b57cec5SDimitry Andric       break;
8240b57cec5SDimitry Andric     assert (CfAlu->getOpcode() == R600::CF_ALU_PUSH_BEFORE);
8250b57cec5SDimitry Andric     CfAlu->setDesc(get(R600::CF_ALU));
8260b57cec5SDimitry Andric     break;
8270b57cec5SDimitry Andric   }
8280b57cec5SDimitry Andric   case R600::JUMP:
8290b57cec5SDimitry Andric     I->eraseFromParent();
8300b57cec5SDimitry Andric     break;
8310b57cec5SDimitry Andric   }
8320b57cec5SDimitry Andric   return 2;
8330b57cec5SDimitry Andric }
8340b57cec5SDimitry Andric 
isPredicated(const MachineInstr & MI) const8350b57cec5SDimitry Andric bool R600InstrInfo::isPredicated(const MachineInstr &MI) const {
8360b57cec5SDimitry Andric   int idx = MI.findFirstPredOperandIdx();
8370b57cec5SDimitry Andric   if (idx < 0)
8380b57cec5SDimitry Andric     return false;
8390b57cec5SDimitry Andric 
8408bcb0991SDimitry Andric   Register Reg = MI.getOperand(idx).getReg();
8410b57cec5SDimitry Andric   switch (Reg) {
8420b57cec5SDimitry Andric   default: return false;
8430b57cec5SDimitry Andric   case R600::PRED_SEL_ONE:
8440b57cec5SDimitry Andric   case R600::PRED_SEL_ZERO:
8450b57cec5SDimitry Andric   case R600::PREDICATE_BIT:
8460b57cec5SDimitry Andric     return true;
8470b57cec5SDimitry Andric   }
8480b57cec5SDimitry Andric }
8490b57cec5SDimitry Andric 
isPredicable(const MachineInstr & MI) const8500b57cec5SDimitry Andric bool R600InstrInfo::isPredicable(const MachineInstr &MI) const {
8510b57cec5SDimitry Andric   // XXX: KILL* instructions can be predicated, but they must be the last
8520b57cec5SDimitry Andric   // instruction in a clause, so this means any instructions after them cannot
8530b57cec5SDimitry Andric   // be predicated.  Until we have proper support for instruction clauses in the
8540b57cec5SDimitry Andric   // backend, we will mark KILL* instructions as unpredicable.
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric   if (MI.getOpcode() == R600::KILLGT) {
8570b57cec5SDimitry Andric     return false;
8580b57cec5SDimitry Andric   } else if (MI.getOpcode() == R600::CF_ALU) {
8590b57cec5SDimitry Andric     // If the clause start in the middle of MBB then the MBB has more
8600b57cec5SDimitry Andric     // than a single clause, unable to predicate several clauses.
8610b57cec5SDimitry Andric     if (MI.getParent()->begin() != MachineBasicBlock::const_iterator(MI))
8620b57cec5SDimitry Andric       return false;
8630b57cec5SDimitry Andric     // TODO: We don't support KC merging atm
8640b57cec5SDimitry Andric     return MI.getOperand(3).getImm() == 0 && MI.getOperand(4).getImm() == 0;
8650b57cec5SDimitry Andric   } else if (isVector(MI)) {
8660b57cec5SDimitry Andric     return false;
8670b57cec5SDimitry Andric   } else {
8680b57cec5SDimitry Andric     return TargetInstrInfo::isPredicable(MI);
8690b57cec5SDimitry Andric   }
8700b57cec5SDimitry Andric }
8710b57cec5SDimitry Andric 
8720b57cec5SDimitry Andric bool
isProfitableToIfCvt(MachineBasicBlock & MBB,unsigned NumCycles,unsigned ExtraPredCycles,BranchProbability Probability) const8730b57cec5SDimitry Andric R600InstrInfo::isProfitableToIfCvt(MachineBasicBlock &MBB,
8740b57cec5SDimitry Andric                                    unsigned NumCycles,
8750b57cec5SDimitry Andric                                    unsigned ExtraPredCycles,
8760b57cec5SDimitry Andric                                    BranchProbability Probability) const{
8770b57cec5SDimitry Andric   return true;
8780b57cec5SDimitry Andric }
8790b57cec5SDimitry Andric 
8800b57cec5SDimitry Andric bool
isProfitableToIfCvt(MachineBasicBlock & TMBB,unsigned NumTCycles,unsigned ExtraTCycles,MachineBasicBlock & FMBB,unsigned NumFCycles,unsigned ExtraFCycles,BranchProbability Probability) const8810b57cec5SDimitry Andric R600InstrInfo::isProfitableToIfCvt(MachineBasicBlock &TMBB,
8820b57cec5SDimitry Andric                                    unsigned NumTCycles,
8830b57cec5SDimitry Andric                                    unsigned ExtraTCycles,
8840b57cec5SDimitry Andric                                    MachineBasicBlock &FMBB,
8850b57cec5SDimitry Andric                                    unsigned NumFCycles,
8860b57cec5SDimitry Andric                                    unsigned ExtraFCycles,
8870b57cec5SDimitry Andric                                    BranchProbability Probability) const {
8880b57cec5SDimitry Andric   return true;
8890b57cec5SDimitry Andric }
8900b57cec5SDimitry Andric 
8910b57cec5SDimitry Andric bool
isProfitableToDupForIfCvt(MachineBasicBlock & MBB,unsigned NumCycles,BranchProbability Probability) const8920b57cec5SDimitry Andric R600InstrInfo::isProfitableToDupForIfCvt(MachineBasicBlock &MBB,
8930b57cec5SDimitry Andric                                          unsigned NumCycles,
8940b57cec5SDimitry Andric                                          BranchProbability Probability)
8950b57cec5SDimitry Andric                                          const {
8960b57cec5SDimitry Andric   return true;
8970b57cec5SDimitry Andric }
8980b57cec5SDimitry Andric 
8990b57cec5SDimitry Andric bool
isProfitableToUnpredicate(MachineBasicBlock & TMBB,MachineBasicBlock & FMBB) const9000b57cec5SDimitry Andric R600InstrInfo::isProfitableToUnpredicate(MachineBasicBlock &TMBB,
9010b57cec5SDimitry Andric                                          MachineBasicBlock &FMBB) const {
9020b57cec5SDimitry Andric   return false;
9030b57cec5SDimitry Andric }
9040b57cec5SDimitry Andric 
9050b57cec5SDimitry Andric bool
reverseBranchCondition(SmallVectorImpl<MachineOperand> & Cond) const9060b57cec5SDimitry Andric R600InstrInfo::reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
9070b57cec5SDimitry Andric   MachineOperand &MO = Cond[1];
9080b57cec5SDimitry Andric   switch (MO.getImm()) {
9090b57cec5SDimitry Andric   case R600::PRED_SETE_INT:
9100b57cec5SDimitry Andric     MO.setImm(R600::PRED_SETNE_INT);
9110b57cec5SDimitry Andric     break;
9120b57cec5SDimitry Andric   case R600::PRED_SETNE_INT:
9130b57cec5SDimitry Andric     MO.setImm(R600::PRED_SETE_INT);
9140b57cec5SDimitry Andric     break;
9150b57cec5SDimitry Andric   case R600::PRED_SETE:
9160b57cec5SDimitry Andric     MO.setImm(R600::PRED_SETNE);
9170b57cec5SDimitry Andric     break;
9180b57cec5SDimitry Andric   case R600::PRED_SETNE:
9190b57cec5SDimitry Andric     MO.setImm(R600::PRED_SETE);
9200b57cec5SDimitry Andric     break;
9210b57cec5SDimitry Andric   default:
9220b57cec5SDimitry Andric     return true;
9230b57cec5SDimitry Andric   }
9240b57cec5SDimitry Andric 
9250b57cec5SDimitry Andric   MachineOperand &MO2 = Cond[2];
9260b57cec5SDimitry Andric   switch (MO2.getReg()) {
9270b57cec5SDimitry Andric   case R600::PRED_SEL_ZERO:
9280b57cec5SDimitry Andric     MO2.setReg(R600::PRED_SEL_ONE);
9290b57cec5SDimitry Andric     break;
9300b57cec5SDimitry Andric   case R600::PRED_SEL_ONE:
9310b57cec5SDimitry Andric     MO2.setReg(R600::PRED_SEL_ZERO);
9320b57cec5SDimitry Andric     break;
9330b57cec5SDimitry Andric   default:
9340b57cec5SDimitry Andric     return true;
9350b57cec5SDimitry Andric   }
9360b57cec5SDimitry Andric   return false;
9370b57cec5SDimitry Andric }
9380b57cec5SDimitry Andric 
ClobbersPredicate(MachineInstr & MI,std::vector<MachineOperand> & Pred,bool SkipDead) const939e8d8bef9SDimitry Andric bool R600InstrInfo::ClobbersPredicate(MachineInstr &MI,
940e8d8bef9SDimitry Andric                                       std::vector<MachineOperand> &Pred,
941e8d8bef9SDimitry Andric                                       bool SkipDead) const {
9420b57cec5SDimitry Andric   return isPredicateSetter(MI.getOpcode());
9430b57cec5SDimitry Andric }
9440b57cec5SDimitry Andric 
PredicateInstruction(MachineInstr & MI,ArrayRef<MachineOperand> Pred) const9450b57cec5SDimitry Andric bool R600InstrInfo::PredicateInstruction(MachineInstr &MI,
9460b57cec5SDimitry Andric                                          ArrayRef<MachineOperand> Pred) const {
9470b57cec5SDimitry Andric   int PIdx = MI.findFirstPredOperandIdx();
9480b57cec5SDimitry Andric 
9490b57cec5SDimitry Andric   if (MI.getOpcode() == R600::CF_ALU) {
9500b57cec5SDimitry Andric     MI.getOperand(8).setImm(0);
9510b57cec5SDimitry Andric     return true;
9520b57cec5SDimitry Andric   }
9530b57cec5SDimitry Andric 
9540b57cec5SDimitry Andric   if (MI.getOpcode() == R600::DOT_4) {
9550b57cec5SDimitry Andric     MI.getOperand(getOperandIdx(MI, R600::OpName::pred_sel_X))
9560b57cec5SDimitry Andric         .setReg(Pred[2].getReg());
9570b57cec5SDimitry Andric     MI.getOperand(getOperandIdx(MI, R600::OpName::pred_sel_Y))
9580b57cec5SDimitry Andric         .setReg(Pred[2].getReg());
9590b57cec5SDimitry Andric     MI.getOperand(getOperandIdx(MI, R600::OpName::pred_sel_Z))
9600b57cec5SDimitry Andric         .setReg(Pred[2].getReg());
9610b57cec5SDimitry Andric     MI.getOperand(getOperandIdx(MI, R600::OpName::pred_sel_W))
9620b57cec5SDimitry Andric         .setReg(Pred[2].getReg());
9630b57cec5SDimitry Andric     MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI);
9640b57cec5SDimitry Andric     MIB.addReg(R600::PREDICATE_BIT, RegState::Implicit);
9650b57cec5SDimitry Andric     return true;
9660b57cec5SDimitry Andric   }
9670b57cec5SDimitry Andric 
9680b57cec5SDimitry Andric   if (PIdx != -1) {
9690b57cec5SDimitry Andric     MachineOperand &PMO = MI.getOperand(PIdx);
9700b57cec5SDimitry Andric     PMO.setReg(Pred[2].getReg());
9710b57cec5SDimitry Andric     MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI);
9720b57cec5SDimitry Andric     MIB.addReg(R600::PREDICATE_BIT, RegState::Implicit);
9730b57cec5SDimitry Andric     return true;
9740b57cec5SDimitry Andric   }
9750b57cec5SDimitry Andric 
9760b57cec5SDimitry Andric   return false;
9770b57cec5SDimitry Andric }
9780b57cec5SDimitry Andric 
getPredicationCost(const MachineInstr &) const9790b57cec5SDimitry Andric unsigned int R600InstrInfo::getPredicationCost(const MachineInstr &) const {
9800b57cec5SDimitry Andric   return 2;
9810b57cec5SDimitry Andric }
9820b57cec5SDimitry Andric 
getInstrLatency(const InstrItineraryData * ItinData,const MachineInstr &,unsigned * PredCost) const9830b57cec5SDimitry Andric unsigned int R600InstrInfo::getInstrLatency(const InstrItineraryData *ItinData,
9840b57cec5SDimitry Andric                                             const MachineInstr &,
9850b57cec5SDimitry Andric                                             unsigned *PredCost) const {
9860b57cec5SDimitry Andric   if (PredCost)
9870b57cec5SDimitry Andric     *PredCost = 2;
9880b57cec5SDimitry Andric   return 2;
9890b57cec5SDimitry Andric }
9900b57cec5SDimitry Andric 
calculateIndirectAddress(unsigned RegIndex,unsigned Channel) const9910b57cec5SDimitry Andric unsigned R600InstrInfo::calculateIndirectAddress(unsigned RegIndex,
9920b57cec5SDimitry Andric                                                    unsigned Channel) const {
9930b57cec5SDimitry Andric   assert(Channel == 0);
9940b57cec5SDimitry Andric   return RegIndex;
9950b57cec5SDimitry Andric }
9960b57cec5SDimitry Andric 
expandPostRAPseudo(MachineInstr & MI) const9970b57cec5SDimitry Andric bool R600InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
9980b57cec5SDimitry Andric   switch (MI.getOpcode()) {
9990b57cec5SDimitry Andric   default: {
10000b57cec5SDimitry Andric     MachineBasicBlock *MBB = MI.getParent();
10010b57cec5SDimitry Andric     int OffsetOpIdx =
10020b57cec5SDimitry Andric         R600::getNamedOperandIdx(MI.getOpcode(), R600::OpName::addr);
10030b57cec5SDimitry Andric     // addr is a custom operand with multiple MI operands, and only the
10040b57cec5SDimitry Andric     // first MI operand is given a name.
10050b57cec5SDimitry Andric     int RegOpIdx = OffsetOpIdx + 1;
10060b57cec5SDimitry Andric     int ChanOpIdx =
10070b57cec5SDimitry Andric         R600::getNamedOperandIdx(MI.getOpcode(), R600::OpName::chan);
10080b57cec5SDimitry Andric     if (isRegisterLoad(MI)) {
10090b57cec5SDimitry Andric       int DstOpIdx =
10100b57cec5SDimitry Andric           R600::getNamedOperandIdx(MI.getOpcode(), R600::OpName::dst);
10110b57cec5SDimitry Andric       unsigned RegIndex = MI.getOperand(RegOpIdx).getImm();
10120b57cec5SDimitry Andric       unsigned Channel = MI.getOperand(ChanOpIdx).getImm();
10130b57cec5SDimitry Andric       unsigned Address = calculateIndirectAddress(RegIndex, Channel);
10148bcb0991SDimitry Andric       Register OffsetReg = MI.getOperand(OffsetOpIdx).getReg();
10150b57cec5SDimitry Andric       if (OffsetReg == R600::INDIRECT_BASE_ADDR) {
10160b57cec5SDimitry Andric         buildMovInstr(MBB, MI, MI.getOperand(DstOpIdx).getReg(),
10170b57cec5SDimitry Andric                       getIndirectAddrRegClass()->getRegister(Address));
10180b57cec5SDimitry Andric       } else {
10190b57cec5SDimitry Andric         buildIndirectRead(MBB, MI, MI.getOperand(DstOpIdx).getReg(), Address,
10200b57cec5SDimitry Andric                           OffsetReg);
10210b57cec5SDimitry Andric       }
10220b57cec5SDimitry Andric     } else if (isRegisterStore(MI)) {
10230b57cec5SDimitry Andric       int ValOpIdx =
10240b57cec5SDimitry Andric           R600::getNamedOperandIdx(MI.getOpcode(), R600::OpName::val);
10250b57cec5SDimitry Andric       unsigned RegIndex = MI.getOperand(RegOpIdx).getImm();
10260b57cec5SDimitry Andric       unsigned Channel = MI.getOperand(ChanOpIdx).getImm();
10270b57cec5SDimitry Andric       unsigned Address = calculateIndirectAddress(RegIndex, Channel);
10288bcb0991SDimitry Andric       Register OffsetReg = MI.getOperand(OffsetOpIdx).getReg();
10290b57cec5SDimitry Andric       if (OffsetReg == R600::INDIRECT_BASE_ADDR) {
10300b57cec5SDimitry Andric         buildMovInstr(MBB, MI, getIndirectAddrRegClass()->getRegister(Address),
10310b57cec5SDimitry Andric                       MI.getOperand(ValOpIdx).getReg());
10320b57cec5SDimitry Andric       } else {
10330b57cec5SDimitry Andric         buildIndirectWrite(MBB, MI, MI.getOperand(ValOpIdx).getReg(),
10340b57cec5SDimitry Andric                            calculateIndirectAddress(RegIndex, Channel),
10350b57cec5SDimitry Andric                            OffsetReg);
10360b57cec5SDimitry Andric       }
10370b57cec5SDimitry Andric     } else {
10380b57cec5SDimitry Andric       return false;
10390b57cec5SDimitry Andric     }
10400b57cec5SDimitry Andric 
10410b57cec5SDimitry Andric     MBB->erase(MI);
10420b57cec5SDimitry Andric     return true;
10430b57cec5SDimitry Andric   }
10440b57cec5SDimitry Andric   case R600::R600_EXTRACT_ELT_V2:
10450b57cec5SDimitry Andric   case R600::R600_EXTRACT_ELT_V4:
10460b57cec5SDimitry Andric     buildIndirectRead(MI.getParent(), MI, MI.getOperand(0).getReg(),
10470b57cec5SDimitry Andric                       RI.getHWRegIndex(MI.getOperand(1).getReg()), //  Address
10480b57cec5SDimitry Andric                       MI.getOperand(2).getReg(),
10490b57cec5SDimitry Andric                       RI.getHWRegChan(MI.getOperand(1).getReg()));
10500b57cec5SDimitry Andric     break;
10510b57cec5SDimitry Andric   case R600::R600_INSERT_ELT_V2:
10520b57cec5SDimitry Andric   case R600::R600_INSERT_ELT_V4:
10530b57cec5SDimitry Andric     buildIndirectWrite(MI.getParent(), MI, MI.getOperand(2).getReg(), // Value
10540b57cec5SDimitry Andric                        RI.getHWRegIndex(MI.getOperand(1).getReg()),   // Address
10550b57cec5SDimitry Andric                        MI.getOperand(3).getReg(),                     // Offset
10560b57cec5SDimitry Andric                        RI.getHWRegChan(MI.getOperand(1).getReg()));   // Channel
10570b57cec5SDimitry Andric     break;
10580b57cec5SDimitry Andric   }
10590b57cec5SDimitry Andric   MI.eraseFromParent();
10600b57cec5SDimitry Andric   return true;
10610b57cec5SDimitry Andric }
10620b57cec5SDimitry Andric 
reserveIndirectRegisters(BitVector & Reserved,const MachineFunction & MF,const R600RegisterInfo & TRI) const10630b57cec5SDimitry Andric void R600InstrInfo::reserveIndirectRegisters(BitVector &Reserved,
10640b57cec5SDimitry Andric                                              const MachineFunction &MF,
10650b57cec5SDimitry Andric                                              const R600RegisterInfo &TRI) const {
10660b57cec5SDimitry Andric   const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>();
10670b57cec5SDimitry Andric   const R600FrameLowering *TFL = ST.getFrameLowering();
10680b57cec5SDimitry Andric 
10690b57cec5SDimitry Andric   unsigned StackWidth = TFL->getStackWidth(MF);
10700b57cec5SDimitry Andric   int End = getIndirectIndexEnd(MF);
10710b57cec5SDimitry Andric 
10720b57cec5SDimitry Andric   if (End == -1)
10730b57cec5SDimitry Andric     return;
10740b57cec5SDimitry Andric 
10750b57cec5SDimitry Andric   for (int Index = getIndirectIndexBegin(MF); Index <= End; ++Index) {
10760b57cec5SDimitry Andric     for (unsigned Chan = 0; Chan < StackWidth; ++Chan) {
10770b57cec5SDimitry Andric       unsigned Reg = R600::R600_TReg32RegClass.getRegister((4 * Index) + Chan);
10780b57cec5SDimitry Andric       TRI.reserveRegisterTuples(Reserved, Reg);
10790b57cec5SDimitry Andric     }
10800b57cec5SDimitry Andric   }
10810b57cec5SDimitry Andric }
10820b57cec5SDimitry Andric 
getIndirectAddrRegClass() const10830b57cec5SDimitry Andric const TargetRegisterClass *R600InstrInfo::getIndirectAddrRegClass() const {
10840b57cec5SDimitry Andric   return &R600::R600_TReg32_XRegClass;
10850b57cec5SDimitry Andric }
10860b57cec5SDimitry Andric 
buildIndirectWrite(MachineBasicBlock * MBB,MachineBasicBlock::iterator I,unsigned ValueReg,unsigned Address,unsigned OffsetReg) const10870b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildIndirectWrite(MachineBasicBlock *MBB,
10880b57cec5SDimitry Andric                                        MachineBasicBlock::iterator I,
10890b57cec5SDimitry Andric                                        unsigned ValueReg, unsigned Address,
10900b57cec5SDimitry Andric                                        unsigned OffsetReg) const {
10910b57cec5SDimitry Andric   return buildIndirectWrite(MBB, I, ValueReg, Address, OffsetReg, 0);
10920b57cec5SDimitry Andric }
10930b57cec5SDimitry Andric 
buildIndirectWrite(MachineBasicBlock * MBB,MachineBasicBlock::iterator I,unsigned ValueReg,unsigned Address,unsigned OffsetReg,unsigned AddrChan) const10940b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildIndirectWrite(MachineBasicBlock *MBB,
10950b57cec5SDimitry Andric                                        MachineBasicBlock::iterator I,
10960b57cec5SDimitry Andric                                        unsigned ValueReg, unsigned Address,
10970b57cec5SDimitry Andric                                        unsigned OffsetReg,
10980b57cec5SDimitry Andric                                        unsigned AddrChan) const {
10990b57cec5SDimitry Andric   unsigned AddrReg;
11000b57cec5SDimitry Andric   switch (AddrChan) {
11010b57cec5SDimitry Andric     default: llvm_unreachable("Invalid Channel");
11020b57cec5SDimitry Andric     case 0: AddrReg = R600::R600_AddrRegClass.getRegister(Address); break;
11030b57cec5SDimitry Andric     case 1: AddrReg = R600::R600_Addr_YRegClass.getRegister(Address); break;
11040b57cec5SDimitry Andric     case 2: AddrReg = R600::R600_Addr_ZRegClass.getRegister(Address); break;
11050b57cec5SDimitry Andric     case 3: AddrReg = R600::R600_Addr_WRegClass.getRegister(Address); break;
11060b57cec5SDimitry Andric   }
11070b57cec5SDimitry Andric   MachineInstr *MOVA = buildDefaultInstruction(*MBB, I, R600::MOVA_INT_eg,
11080b57cec5SDimitry Andric                                                R600::AR_X, OffsetReg);
11090b57cec5SDimitry Andric   setImmOperand(*MOVA, R600::OpName::write, 0);
11100b57cec5SDimitry Andric 
11110b57cec5SDimitry Andric   MachineInstrBuilder Mov = buildDefaultInstruction(*MBB, I, R600::MOV,
11120b57cec5SDimitry Andric                                       AddrReg, ValueReg)
11130b57cec5SDimitry Andric                                       .addReg(R600::AR_X,
11140b57cec5SDimitry Andric                                            RegState::Implicit | RegState::Kill);
11150b57cec5SDimitry Andric   setImmOperand(*Mov, R600::OpName::dst_rel, 1);
11160b57cec5SDimitry Andric   return Mov;
11170b57cec5SDimitry Andric }
11180b57cec5SDimitry Andric 
buildIndirectRead(MachineBasicBlock * MBB,MachineBasicBlock::iterator I,unsigned ValueReg,unsigned Address,unsigned OffsetReg) const11190b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildIndirectRead(MachineBasicBlock *MBB,
11200b57cec5SDimitry Andric                                        MachineBasicBlock::iterator I,
11210b57cec5SDimitry Andric                                        unsigned ValueReg, unsigned Address,
11220b57cec5SDimitry Andric                                        unsigned OffsetReg) const {
11230b57cec5SDimitry Andric   return buildIndirectRead(MBB, I, ValueReg, Address, OffsetReg, 0);
11240b57cec5SDimitry Andric }
11250b57cec5SDimitry Andric 
buildIndirectRead(MachineBasicBlock * MBB,MachineBasicBlock::iterator I,unsigned ValueReg,unsigned Address,unsigned OffsetReg,unsigned AddrChan) const11260b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildIndirectRead(MachineBasicBlock *MBB,
11270b57cec5SDimitry Andric                                        MachineBasicBlock::iterator I,
11280b57cec5SDimitry Andric                                        unsigned ValueReg, unsigned Address,
11290b57cec5SDimitry Andric                                        unsigned OffsetReg,
11300b57cec5SDimitry Andric                                        unsigned AddrChan) const {
11310b57cec5SDimitry Andric   unsigned AddrReg;
11320b57cec5SDimitry Andric   switch (AddrChan) {
11330b57cec5SDimitry Andric     default: llvm_unreachable("Invalid Channel");
11340b57cec5SDimitry Andric     case 0: AddrReg = R600::R600_AddrRegClass.getRegister(Address); break;
11350b57cec5SDimitry Andric     case 1: AddrReg = R600::R600_Addr_YRegClass.getRegister(Address); break;
11360b57cec5SDimitry Andric     case 2: AddrReg = R600::R600_Addr_ZRegClass.getRegister(Address); break;
11370b57cec5SDimitry Andric     case 3: AddrReg = R600::R600_Addr_WRegClass.getRegister(Address); break;
11380b57cec5SDimitry Andric   }
11390b57cec5SDimitry Andric   MachineInstr *MOVA = buildDefaultInstruction(*MBB, I, R600::MOVA_INT_eg,
11400b57cec5SDimitry Andric                                                        R600::AR_X,
11410b57cec5SDimitry Andric                                                        OffsetReg);
11420b57cec5SDimitry Andric   setImmOperand(*MOVA, R600::OpName::write, 0);
11430b57cec5SDimitry Andric   MachineInstrBuilder Mov = buildDefaultInstruction(*MBB, I, R600::MOV,
11440b57cec5SDimitry Andric                                       ValueReg,
11450b57cec5SDimitry Andric                                       AddrReg)
11460b57cec5SDimitry Andric                                       .addReg(R600::AR_X,
11470b57cec5SDimitry Andric                                            RegState::Implicit | RegState::Kill);
11480b57cec5SDimitry Andric   setImmOperand(*Mov, R600::OpName::src0_rel, 1);
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric   return Mov;
11510b57cec5SDimitry Andric }
11520b57cec5SDimitry Andric 
getIndirectIndexBegin(const MachineFunction & MF) const11530b57cec5SDimitry Andric int R600InstrInfo::getIndirectIndexBegin(const MachineFunction &MF) const {
11540b57cec5SDimitry Andric   const MachineRegisterInfo &MRI = MF.getRegInfo();
11550b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
11560b57cec5SDimitry Andric   int Offset = -1;
11570b57cec5SDimitry Andric 
11580b57cec5SDimitry Andric   if (MFI.getNumObjects() == 0) {
11590b57cec5SDimitry Andric     return -1;
11600b57cec5SDimitry Andric   }
11610b57cec5SDimitry Andric 
11620b57cec5SDimitry Andric   if (MRI.livein_empty()) {
11630b57cec5SDimitry Andric     return 0;
11640b57cec5SDimitry Andric   }
11650b57cec5SDimitry Andric 
11660b57cec5SDimitry Andric   const TargetRegisterClass *IndirectRC = getIndirectAddrRegClass();
11670b57cec5SDimitry Andric   for (std::pair<unsigned, unsigned> LI : MRI.liveins()) {
1168e8d8bef9SDimitry Andric     Register Reg = LI.first;
1169e8d8bef9SDimitry Andric     if (Reg.isVirtual() || !IndirectRC->contains(Reg))
11700b57cec5SDimitry Andric       continue;
11710b57cec5SDimitry Andric 
11720b57cec5SDimitry Andric     unsigned RegIndex;
11730b57cec5SDimitry Andric     unsigned RegEnd;
11740b57cec5SDimitry Andric     for (RegIndex = 0, RegEnd = IndirectRC->getNumRegs(); RegIndex != RegEnd;
11750b57cec5SDimitry Andric                                                           ++RegIndex) {
1176e8d8bef9SDimitry Andric       if (IndirectRC->getRegister(RegIndex) == (unsigned)Reg)
11770b57cec5SDimitry Andric         break;
11780b57cec5SDimitry Andric     }
11790b57cec5SDimitry Andric     Offset = std::max(Offset, (int)RegIndex);
11800b57cec5SDimitry Andric   }
11810b57cec5SDimitry Andric 
11820b57cec5SDimitry Andric   return Offset + 1;
11830b57cec5SDimitry Andric }
11840b57cec5SDimitry Andric 
getIndirectIndexEnd(const MachineFunction & MF) const11850b57cec5SDimitry Andric int R600InstrInfo::getIndirectIndexEnd(const MachineFunction &MF) const {
11860b57cec5SDimitry Andric   int Offset = 0;
11870b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
11880b57cec5SDimitry Andric 
11890b57cec5SDimitry Andric   // Variable sized objects are not supported
11900b57cec5SDimitry Andric   if (MFI.hasVarSizedObjects()) {
11910b57cec5SDimitry Andric     return -1;
11920b57cec5SDimitry Andric   }
11930b57cec5SDimitry Andric 
11940b57cec5SDimitry Andric   if (MFI.getNumObjects() == 0) {
11950b57cec5SDimitry Andric     return -1;
11960b57cec5SDimitry Andric   }
11970b57cec5SDimitry Andric 
11980b57cec5SDimitry Andric   const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>();
11990b57cec5SDimitry Andric   const R600FrameLowering *TFL = ST.getFrameLowering();
12000b57cec5SDimitry Andric 
12015ffd83dbSDimitry Andric   Register IgnoredFrameReg;
1202e8d8bef9SDimitry Andric   Offset = TFL->getFrameIndexReference(MF, -1, IgnoredFrameReg).getFixed();
12030b57cec5SDimitry Andric 
12040b57cec5SDimitry Andric   return getIndirectIndexBegin(MF) + Offset;
12050b57cec5SDimitry Andric }
12060b57cec5SDimitry Andric 
getMaxAlusPerClause() const12070b57cec5SDimitry Andric unsigned R600InstrInfo::getMaxAlusPerClause() const {
12080b57cec5SDimitry Andric   return 115;
12090b57cec5SDimitry Andric }
12100b57cec5SDimitry Andric 
buildDefaultInstruction(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,unsigned Opcode,unsigned DstReg,unsigned Src0Reg,unsigned Src1Reg) const12110b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildDefaultInstruction(MachineBasicBlock &MBB,
12120b57cec5SDimitry Andric                                                   MachineBasicBlock::iterator I,
12130b57cec5SDimitry Andric                                                   unsigned Opcode,
12140b57cec5SDimitry Andric                                                   unsigned DstReg,
12150b57cec5SDimitry Andric                                                   unsigned Src0Reg,
12160b57cec5SDimitry Andric                                                   unsigned Src1Reg) const {
12170b57cec5SDimitry Andric   MachineInstrBuilder MIB = BuildMI(MBB, I, MBB.findDebugLoc(I), get(Opcode),
12180b57cec5SDimitry Andric     DstReg);           // $dst
12190b57cec5SDimitry Andric 
12200b57cec5SDimitry Andric   if (Src1Reg) {
12210b57cec5SDimitry Andric     MIB.addImm(0)     // $update_exec_mask
12220b57cec5SDimitry Andric        .addImm(0);    // $update_predicate
12230b57cec5SDimitry Andric   }
12240b57cec5SDimitry Andric   MIB.addImm(1)        // $write
12250b57cec5SDimitry Andric      .addImm(0)        // $omod
12260b57cec5SDimitry Andric      .addImm(0)        // $dst_rel
12270b57cec5SDimitry Andric      .addImm(0)        // $dst_clamp
12280b57cec5SDimitry Andric      .addReg(Src0Reg)  // $src0
12290b57cec5SDimitry Andric      .addImm(0)        // $src0_neg
12300b57cec5SDimitry Andric      .addImm(0)        // $src0_rel
12310b57cec5SDimitry Andric      .addImm(0)        // $src0_abs
12320b57cec5SDimitry Andric      .addImm(-1);       // $src0_sel
12330b57cec5SDimitry Andric 
12340b57cec5SDimitry Andric   if (Src1Reg) {
12350b57cec5SDimitry Andric     MIB.addReg(Src1Reg) // $src1
12360b57cec5SDimitry Andric        .addImm(0)       // $src1_neg
12370b57cec5SDimitry Andric        .addImm(0)       // $src1_rel
12380b57cec5SDimitry Andric        .addImm(0)       // $src1_abs
12390b57cec5SDimitry Andric        .addImm(-1);      // $src1_sel
12400b57cec5SDimitry Andric   }
12410b57cec5SDimitry Andric 
12420b57cec5SDimitry Andric   //XXX: The r600g finalizer expects this to be 1, once we've moved the
12430b57cec5SDimitry Andric   //scheduling to the backend, we can change the default to 0.
12440b57cec5SDimitry Andric   MIB.addImm(1)        // $last
12450b57cec5SDimitry Andric       .addReg(R600::PRED_SEL_OFF) // $pred_sel
12460b57cec5SDimitry Andric       .addImm(0)         // $literal
12470b57cec5SDimitry Andric       .addImm(0);        // $bank_swizzle
12480b57cec5SDimitry Andric 
12490b57cec5SDimitry Andric   return MIB;
12500b57cec5SDimitry Andric }
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric #define OPERAND_CASE(Label) \
12530b57cec5SDimitry Andric   case Label: { \
12540b57cec5SDimitry Andric     static const unsigned Ops[] = \
12550b57cec5SDimitry Andric     { \
12560b57cec5SDimitry Andric       Label##_X, \
12570b57cec5SDimitry Andric       Label##_Y, \
12580b57cec5SDimitry Andric       Label##_Z, \
12590b57cec5SDimitry Andric       Label##_W \
12600b57cec5SDimitry Andric     }; \
12610b57cec5SDimitry Andric     return Ops[Slot]; \
12620b57cec5SDimitry Andric   }
12630b57cec5SDimitry Andric 
getSlotedOps(unsigned Op,unsigned Slot)12640b57cec5SDimitry Andric static unsigned getSlotedOps(unsigned  Op, unsigned Slot) {
12650b57cec5SDimitry Andric   switch (Op) {
12660b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::update_exec_mask)
12670b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::update_pred)
12680b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::write)
12690b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::omod)
12700b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::dst_rel)
12710b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::clamp)
12720b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src0)
12730b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src0_neg)
12740b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src0_rel)
12750b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src0_abs)
12760b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src0_sel)
12770b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src1)
12780b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src1_neg)
12790b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src1_rel)
12800b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src1_abs)
12810b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::src1_sel)
12820b57cec5SDimitry Andric   OPERAND_CASE(R600::OpName::pred_sel)
12830b57cec5SDimitry Andric   default:
12840b57cec5SDimitry Andric     llvm_unreachable("Wrong Operand");
12850b57cec5SDimitry Andric   }
12860b57cec5SDimitry Andric }
12870b57cec5SDimitry Andric 
12880b57cec5SDimitry Andric #undef OPERAND_CASE
12890b57cec5SDimitry Andric 
buildSlotOfVectorInstruction(MachineBasicBlock & MBB,MachineInstr * MI,unsigned Slot,unsigned DstReg) const12900b57cec5SDimitry Andric MachineInstr *R600InstrInfo::buildSlotOfVectorInstruction(
12910b57cec5SDimitry Andric     MachineBasicBlock &MBB, MachineInstr *MI, unsigned Slot, unsigned DstReg)
12920b57cec5SDimitry Andric     const {
12930b57cec5SDimitry Andric   assert (MI->getOpcode() == R600::DOT_4 && "Not Implemented");
12940b57cec5SDimitry Andric   unsigned Opcode;
12950b57cec5SDimitry Andric   if (ST.getGeneration() <= AMDGPUSubtarget::R700)
12960b57cec5SDimitry Andric     Opcode = R600::DOT4_r600;
12970b57cec5SDimitry Andric   else
12980b57cec5SDimitry Andric     Opcode = R600::DOT4_eg;
12990b57cec5SDimitry Andric   MachineBasicBlock::iterator I = MI;
13000b57cec5SDimitry Andric   MachineOperand &Src0 = MI->getOperand(
13010b57cec5SDimitry Andric       getOperandIdx(MI->getOpcode(), getSlotedOps(R600::OpName::src0, Slot)));
13020b57cec5SDimitry Andric   MachineOperand &Src1 = MI->getOperand(
13030b57cec5SDimitry Andric       getOperandIdx(MI->getOpcode(), getSlotedOps(R600::OpName::src1, Slot)));
13040b57cec5SDimitry Andric   MachineInstr *MIB = buildDefaultInstruction(
13050b57cec5SDimitry Andric       MBB, I, Opcode, DstReg, Src0.getReg(), Src1.getReg());
13060b57cec5SDimitry Andric   static const unsigned  Operands[14] = {
13070b57cec5SDimitry Andric     R600::OpName::update_exec_mask,
13080b57cec5SDimitry Andric     R600::OpName::update_pred,
13090b57cec5SDimitry Andric     R600::OpName::write,
13100b57cec5SDimitry Andric     R600::OpName::omod,
13110b57cec5SDimitry Andric     R600::OpName::dst_rel,
13120b57cec5SDimitry Andric     R600::OpName::clamp,
13130b57cec5SDimitry Andric     R600::OpName::src0_neg,
13140b57cec5SDimitry Andric     R600::OpName::src0_rel,
13150b57cec5SDimitry Andric     R600::OpName::src0_abs,
13160b57cec5SDimitry Andric     R600::OpName::src0_sel,
13170b57cec5SDimitry Andric     R600::OpName::src1_neg,
13180b57cec5SDimitry Andric     R600::OpName::src1_rel,
13190b57cec5SDimitry Andric     R600::OpName::src1_abs,
13200b57cec5SDimitry Andric     R600::OpName::src1_sel,
13210b57cec5SDimitry Andric   };
13220b57cec5SDimitry Andric 
13230b57cec5SDimitry Andric   MachineOperand &MO = MI->getOperand(getOperandIdx(MI->getOpcode(),
13240b57cec5SDimitry Andric       getSlotedOps(R600::OpName::pred_sel, Slot)));
13250b57cec5SDimitry Andric   MIB->getOperand(getOperandIdx(Opcode, R600::OpName::pred_sel))
13260b57cec5SDimitry Andric       .setReg(MO.getReg());
13270b57cec5SDimitry Andric 
13280eae32dcSDimitry Andric   for (unsigned Operand : Operands) {
13290b57cec5SDimitry Andric     MachineOperand &MO = MI->getOperand(
13300eae32dcSDimitry Andric         getOperandIdx(MI->getOpcode(), getSlotedOps(Operand, Slot)));
13310b57cec5SDimitry Andric     assert (MO.isImm());
13320eae32dcSDimitry Andric     setImmOperand(*MIB, Operand, MO.getImm());
13330b57cec5SDimitry Andric   }
13340b57cec5SDimitry Andric   MIB->getOperand(20).setImm(0);
13350b57cec5SDimitry Andric   return MIB;
13360b57cec5SDimitry Andric }
13370b57cec5SDimitry Andric 
buildMovImm(MachineBasicBlock & BB,MachineBasicBlock::iterator I,unsigned DstReg,uint64_t Imm) const13380b57cec5SDimitry Andric MachineInstr *R600InstrInfo::buildMovImm(MachineBasicBlock &BB,
13390b57cec5SDimitry Andric                                          MachineBasicBlock::iterator I,
13400b57cec5SDimitry Andric                                          unsigned DstReg,
13410b57cec5SDimitry Andric                                          uint64_t Imm) const {
13420b57cec5SDimitry Andric   MachineInstr *MovImm = buildDefaultInstruction(BB, I, R600::MOV, DstReg,
13430b57cec5SDimitry Andric                                                   R600::ALU_LITERAL_X);
13440b57cec5SDimitry Andric   setImmOperand(*MovImm, R600::OpName::literal, Imm);
13450b57cec5SDimitry Andric   return MovImm;
13460b57cec5SDimitry Andric }
13470b57cec5SDimitry Andric 
buildMovInstr(MachineBasicBlock * MBB,MachineBasicBlock::iterator I,unsigned DstReg,unsigned SrcReg) const13480b57cec5SDimitry Andric MachineInstr *R600InstrInfo::buildMovInstr(MachineBasicBlock *MBB,
13490b57cec5SDimitry Andric                                        MachineBasicBlock::iterator I,
13500b57cec5SDimitry Andric                                        unsigned DstReg, unsigned SrcReg) const {
13510b57cec5SDimitry Andric   return buildDefaultInstruction(*MBB, I, R600::MOV, DstReg, SrcReg);
13520b57cec5SDimitry Andric }
13530b57cec5SDimitry Andric 
getOperandIdx(const MachineInstr & MI,unsigned Op) const13540b57cec5SDimitry Andric int R600InstrInfo::getOperandIdx(const MachineInstr &MI, unsigned Op) const {
13550b57cec5SDimitry Andric   return getOperandIdx(MI.getOpcode(), Op);
13560b57cec5SDimitry Andric }
13570b57cec5SDimitry Andric 
getOperandIdx(unsigned Opcode,unsigned Op) const13580b57cec5SDimitry Andric int R600InstrInfo::getOperandIdx(unsigned Opcode, unsigned Op) const {
13590b57cec5SDimitry Andric   return R600::getNamedOperandIdx(Opcode, Op);
13600b57cec5SDimitry Andric }
13610b57cec5SDimitry Andric 
setImmOperand(MachineInstr & MI,unsigned Op,int64_t Imm) const13620b57cec5SDimitry Andric void R600InstrInfo::setImmOperand(MachineInstr &MI, unsigned Op,
13630b57cec5SDimitry Andric                                   int64_t Imm) const {
13640b57cec5SDimitry Andric   int Idx = getOperandIdx(MI, Op);
13650b57cec5SDimitry Andric   assert(Idx != -1 && "Operand not supported for this instruction.");
13660b57cec5SDimitry Andric   assert(MI.getOperand(Idx).isImm());
13670b57cec5SDimitry Andric   MI.getOperand(Idx).setImm(Imm);
13680b57cec5SDimitry Andric }
13690b57cec5SDimitry Andric 
13700b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13710b57cec5SDimitry Andric // Instruction flag getters/setters
13720b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13730b57cec5SDimitry Andric 
getFlagOp(MachineInstr & MI,unsigned SrcIdx,unsigned Flag) const13740b57cec5SDimitry Andric MachineOperand &R600InstrInfo::getFlagOp(MachineInstr &MI, unsigned SrcIdx,
13750b57cec5SDimitry Andric                                          unsigned Flag) const {
13760b57cec5SDimitry Andric   unsigned TargetFlags = get(MI.getOpcode()).TSFlags;
13770b57cec5SDimitry Andric   int FlagIndex = 0;
13780b57cec5SDimitry Andric   if (Flag != 0) {
13790b57cec5SDimitry Andric     // If we pass something other than the default value of Flag to this
13800b57cec5SDimitry Andric     // function, it means we are want to set a flag on an instruction
13810b57cec5SDimitry Andric     // that uses native encoding.
13820b57cec5SDimitry Andric     assert(HAS_NATIVE_OPERANDS(TargetFlags));
13830b57cec5SDimitry Andric     bool IsOP3 = (TargetFlags & R600_InstFlag::OP3) == R600_InstFlag::OP3;
13840b57cec5SDimitry Andric     switch (Flag) {
13850b57cec5SDimitry Andric     case MO_FLAG_CLAMP:
13860b57cec5SDimitry Andric       FlagIndex = getOperandIdx(MI, R600::OpName::clamp);
13870b57cec5SDimitry Andric       break;
13880b57cec5SDimitry Andric     case MO_FLAG_MASK:
13890b57cec5SDimitry Andric       FlagIndex = getOperandIdx(MI, R600::OpName::write);
13900b57cec5SDimitry Andric       break;
13910b57cec5SDimitry Andric     case MO_FLAG_NOT_LAST:
13920b57cec5SDimitry Andric     case MO_FLAG_LAST:
13930b57cec5SDimitry Andric       FlagIndex = getOperandIdx(MI, R600::OpName::last);
13940b57cec5SDimitry Andric       break;
13950b57cec5SDimitry Andric     case MO_FLAG_NEG:
13960b57cec5SDimitry Andric       switch (SrcIdx) {
13970b57cec5SDimitry Andric       case 0:
13980b57cec5SDimitry Andric         FlagIndex = getOperandIdx(MI, R600::OpName::src0_neg);
13990b57cec5SDimitry Andric         break;
14000b57cec5SDimitry Andric       case 1:
14010b57cec5SDimitry Andric         FlagIndex = getOperandIdx(MI, R600::OpName::src1_neg);
14020b57cec5SDimitry Andric         break;
14030b57cec5SDimitry Andric       case 2:
14040b57cec5SDimitry Andric         FlagIndex = getOperandIdx(MI, R600::OpName::src2_neg);
14050b57cec5SDimitry Andric         break;
14060b57cec5SDimitry Andric       }
14070b57cec5SDimitry Andric       break;
14080b57cec5SDimitry Andric 
14090b57cec5SDimitry Andric     case MO_FLAG_ABS:
14100b57cec5SDimitry Andric       assert(!IsOP3 && "Cannot set absolute value modifier for OP3 "
14110b57cec5SDimitry Andric                        "instructions.");
14120b57cec5SDimitry Andric       (void)IsOP3;
14130b57cec5SDimitry Andric       switch (SrcIdx) {
14140b57cec5SDimitry Andric       case 0:
14150b57cec5SDimitry Andric         FlagIndex = getOperandIdx(MI, R600::OpName::src0_abs);
14160b57cec5SDimitry Andric         break;
14170b57cec5SDimitry Andric       case 1:
14180b57cec5SDimitry Andric         FlagIndex = getOperandIdx(MI, R600::OpName::src1_abs);
14190b57cec5SDimitry Andric         break;
14200b57cec5SDimitry Andric       }
14210b57cec5SDimitry Andric       break;
14220b57cec5SDimitry Andric 
14230b57cec5SDimitry Andric     default:
14240b57cec5SDimitry Andric       FlagIndex = -1;
14250b57cec5SDimitry Andric       break;
14260b57cec5SDimitry Andric     }
14270b57cec5SDimitry Andric     assert(FlagIndex != -1 && "Flag not supported for this instruction");
14280b57cec5SDimitry Andric   } else {
14290b57cec5SDimitry Andric       FlagIndex = GET_FLAG_OPERAND_IDX(TargetFlags);
14300b57cec5SDimitry Andric       assert(FlagIndex != 0 &&
14310b57cec5SDimitry Andric          "Instruction flags not supported for this instruction");
14320b57cec5SDimitry Andric   }
14330b57cec5SDimitry Andric 
14340b57cec5SDimitry Andric   MachineOperand &FlagOp = MI.getOperand(FlagIndex);
14350b57cec5SDimitry Andric   assert(FlagOp.isImm());
14360b57cec5SDimitry Andric   return FlagOp;
14370b57cec5SDimitry Andric }
14380b57cec5SDimitry Andric 
addFlag(MachineInstr & MI,unsigned Operand,unsigned Flag) const14390b57cec5SDimitry Andric void R600InstrInfo::addFlag(MachineInstr &MI, unsigned Operand,
14400b57cec5SDimitry Andric                             unsigned Flag) const {
14410b57cec5SDimitry Andric   unsigned TargetFlags = get(MI.getOpcode()).TSFlags;
14420b57cec5SDimitry Andric   if (Flag == 0) {
14430b57cec5SDimitry Andric     return;
14440b57cec5SDimitry Andric   }
14450b57cec5SDimitry Andric   if (HAS_NATIVE_OPERANDS(TargetFlags)) {
14460b57cec5SDimitry Andric     MachineOperand &FlagOp = getFlagOp(MI, Operand, Flag);
14470b57cec5SDimitry Andric     if (Flag == MO_FLAG_NOT_LAST) {
14480b57cec5SDimitry Andric       clearFlag(MI, Operand, MO_FLAG_LAST);
14490b57cec5SDimitry Andric     } else if (Flag == MO_FLAG_MASK) {
14500b57cec5SDimitry Andric       clearFlag(MI, Operand, Flag);
14510b57cec5SDimitry Andric     } else {
14520b57cec5SDimitry Andric       FlagOp.setImm(1);
14530b57cec5SDimitry Andric     }
14540b57cec5SDimitry Andric   } else {
14550b57cec5SDimitry Andric       MachineOperand &FlagOp = getFlagOp(MI, Operand);
14560b57cec5SDimitry Andric       FlagOp.setImm(FlagOp.getImm() | (Flag << (NUM_MO_FLAGS * Operand)));
14570b57cec5SDimitry Andric   }
14580b57cec5SDimitry Andric }
14590b57cec5SDimitry Andric 
clearFlag(MachineInstr & MI,unsigned Operand,unsigned Flag) const14600b57cec5SDimitry Andric void R600InstrInfo::clearFlag(MachineInstr &MI, unsigned Operand,
14610b57cec5SDimitry Andric                               unsigned Flag) const {
14620b57cec5SDimitry Andric   unsigned TargetFlags = get(MI.getOpcode()).TSFlags;
14630b57cec5SDimitry Andric   if (HAS_NATIVE_OPERANDS(TargetFlags)) {
14640b57cec5SDimitry Andric     MachineOperand &FlagOp = getFlagOp(MI, Operand, Flag);
14650b57cec5SDimitry Andric     FlagOp.setImm(0);
14660b57cec5SDimitry Andric   } else {
14670b57cec5SDimitry Andric     MachineOperand &FlagOp = getFlagOp(MI);
14680b57cec5SDimitry Andric     unsigned InstFlags = FlagOp.getImm();
14690b57cec5SDimitry Andric     InstFlags &= ~(Flag << (NUM_MO_FLAGS * Operand));
14700b57cec5SDimitry Andric     FlagOp.setImm(InstFlags);
14710b57cec5SDimitry Andric   }
14720b57cec5SDimitry Andric }
1473