1*0b57cec5SDimitry Andric //===-- R600InstrInfo.cpp - R600 Instruction Information ------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric /// \file 10*0b57cec5SDimitry Andric /// R600 Implementation of TargetInstrInfo. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "R600InstrInfo.h" 15*0b57cec5SDimitry Andric #include "AMDGPU.h" 16*0b57cec5SDimitry Andric #include "AMDGPUInstrInfo.h" 17*0b57cec5SDimitry Andric #include "AMDGPUSubtarget.h" 18*0b57cec5SDimitry Andric #include "R600Defines.h" 19*0b57cec5SDimitry Andric #include "R600FrameLowering.h" 20*0b57cec5SDimitry Andric #include "R600RegisterInfo.h" 21*0b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 22*0b57cec5SDimitry Andric #include "Utils/AMDGPUBaseInfo.h" 23*0b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 24*0b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 25*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 26*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 27*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 28*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 29*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 30*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 31*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 32*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 33*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 34*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 35*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 36*0b57cec5SDimitry Andric #include <algorithm> 37*0b57cec5SDimitry Andric #include <cassert> 38*0b57cec5SDimitry Andric #include <cstdint> 39*0b57cec5SDimitry Andric #include <cstring> 40*0b57cec5SDimitry Andric #include <iterator> 41*0b57cec5SDimitry Andric #include <utility> 42*0b57cec5SDimitry Andric #include <vector> 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric using namespace llvm; 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR 47*0b57cec5SDimitry Andric #include "R600GenDFAPacketizer.inc" 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR 50*0b57cec5SDimitry Andric #define GET_INSTRMAP_INFO 51*0b57cec5SDimitry Andric #define GET_INSTRINFO_NAMED_OPS 52*0b57cec5SDimitry Andric #include "R600GenInstrInfo.inc" 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric R600InstrInfo::R600InstrInfo(const R600Subtarget &ST) 55*0b57cec5SDimitry Andric : R600GenInstrInfo(-1, -1), RI(), ST(ST) {} 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric bool R600InstrInfo::isVector(const MachineInstr &MI) const { 58*0b57cec5SDimitry Andric return get(MI.getOpcode()).TSFlags & R600_InstFlag::VECTOR; 59*0b57cec5SDimitry Andric } 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric void R600InstrInfo::copyPhysReg(MachineBasicBlock &MBB, 62*0b57cec5SDimitry Andric MachineBasicBlock::iterator MI, 63*0b57cec5SDimitry Andric const DebugLoc &DL, unsigned DestReg, 64*0b57cec5SDimitry Andric unsigned SrcReg, bool KillSrc) const { 65*0b57cec5SDimitry Andric unsigned VectorComponents = 0; 66*0b57cec5SDimitry Andric if ((R600::R600_Reg128RegClass.contains(DestReg) || 67*0b57cec5SDimitry Andric R600::R600_Reg128VerticalRegClass.contains(DestReg)) && 68*0b57cec5SDimitry Andric (R600::R600_Reg128RegClass.contains(SrcReg) || 69*0b57cec5SDimitry Andric R600::R600_Reg128VerticalRegClass.contains(SrcReg))) { 70*0b57cec5SDimitry Andric VectorComponents = 4; 71*0b57cec5SDimitry Andric } else if((R600::R600_Reg64RegClass.contains(DestReg) || 72*0b57cec5SDimitry Andric R600::R600_Reg64VerticalRegClass.contains(DestReg)) && 73*0b57cec5SDimitry Andric (R600::R600_Reg64RegClass.contains(SrcReg) || 74*0b57cec5SDimitry Andric R600::R600_Reg64VerticalRegClass.contains(SrcReg))) { 75*0b57cec5SDimitry Andric VectorComponents = 2; 76*0b57cec5SDimitry Andric } 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric if (VectorComponents > 0) { 79*0b57cec5SDimitry Andric for (unsigned I = 0; I < VectorComponents; I++) { 80*0b57cec5SDimitry Andric unsigned SubRegIndex = AMDGPURegisterInfo::getSubRegFromChannel(I); 81*0b57cec5SDimitry Andric buildDefaultInstruction(MBB, MI, R600::MOV, 82*0b57cec5SDimitry Andric RI.getSubReg(DestReg, SubRegIndex), 83*0b57cec5SDimitry Andric RI.getSubReg(SrcReg, SubRegIndex)) 84*0b57cec5SDimitry Andric .addReg(DestReg, 85*0b57cec5SDimitry Andric RegState::Define | RegState::Implicit); 86*0b57cec5SDimitry Andric } 87*0b57cec5SDimitry Andric } else { 88*0b57cec5SDimitry Andric MachineInstr *NewMI = buildDefaultInstruction(MBB, MI, R600::MOV, 89*0b57cec5SDimitry Andric DestReg, SrcReg); 90*0b57cec5SDimitry Andric NewMI->getOperand(getOperandIdx(*NewMI, R600::OpName::src0)) 91*0b57cec5SDimitry Andric .setIsKill(KillSrc); 92*0b57cec5SDimitry Andric } 93*0b57cec5SDimitry Andric } 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric /// \returns true if \p MBBI can be moved into a new basic. 96*0b57cec5SDimitry Andric bool R600InstrInfo::isLegalToSplitMBBAt(MachineBasicBlock &MBB, 97*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI) const { 98*0b57cec5SDimitry Andric for (MachineInstr::const_mop_iterator I = MBBI->operands_begin(), 99*0b57cec5SDimitry Andric E = MBBI->operands_end(); I != E; ++I) { 100*0b57cec5SDimitry Andric if (I->isReg() && !TargetRegisterInfo::isVirtualRegister(I->getReg()) && 101*0b57cec5SDimitry Andric I->isUse() && RI.isPhysRegLiveAcrossClauses(I->getReg())) 102*0b57cec5SDimitry Andric return false; 103*0b57cec5SDimitry Andric } 104*0b57cec5SDimitry Andric return true; 105*0b57cec5SDimitry Andric } 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric bool R600InstrInfo::isMov(unsigned Opcode) const { 108*0b57cec5SDimitry Andric switch(Opcode) { 109*0b57cec5SDimitry Andric default: 110*0b57cec5SDimitry Andric return false; 111*0b57cec5SDimitry Andric case R600::MOV: 112*0b57cec5SDimitry Andric case R600::MOV_IMM_F32: 113*0b57cec5SDimitry Andric case R600::MOV_IMM_I32: 114*0b57cec5SDimitry Andric return true; 115*0b57cec5SDimitry Andric } 116*0b57cec5SDimitry Andric } 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric bool R600InstrInfo::isReductionOp(unsigned Opcode) const { 119*0b57cec5SDimitry Andric return false; 120*0b57cec5SDimitry Andric } 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric bool R600InstrInfo::isCubeOp(unsigned Opcode) const { 123*0b57cec5SDimitry Andric switch(Opcode) { 124*0b57cec5SDimitry Andric default: return false; 125*0b57cec5SDimitry Andric case R600::CUBE_r600_pseudo: 126*0b57cec5SDimitry Andric case R600::CUBE_r600_real: 127*0b57cec5SDimitry Andric case R600::CUBE_eg_pseudo: 128*0b57cec5SDimitry Andric case R600::CUBE_eg_real: 129*0b57cec5SDimitry Andric return true; 130*0b57cec5SDimitry Andric } 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric bool R600InstrInfo::isALUInstr(unsigned Opcode) const { 134*0b57cec5SDimitry Andric unsigned TargetFlags = get(Opcode).TSFlags; 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric return (TargetFlags & R600_InstFlag::ALU_INST); 137*0b57cec5SDimitry Andric } 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric bool R600InstrInfo::hasInstrModifiers(unsigned Opcode) const { 140*0b57cec5SDimitry Andric unsigned TargetFlags = get(Opcode).TSFlags; 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric return ((TargetFlags & R600_InstFlag::OP1) | 143*0b57cec5SDimitry Andric (TargetFlags & R600_InstFlag::OP2) | 144*0b57cec5SDimitry Andric (TargetFlags & R600_InstFlag::OP3)); 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric bool R600InstrInfo::isLDSInstr(unsigned Opcode) const { 148*0b57cec5SDimitry Andric unsigned TargetFlags = get(Opcode).TSFlags; 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric return ((TargetFlags & R600_InstFlag::LDS_1A) | 151*0b57cec5SDimitry Andric (TargetFlags & R600_InstFlag::LDS_1A1D) | 152*0b57cec5SDimitry Andric (TargetFlags & R600_InstFlag::LDS_1A2D)); 153*0b57cec5SDimitry Andric } 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric bool R600InstrInfo::isLDSRetInstr(unsigned Opcode) const { 156*0b57cec5SDimitry Andric return isLDSInstr(Opcode) && getOperandIdx(Opcode, R600::OpName::dst) != -1; 157*0b57cec5SDimitry Andric } 158*0b57cec5SDimitry Andric 159*0b57cec5SDimitry Andric bool R600InstrInfo::canBeConsideredALU(const MachineInstr &MI) const { 160*0b57cec5SDimitry Andric if (isALUInstr(MI.getOpcode())) 161*0b57cec5SDimitry Andric return true; 162*0b57cec5SDimitry Andric if (isVector(MI) || isCubeOp(MI.getOpcode())) 163*0b57cec5SDimitry Andric return true; 164*0b57cec5SDimitry Andric switch (MI.getOpcode()) { 165*0b57cec5SDimitry Andric case R600::PRED_X: 166*0b57cec5SDimitry Andric case R600::INTERP_PAIR_XY: 167*0b57cec5SDimitry Andric case R600::INTERP_PAIR_ZW: 168*0b57cec5SDimitry Andric case R600::INTERP_VEC_LOAD: 169*0b57cec5SDimitry Andric case R600::COPY: 170*0b57cec5SDimitry Andric case R600::DOT_4: 171*0b57cec5SDimitry Andric return true; 172*0b57cec5SDimitry Andric default: 173*0b57cec5SDimitry Andric return false; 174*0b57cec5SDimitry Andric } 175*0b57cec5SDimitry Andric } 176*0b57cec5SDimitry Andric 177*0b57cec5SDimitry Andric bool R600InstrInfo::isTransOnly(unsigned Opcode) const { 178*0b57cec5SDimitry Andric if (ST.hasCaymanISA()) 179*0b57cec5SDimitry Andric return false; 180*0b57cec5SDimitry Andric return (get(Opcode).getSchedClass() == R600::Sched::TransALU); 181*0b57cec5SDimitry Andric } 182*0b57cec5SDimitry Andric 183*0b57cec5SDimitry Andric bool R600InstrInfo::isTransOnly(const MachineInstr &MI) const { 184*0b57cec5SDimitry Andric return isTransOnly(MI.getOpcode()); 185*0b57cec5SDimitry Andric } 186*0b57cec5SDimitry Andric 187*0b57cec5SDimitry Andric bool R600InstrInfo::isVectorOnly(unsigned Opcode) const { 188*0b57cec5SDimitry Andric return (get(Opcode).getSchedClass() == R600::Sched::VecALU); 189*0b57cec5SDimitry Andric } 190*0b57cec5SDimitry Andric 191*0b57cec5SDimitry Andric bool R600InstrInfo::isVectorOnly(const MachineInstr &MI) const { 192*0b57cec5SDimitry Andric return isVectorOnly(MI.getOpcode()); 193*0b57cec5SDimitry Andric } 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric bool R600InstrInfo::isExport(unsigned Opcode) const { 196*0b57cec5SDimitry Andric return (get(Opcode).TSFlags & R600_InstFlag::IS_EXPORT); 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric bool R600InstrInfo::usesVertexCache(unsigned Opcode) const { 200*0b57cec5SDimitry Andric return ST.hasVertexCache() && IS_VTX(get(Opcode)); 201*0b57cec5SDimitry Andric } 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric bool R600InstrInfo::usesVertexCache(const MachineInstr &MI) const { 204*0b57cec5SDimitry Andric const MachineFunction *MF = MI.getParent()->getParent(); 205*0b57cec5SDimitry Andric return !AMDGPU::isCompute(MF->getFunction().getCallingConv()) && 206*0b57cec5SDimitry Andric usesVertexCache(MI.getOpcode()); 207*0b57cec5SDimitry Andric } 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric bool R600InstrInfo::usesTextureCache(unsigned Opcode) const { 210*0b57cec5SDimitry Andric return (!ST.hasVertexCache() && IS_VTX(get(Opcode))) || IS_TEX(get(Opcode)); 211*0b57cec5SDimitry Andric } 212*0b57cec5SDimitry Andric 213*0b57cec5SDimitry Andric bool R600InstrInfo::usesTextureCache(const MachineInstr &MI) const { 214*0b57cec5SDimitry Andric const MachineFunction *MF = MI.getParent()->getParent(); 215*0b57cec5SDimitry Andric return (AMDGPU::isCompute(MF->getFunction().getCallingConv()) && 216*0b57cec5SDimitry Andric usesVertexCache(MI.getOpcode())) || 217*0b57cec5SDimitry Andric usesTextureCache(MI.getOpcode()); 218*0b57cec5SDimitry Andric } 219*0b57cec5SDimitry Andric 220*0b57cec5SDimitry Andric bool R600InstrInfo::mustBeLastInClause(unsigned Opcode) const { 221*0b57cec5SDimitry Andric switch (Opcode) { 222*0b57cec5SDimitry Andric case R600::KILLGT: 223*0b57cec5SDimitry Andric case R600::GROUP_BARRIER: 224*0b57cec5SDimitry Andric return true; 225*0b57cec5SDimitry Andric default: 226*0b57cec5SDimitry Andric return false; 227*0b57cec5SDimitry Andric } 228*0b57cec5SDimitry Andric } 229*0b57cec5SDimitry Andric 230*0b57cec5SDimitry Andric bool R600InstrInfo::usesAddressRegister(MachineInstr &MI) const { 231*0b57cec5SDimitry Andric return MI.findRegisterUseOperandIdx(R600::AR_X, false, &RI) != -1; 232*0b57cec5SDimitry Andric } 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric bool R600InstrInfo::definesAddressRegister(MachineInstr &MI) const { 235*0b57cec5SDimitry Andric return MI.findRegisterDefOperandIdx(R600::AR_X, false, false, &RI) != -1; 236*0b57cec5SDimitry Andric } 237*0b57cec5SDimitry Andric 238*0b57cec5SDimitry Andric bool R600InstrInfo::readsLDSSrcReg(const MachineInstr &MI) const { 239*0b57cec5SDimitry Andric if (!isALUInstr(MI.getOpcode())) { 240*0b57cec5SDimitry Andric return false; 241*0b57cec5SDimitry Andric } 242*0b57cec5SDimitry Andric for (MachineInstr::const_mop_iterator I = MI.operands_begin(), 243*0b57cec5SDimitry Andric E = MI.operands_end(); 244*0b57cec5SDimitry Andric I != E; ++I) { 245*0b57cec5SDimitry Andric if (!I->isReg() || !I->isUse() || 246*0b57cec5SDimitry Andric TargetRegisterInfo::isVirtualRegister(I->getReg())) 247*0b57cec5SDimitry Andric continue; 248*0b57cec5SDimitry Andric 249*0b57cec5SDimitry Andric if (R600::R600_LDS_SRC_REGRegClass.contains(I->getReg())) 250*0b57cec5SDimitry Andric return true; 251*0b57cec5SDimitry Andric } 252*0b57cec5SDimitry Andric return false; 253*0b57cec5SDimitry Andric } 254*0b57cec5SDimitry Andric 255*0b57cec5SDimitry Andric int R600InstrInfo::getSelIdx(unsigned Opcode, unsigned SrcIdx) const { 256*0b57cec5SDimitry Andric static const unsigned SrcSelTable[][2] = { 257*0b57cec5SDimitry Andric {R600::OpName::src0, R600::OpName::src0_sel}, 258*0b57cec5SDimitry Andric {R600::OpName::src1, R600::OpName::src1_sel}, 259*0b57cec5SDimitry Andric {R600::OpName::src2, R600::OpName::src2_sel}, 260*0b57cec5SDimitry Andric {R600::OpName::src0_X, R600::OpName::src0_sel_X}, 261*0b57cec5SDimitry Andric {R600::OpName::src0_Y, R600::OpName::src0_sel_Y}, 262*0b57cec5SDimitry Andric {R600::OpName::src0_Z, R600::OpName::src0_sel_Z}, 263*0b57cec5SDimitry Andric {R600::OpName::src0_W, R600::OpName::src0_sel_W}, 264*0b57cec5SDimitry Andric {R600::OpName::src1_X, R600::OpName::src1_sel_X}, 265*0b57cec5SDimitry Andric {R600::OpName::src1_Y, R600::OpName::src1_sel_Y}, 266*0b57cec5SDimitry Andric {R600::OpName::src1_Z, R600::OpName::src1_sel_Z}, 267*0b57cec5SDimitry Andric {R600::OpName::src1_W, R600::OpName::src1_sel_W} 268*0b57cec5SDimitry Andric }; 269*0b57cec5SDimitry Andric 270*0b57cec5SDimitry Andric for (const auto &Row : SrcSelTable) { 271*0b57cec5SDimitry Andric if (getOperandIdx(Opcode, Row[0]) == (int)SrcIdx) { 272*0b57cec5SDimitry Andric return getOperandIdx(Opcode, Row[1]); 273*0b57cec5SDimitry Andric } 274*0b57cec5SDimitry Andric } 275*0b57cec5SDimitry Andric return -1; 276*0b57cec5SDimitry Andric } 277*0b57cec5SDimitry Andric 278*0b57cec5SDimitry Andric SmallVector<std::pair<MachineOperand *, int64_t>, 3> 279*0b57cec5SDimitry Andric R600InstrInfo::getSrcs(MachineInstr &MI) const { 280*0b57cec5SDimitry Andric SmallVector<std::pair<MachineOperand *, int64_t>, 3> Result; 281*0b57cec5SDimitry Andric 282*0b57cec5SDimitry Andric if (MI.getOpcode() == R600::DOT_4) { 283*0b57cec5SDimitry Andric static const unsigned OpTable[8][2] = { 284*0b57cec5SDimitry Andric {R600::OpName::src0_X, R600::OpName::src0_sel_X}, 285*0b57cec5SDimitry Andric {R600::OpName::src0_Y, R600::OpName::src0_sel_Y}, 286*0b57cec5SDimitry Andric {R600::OpName::src0_Z, R600::OpName::src0_sel_Z}, 287*0b57cec5SDimitry Andric {R600::OpName::src0_W, R600::OpName::src0_sel_W}, 288*0b57cec5SDimitry Andric {R600::OpName::src1_X, R600::OpName::src1_sel_X}, 289*0b57cec5SDimitry Andric {R600::OpName::src1_Y, R600::OpName::src1_sel_Y}, 290*0b57cec5SDimitry Andric {R600::OpName::src1_Z, R600::OpName::src1_sel_Z}, 291*0b57cec5SDimitry Andric {R600::OpName::src1_W, R600::OpName::src1_sel_W}, 292*0b57cec5SDimitry Andric }; 293*0b57cec5SDimitry Andric 294*0b57cec5SDimitry Andric for (unsigned j = 0; j < 8; j++) { 295*0b57cec5SDimitry Andric MachineOperand &MO = 296*0b57cec5SDimitry Andric MI.getOperand(getOperandIdx(MI.getOpcode(), OpTable[j][0])); 297*0b57cec5SDimitry Andric unsigned Reg = MO.getReg(); 298*0b57cec5SDimitry Andric if (Reg == R600::ALU_CONST) { 299*0b57cec5SDimitry Andric MachineOperand &Sel = 300*0b57cec5SDimitry Andric MI.getOperand(getOperandIdx(MI.getOpcode(), OpTable[j][1])); 301*0b57cec5SDimitry Andric Result.push_back(std::make_pair(&MO, Sel.getImm())); 302*0b57cec5SDimitry Andric continue; 303*0b57cec5SDimitry Andric } 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric } 306*0b57cec5SDimitry Andric return Result; 307*0b57cec5SDimitry Andric } 308*0b57cec5SDimitry Andric 309*0b57cec5SDimitry Andric static const unsigned OpTable[3][2] = { 310*0b57cec5SDimitry Andric {R600::OpName::src0, R600::OpName::src0_sel}, 311*0b57cec5SDimitry Andric {R600::OpName::src1, R600::OpName::src1_sel}, 312*0b57cec5SDimitry Andric {R600::OpName::src2, R600::OpName::src2_sel}, 313*0b57cec5SDimitry Andric }; 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric for (unsigned j = 0; j < 3; j++) { 316*0b57cec5SDimitry Andric int SrcIdx = getOperandIdx(MI.getOpcode(), OpTable[j][0]); 317*0b57cec5SDimitry Andric if (SrcIdx < 0) 318*0b57cec5SDimitry Andric break; 319*0b57cec5SDimitry Andric MachineOperand &MO = MI.getOperand(SrcIdx); 320*0b57cec5SDimitry Andric unsigned Reg = MO.getReg(); 321*0b57cec5SDimitry Andric if (Reg == R600::ALU_CONST) { 322*0b57cec5SDimitry Andric MachineOperand &Sel = 323*0b57cec5SDimitry Andric MI.getOperand(getOperandIdx(MI.getOpcode(), OpTable[j][1])); 324*0b57cec5SDimitry Andric Result.push_back(std::make_pair(&MO, Sel.getImm())); 325*0b57cec5SDimitry Andric continue; 326*0b57cec5SDimitry Andric } 327*0b57cec5SDimitry Andric if (Reg == R600::ALU_LITERAL_X) { 328*0b57cec5SDimitry Andric MachineOperand &Operand = 329*0b57cec5SDimitry Andric MI.getOperand(getOperandIdx(MI.getOpcode(), R600::OpName::literal)); 330*0b57cec5SDimitry Andric if (Operand.isImm()) { 331*0b57cec5SDimitry Andric Result.push_back(std::make_pair(&MO, Operand.getImm())); 332*0b57cec5SDimitry Andric continue; 333*0b57cec5SDimitry Andric } 334*0b57cec5SDimitry Andric assert(Operand.isGlobal()); 335*0b57cec5SDimitry Andric } 336*0b57cec5SDimitry Andric Result.push_back(std::make_pair(&MO, 0)); 337*0b57cec5SDimitry Andric } 338*0b57cec5SDimitry Andric return Result; 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric std::vector<std::pair<int, unsigned>> 342*0b57cec5SDimitry Andric R600InstrInfo::ExtractSrcs(MachineInstr &MI, 343*0b57cec5SDimitry Andric const DenseMap<unsigned, unsigned> &PV, 344*0b57cec5SDimitry Andric unsigned &ConstCount) const { 345*0b57cec5SDimitry Andric ConstCount = 0; 346*0b57cec5SDimitry Andric const std::pair<int, unsigned> DummyPair(-1, 0); 347*0b57cec5SDimitry Andric std::vector<std::pair<int, unsigned>> Result; 348*0b57cec5SDimitry Andric unsigned i = 0; 349*0b57cec5SDimitry Andric for (const auto &Src : getSrcs(MI)) { 350*0b57cec5SDimitry Andric ++i; 351*0b57cec5SDimitry Andric unsigned Reg = Src.first->getReg(); 352*0b57cec5SDimitry Andric int Index = RI.getEncodingValue(Reg) & 0xff; 353*0b57cec5SDimitry Andric if (Reg == R600::OQAP) { 354*0b57cec5SDimitry Andric Result.push_back(std::make_pair(Index, 0U)); 355*0b57cec5SDimitry Andric } 356*0b57cec5SDimitry Andric if (PV.find(Reg) != PV.end()) { 357*0b57cec5SDimitry Andric // 255 is used to tells its a PS/PV reg 358*0b57cec5SDimitry Andric Result.push_back(std::make_pair(255, 0U)); 359*0b57cec5SDimitry Andric continue; 360*0b57cec5SDimitry Andric } 361*0b57cec5SDimitry Andric if (Index > 127) { 362*0b57cec5SDimitry Andric ConstCount++; 363*0b57cec5SDimitry Andric Result.push_back(DummyPair); 364*0b57cec5SDimitry Andric continue; 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric unsigned Chan = RI.getHWRegChan(Reg); 367*0b57cec5SDimitry Andric Result.push_back(std::make_pair(Index, Chan)); 368*0b57cec5SDimitry Andric } 369*0b57cec5SDimitry Andric for (; i < 3; ++i) 370*0b57cec5SDimitry Andric Result.push_back(DummyPair); 371*0b57cec5SDimitry Andric return Result; 372*0b57cec5SDimitry Andric } 373*0b57cec5SDimitry Andric 374*0b57cec5SDimitry Andric static std::vector<std::pair<int, unsigned>> 375*0b57cec5SDimitry Andric Swizzle(std::vector<std::pair<int, unsigned>> Src, 376*0b57cec5SDimitry Andric R600InstrInfo::BankSwizzle Swz) { 377*0b57cec5SDimitry Andric if (Src[0] == Src[1]) 378*0b57cec5SDimitry Andric Src[1].first = -1; 379*0b57cec5SDimitry Andric switch (Swz) { 380*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_012_SCL_210: 381*0b57cec5SDimitry Andric break; 382*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_021_SCL_122: 383*0b57cec5SDimitry Andric std::swap(Src[1], Src[2]); 384*0b57cec5SDimitry Andric break; 385*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_102_SCL_221: 386*0b57cec5SDimitry Andric std::swap(Src[0], Src[1]); 387*0b57cec5SDimitry Andric break; 388*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_120_SCL_212: 389*0b57cec5SDimitry Andric std::swap(Src[0], Src[1]); 390*0b57cec5SDimitry Andric std::swap(Src[0], Src[2]); 391*0b57cec5SDimitry Andric break; 392*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_201: 393*0b57cec5SDimitry Andric std::swap(Src[0], Src[2]); 394*0b57cec5SDimitry Andric std::swap(Src[0], Src[1]); 395*0b57cec5SDimitry Andric break; 396*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_210: 397*0b57cec5SDimitry Andric std::swap(Src[0], Src[2]); 398*0b57cec5SDimitry Andric break; 399*0b57cec5SDimitry Andric } 400*0b57cec5SDimitry Andric return Src; 401*0b57cec5SDimitry Andric } 402*0b57cec5SDimitry Andric 403*0b57cec5SDimitry Andric static unsigned getTransSwizzle(R600InstrInfo::BankSwizzle Swz, unsigned Op) { 404*0b57cec5SDimitry Andric assert(Op < 3 && "Out of range swizzle index"); 405*0b57cec5SDimitry Andric switch (Swz) { 406*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_012_SCL_210: { 407*0b57cec5SDimitry Andric unsigned Cycles[3] = { 2, 1, 0}; 408*0b57cec5SDimitry Andric return Cycles[Op]; 409*0b57cec5SDimitry Andric } 410*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_021_SCL_122: { 411*0b57cec5SDimitry Andric unsigned Cycles[3] = { 1, 2, 2}; 412*0b57cec5SDimitry Andric return Cycles[Op]; 413*0b57cec5SDimitry Andric } 414*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_120_SCL_212: { 415*0b57cec5SDimitry Andric unsigned Cycles[3] = { 2, 1, 2}; 416*0b57cec5SDimitry Andric return Cycles[Op]; 417*0b57cec5SDimitry Andric } 418*0b57cec5SDimitry Andric case R600InstrInfo::ALU_VEC_102_SCL_221: { 419*0b57cec5SDimitry Andric unsigned Cycles[3] = { 2, 2, 1}; 420*0b57cec5SDimitry Andric return Cycles[Op]; 421*0b57cec5SDimitry Andric } 422*0b57cec5SDimitry Andric default: 423*0b57cec5SDimitry Andric llvm_unreachable("Wrong Swizzle for Trans Slot"); 424*0b57cec5SDimitry Andric } 425*0b57cec5SDimitry Andric } 426*0b57cec5SDimitry Andric 427*0b57cec5SDimitry Andric /// returns how many MIs (whose inputs are represented by IGSrcs) can be packed 428*0b57cec5SDimitry Andric /// in the same Instruction Group while meeting read port limitations given a 429*0b57cec5SDimitry Andric /// Swz swizzle sequence. 430*0b57cec5SDimitry Andric unsigned R600InstrInfo::isLegalUpTo( 431*0b57cec5SDimitry Andric const std::vector<std::vector<std::pair<int, unsigned>>> &IGSrcs, 432*0b57cec5SDimitry Andric const std::vector<R600InstrInfo::BankSwizzle> &Swz, 433*0b57cec5SDimitry Andric const std::vector<std::pair<int, unsigned>> &TransSrcs, 434*0b57cec5SDimitry Andric R600InstrInfo::BankSwizzle TransSwz) const { 435*0b57cec5SDimitry Andric int Vector[4][3]; 436*0b57cec5SDimitry Andric memset(Vector, -1, sizeof(Vector)); 437*0b57cec5SDimitry Andric for (unsigned i = 0, e = IGSrcs.size(); i < e; i++) { 438*0b57cec5SDimitry Andric const std::vector<std::pair<int, unsigned>> &Srcs = 439*0b57cec5SDimitry Andric Swizzle(IGSrcs[i], Swz[i]); 440*0b57cec5SDimitry Andric for (unsigned j = 0; j < 3; j++) { 441*0b57cec5SDimitry Andric const std::pair<int, unsigned> &Src = Srcs[j]; 442*0b57cec5SDimitry Andric if (Src.first < 0 || Src.first == 255) 443*0b57cec5SDimitry Andric continue; 444*0b57cec5SDimitry Andric if (Src.first == GET_REG_INDEX(RI.getEncodingValue(R600::OQAP))) { 445*0b57cec5SDimitry Andric if (Swz[i] != R600InstrInfo::ALU_VEC_012_SCL_210 && 446*0b57cec5SDimitry Andric Swz[i] != R600InstrInfo::ALU_VEC_021_SCL_122) { 447*0b57cec5SDimitry Andric // The value from output queue A (denoted by register OQAP) can 448*0b57cec5SDimitry Andric // only be fetched during the first cycle. 449*0b57cec5SDimitry Andric return false; 450*0b57cec5SDimitry Andric } 451*0b57cec5SDimitry Andric // OQAP does not count towards the normal read port restrictions 452*0b57cec5SDimitry Andric continue; 453*0b57cec5SDimitry Andric } 454*0b57cec5SDimitry Andric if (Vector[Src.second][j] < 0) 455*0b57cec5SDimitry Andric Vector[Src.second][j] = Src.first; 456*0b57cec5SDimitry Andric if (Vector[Src.second][j] != Src.first) 457*0b57cec5SDimitry Andric return i; 458*0b57cec5SDimitry Andric } 459*0b57cec5SDimitry Andric } 460*0b57cec5SDimitry Andric // Now check Trans Alu 461*0b57cec5SDimitry Andric for (unsigned i = 0, e = TransSrcs.size(); i < e; ++i) { 462*0b57cec5SDimitry Andric const std::pair<int, unsigned> &Src = TransSrcs[i]; 463*0b57cec5SDimitry Andric unsigned Cycle = getTransSwizzle(TransSwz, i); 464*0b57cec5SDimitry Andric if (Src.first < 0) 465*0b57cec5SDimitry Andric continue; 466*0b57cec5SDimitry Andric if (Src.first == 255) 467*0b57cec5SDimitry Andric continue; 468*0b57cec5SDimitry Andric if (Vector[Src.second][Cycle] < 0) 469*0b57cec5SDimitry Andric Vector[Src.second][Cycle] = Src.first; 470*0b57cec5SDimitry Andric if (Vector[Src.second][Cycle] != Src.first) 471*0b57cec5SDimitry Andric return IGSrcs.size() - 1; 472*0b57cec5SDimitry Andric } 473*0b57cec5SDimitry Andric return IGSrcs.size(); 474*0b57cec5SDimitry Andric } 475*0b57cec5SDimitry Andric 476*0b57cec5SDimitry Andric /// Given a swizzle sequence SwzCandidate and an index Idx, returns the next 477*0b57cec5SDimitry Andric /// (in lexicographic term) swizzle sequence assuming that all swizzles after 478*0b57cec5SDimitry Andric /// Idx can be skipped 479*0b57cec5SDimitry Andric static bool 480*0b57cec5SDimitry Andric NextPossibleSolution( 481*0b57cec5SDimitry Andric std::vector<R600InstrInfo::BankSwizzle> &SwzCandidate, 482*0b57cec5SDimitry Andric unsigned Idx) { 483*0b57cec5SDimitry Andric assert(Idx < SwzCandidate.size()); 484*0b57cec5SDimitry Andric int ResetIdx = Idx; 485*0b57cec5SDimitry Andric while (ResetIdx > -1 && SwzCandidate[ResetIdx] == R600InstrInfo::ALU_VEC_210) 486*0b57cec5SDimitry Andric ResetIdx --; 487*0b57cec5SDimitry Andric for (unsigned i = ResetIdx + 1, e = SwzCandidate.size(); i < e; i++) { 488*0b57cec5SDimitry Andric SwzCandidate[i] = R600InstrInfo::ALU_VEC_012_SCL_210; 489*0b57cec5SDimitry Andric } 490*0b57cec5SDimitry Andric if (ResetIdx == -1) 491*0b57cec5SDimitry Andric return false; 492*0b57cec5SDimitry Andric int NextSwizzle = SwzCandidate[ResetIdx] + 1; 493*0b57cec5SDimitry Andric SwzCandidate[ResetIdx] = (R600InstrInfo::BankSwizzle)NextSwizzle; 494*0b57cec5SDimitry Andric return true; 495*0b57cec5SDimitry Andric } 496*0b57cec5SDimitry Andric 497*0b57cec5SDimitry Andric /// Enumerate all possible Swizzle sequence to find one that can meet all 498*0b57cec5SDimitry Andric /// read port requirements. 499*0b57cec5SDimitry Andric bool R600InstrInfo::FindSwizzleForVectorSlot( 500*0b57cec5SDimitry Andric const std::vector<std::vector<std::pair<int, unsigned>>> &IGSrcs, 501*0b57cec5SDimitry Andric std::vector<R600InstrInfo::BankSwizzle> &SwzCandidate, 502*0b57cec5SDimitry Andric const std::vector<std::pair<int, unsigned>> &TransSrcs, 503*0b57cec5SDimitry Andric R600InstrInfo::BankSwizzle TransSwz) const { 504*0b57cec5SDimitry Andric unsigned ValidUpTo = 0; 505*0b57cec5SDimitry Andric do { 506*0b57cec5SDimitry Andric ValidUpTo = isLegalUpTo(IGSrcs, SwzCandidate, TransSrcs, TransSwz); 507*0b57cec5SDimitry Andric if (ValidUpTo == IGSrcs.size()) 508*0b57cec5SDimitry Andric return true; 509*0b57cec5SDimitry Andric } while (NextPossibleSolution(SwzCandidate, ValidUpTo)); 510*0b57cec5SDimitry Andric return false; 511*0b57cec5SDimitry Andric } 512*0b57cec5SDimitry Andric 513*0b57cec5SDimitry Andric /// Instructions in Trans slot can't read gpr at cycle 0 if they also read 514*0b57cec5SDimitry Andric /// a const, and can't read a gpr at cycle 1 if they read 2 const. 515*0b57cec5SDimitry Andric static bool 516*0b57cec5SDimitry Andric isConstCompatible(R600InstrInfo::BankSwizzle TransSwz, 517*0b57cec5SDimitry Andric const std::vector<std::pair<int, unsigned>> &TransOps, 518*0b57cec5SDimitry Andric unsigned ConstCount) { 519*0b57cec5SDimitry Andric // TransALU can't read 3 constants 520*0b57cec5SDimitry Andric if (ConstCount > 2) 521*0b57cec5SDimitry Andric return false; 522*0b57cec5SDimitry Andric for (unsigned i = 0, e = TransOps.size(); i < e; ++i) { 523*0b57cec5SDimitry Andric const std::pair<int, unsigned> &Src = TransOps[i]; 524*0b57cec5SDimitry Andric unsigned Cycle = getTransSwizzle(TransSwz, i); 525*0b57cec5SDimitry Andric if (Src.first < 0) 526*0b57cec5SDimitry Andric continue; 527*0b57cec5SDimitry Andric if (ConstCount > 0 && Cycle == 0) 528*0b57cec5SDimitry Andric return false; 529*0b57cec5SDimitry Andric if (ConstCount > 1 && Cycle == 1) 530*0b57cec5SDimitry Andric return false; 531*0b57cec5SDimitry Andric } 532*0b57cec5SDimitry Andric return true; 533*0b57cec5SDimitry Andric } 534*0b57cec5SDimitry Andric 535*0b57cec5SDimitry Andric bool 536*0b57cec5SDimitry Andric R600InstrInfo::fitsReadPortLimitations(const std::vector<MachineInstr *> &IG, 537*0b57cec5SDimitry Andric const DenseMap<unsigned, unsigned> &PV, 538*0b57cec5SDimitry Andric std::vector<BankSwizzle> &ValidSwizzle, 539*0b57cec5SDimitry Andric bool isLastAluTrans) 540*0b57cec5SDimitry Andric const { 541*0b57cec5SDimitry Andric //Todo : support shared src0 - src1 operand 542*0b57cec5SDimitry Andric 543*0b57cec5SDimitry Andric std::vector<std::vector<std::pair<int, unsigned>>> IGSrcs; 544*0b57cec5SDimitry Andric ValidSwizzle.clear(); 545*0b57cec5SDimitry Andric unsigned ConstCount; 546*0b57cec5SDimitry Andric BankSwizzle TransBS = ALU_VEC_012_SCL_210; 547*0b57cec5SDimitry Andric for (unsigned i = 0, e = IG.size(); i < e; ++i) { 548*0b57cec5SDimitry Andric IGSrcs.push_back(ExtractSrcs(*IG[i], PV, ConstCount)); 549*0b57cec5SDimitry Andric unsigned Op = getOperandIdx(IG[i]->getOpcode(), 550*0b57cec5SDimitry Andric R600::OpName::bank_swizzle); 551*0b57cec5SDimitry Andric ValidSwizzle.push_back( (R600InstrInfo::BankSwizzle) 552*0b57cec5SDimitry Andric IG[i]->getOperand(Op).getImm()); 553*0b57cec5SDimitry Andric } 554*0b57cec5SDimitry Andric std::vector<std::pair<int, unsigned>> TransOps; 555*0b57cec5SDimitry Andric if (!isLastAluTrans) 556*0b57cec5SDimitry Andric return FindSwizzleForVectorSlot(IGSrcs, ValidSwizzle, TransOps, TransBS); 557*0b57cec5SDimitry Andric 558*0b57cec5SDimitry Andric TransOps = std::move(IGSrcs.back()); 559*0b57cec5SDimitry Andric IGSrcs.pop_back(); 560*0b57cec5SDimitry Andric ValidSwizzle.pop_back(); 561*0b57cec5SDimitry Andric 562*0b57cec5SDimitry Andric static const R600InstrInfo::BankSwizzle TransSwz[] = { 563*0b57cec5SDimitry Andric ALU_VEC_012_SCL_210, 564*0b57cec5SDimitry Andric ALU_VEC_021_SCL_122, 565*0b57cec5SDimitry Andric ALU_VEC_120_SCL_212, 566*0b57cec5SDimitry Andric ALU_VEC_102_SCL_221 567*0b57cec5SDimitry Andric }; 568*0b57cec5SDimitry Andric for (unsigned i = 0; i < 4; i++) { 569*0b57cec5SDimitry Andric TransBS = TransSwz[i]; 570*0b57cec5SDimitry Andric if (!isConstCompatible(TransBS, TransOps, ConstCount)) 571*0b57cec5SDimitry Andric continue; 572*0b57cec5SDimitry Andric bool Result = FindSwizzleForVectorSlot(IGSrcs, ValidSwizzle, TransOps, 573*0b57cec5SDimitry Andric TransBS); 574*0b57cec5SDimitry Andric if (Result) { 575*0b57cec5SDimitry Andric ValidSwizzle.push_back(TransBS); 576*0b57cec5SDimitry Andric return true; 577*0b57cec5SDimitry Andric } 578*0b57cec5SDimitry Andric } 579*0b57cec5SDimitry Andric 580*0b57cec5SDimitry Andric return false; 581*0b57cec5SDimitry Andric } 582*0b57cec5SDimitry Andric 583*0b57cec5SDimitry Andric bool 584*0b57cec5SDimitry Andric R600InstrInfo::fitsConstReadLimitations(const std::vector<unsigned> &Consts) 585*0b57cec5SDimitry Andric const { 586*0b57cec5SDimitry Andric assert (Consts.size() <= 12 && "Too many operands in instructions group"); 587*0b57cec5SDimitry Andric unsigned Pair1 = 0, Pair2 = 0; 588*0b57cec5SDimitry Andric for (unsigned i = 0, n = Consts.size(); i < n; ++i) { 589*0b57cec5SDimitry Andric unsigned ReadConstHalf = Consts[i] & 2; 590*0b57cec5SDimitry Andric unsigned ReadConstIndex = Consts[i] & (~3); 591*0b57cec5SDimitry Andric unsigned ReadHalfConst = ReadConstIndex | ReadConstHalf; 592*0b57cec5SDimitry Andric if (!Pair1) { 593*0b57cec5SDimitry Andric Pair1 = ReadHalfConst; 594*0b57cec5SDimitry Andric continue; 595*0b57cec5SDimitry Andric } 596*0b57cec5SDimitry Andric if (Pair1 == ReadHalfConst) 597*0b57cec5SDimitry Andric continue; 598*0b57cec5SDimitry Andric if (!Pair2) { 599*0b57cec5SDimitry Andric Pair2 = ReadHalfConst; 600*0b57cec5SDimitry Andric continue; 601*0b57cec5SDimitry Andric } 602*0b57cec5SDimitry Andric if (Pair2 != ReadHalfConst) 603*0b57cec5SDimitry Andric return false; 604*0b57cec5SDimitry Andric } 605*0b57cec5SDimitry Andric return true; 606*0b57cec5SDimitry Andric } 607*0b57cec5SDimitry Andric 608*0b57cec5SDimitry Andric bool 609*0b57cec5SDimitry Andric R600InstrInfo::fitsConstReadLimitations(const std::vector<MachineInstr *> &MIs) 610*0b57cec5SDimitry Andric const { 611*0b57cec5SDimitry Andric std::vector<unsigned> Consts; 612*0b57cec5SDimitry Andric SmallSet<int64_t, 4> Literals; 613*0b57cec5SDimitry Andric for (unsigned i = 0, n = MIs.size(); i < n; i++) { 614*0b57cec5SDimitry Andric MachineInstr &MI = *MIs[i]; 615*0b57cec5SDimitry Andric if (!isALUInstr(MI.getOpcode())) 616*0b57cec5SDimitry Andric continue; 617*0b57cec5SDimitry Andric 618*0b57cec5SDimitry Andric for (const auto &Src : getSrcs(MI)) { 619*0b57cec5SDimitry Andric if (Src.first->getReg() == R600::ALU_LITERAL_X) 620*0b57cec5SDimitry Andric Literals.insert(Src.second); 621*0b57cec5SDimitry Andric if (Literals.size() > 4) 622*0b57cec5SDimitry Andric return false; 623*0b57cec5SDimitry Andric if (Src.first->getReg() == R600::ALU_CONST) 624*0b57cec5SDimitry Andric Consts.push_back(Src.second); 625*0b57cec5SDimitry Andric if (R600::R600_KC0RegClass.contains(Src.first->getReg()) || 626*0b57cec5SDimitry Andric R600::R600_KC1RegClass.contains(Src.first->getReg())) { 627*0b57cec5SDimitry Andric unsigned Index = RI.getEncodingValue(Src.first->getReg()) & 0xff; 628*0b57cec5SDimitry Andric unsigned Chan = RI.getHWRegChan(Src.first->getReg()); 629*0b57cec5SDimitry Andric Consts.push_back((Index << 2) | Chan); 630*0b57cec5SDimitry Andric } 631*0b57cec5SDimitry Andric } 632*0b57cec5SDimitry Andric } 633*0b57cec5SDimitry Andric return fitsConstReadLimitations(Consts); 634*0b57cec5SDimitry Andric } 635*0b57cec5SDimitry Andric 636*0b57cec5SDimitry Andric DFAPacketizer * 637*0b57cec5SDimitry Andric R600InstrInfo::CreateTargetScheduleState(const TargetSubtargetInfo &STI) const { 638*0b57cec5SDimitry Andric const InstrItineraryData *II = STI.getInstrItineraryData(); 639*0b57cec5SDimitry Andric return static_cast<const R600Subtarget &>(STI).createDFAPacketizer(II); 640*0b57cec5SDimitry Andric } 641*0b57cec5SDimitry Andric 642*0b57cec5SDimitry Andric static bool 643*0b57cec5SDimitry Andric isPredicateSetter(unsigned Opcode) { 644*0b57cec5SDimitry Andric switch (Opcode) { 645*0b57cec5SDimitry Andric case R600::PRED_X: 646*0b57cec5SDimitry Andric return true; 647*0b57cec5SDimitry Andric default: 648*0b57cec5SDimitry Andric return false; 649*0b57cec5SDimitry Andric } 650*0b57cec5SDimitry Andric } 651*0b57cec5SDimitry Andric 652*0b57cec5SDimitry Andric static MachineInstr * 653*0b57cec5SDimitry Andric findFirstPredicateSetterFrom(MachineBasicBlock &MBB, 654*0b57cec5SDimitry Andric MachineBasicBlock::iterator I) { 655*0b57cec5SDimitry Andric while (I != MBB.begin()) { 656*0b57cec5SDimitry Andric --I; 657*0b57cec5SDimitry Andric MachineInstr &MI = *I; 658*0b57cec5SDimitry Andric if (isPredicateSetter(MI.getOpcode())) 659*0b57cec5SDimitry Andric return &MI; 660*0b57cec5SDimitry Andric } 661*0b57cec5SDimitry Andric 662*0b57cec5SDimitry Andric return nullptr; 663*0b57cec5SDimitry Andric } 664*0b57cec5SDimitry Andric 665*0b57cec5SDimitry Andric static 666*0b57cec5SDimitry Andric bool isJump(unsigned Opcode) { 667*0b57cec5SDimitry Andric return Opcode == R600::JUMP || Opcode == R600::JUMP_COND; 668*0b57cec5SDimitry Andric } 669*0b57cec5SDimitry Andric 670*0b57cec5SDimitry Andric static bool isBranch(unsigned Opcode) { 671*0b57cec5SDimitry Andric return Opcode == R600::BRANCH || Opcode == R600::BRANCH_COND_i32 || 672*0b57cec5SDimitry Andric Opcode == R600::BRANCH_COND_f32; 673*0b57cec5SDimitry Andric } 674*0b57cec5SDimitry Andric 675*0b57cec5SDimitry Andric bool R600InstrInfo::analyzeBranch(MachineBasicBlock &MBB, 676*0b57cec5SDimitry Andric MachineBasicBlock *&TBB, 677*0b57cec5SDimitry Andric MachineBasicBlock *&FBB, 678*0b57cec5SDimitry Andric SmallVectorImpl<MachineOperand> &Cond, 679*0b57cec5SDimitry Andric bool AllowModify) const { 680*0b57cec5SDimitry Andric // Most of the following comes from the ARM implementation of AnalyzeBranch 681*0b57cec5SDimitry Andric 682*0b57cec5SDimitry Andric // If the block has no terminators, it just falls into the block after it. 683*0b57cec5SDimitry Andric MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); 684*0b57cec5SDimitry Andric if (I == MBB.end()) 685*0b57cec5SDimitry Andric return false; 686*0b57cec5SDimitry Andric 687*0b57cec5SDimitry Andric // R600::BRANCH* instructions are only available after isel and are not 688*0b57cec5SDimitry Andric // handled 689*0b57cec5SDimitry Andric if (isBranch(I->getOpcode())) 690*0b57cec5SDimitry Andric return true; 691*0b57cec5SDimitry Andric if (!isJump(I->getOpcode())) { 692*0b57cec5SDimitry Andric return false; 693*0b57cec5SDimitry Andric } 694*0b57cec5SDimitry Andric 695*0b57cec5SDimitry Andric // Remove successive JUMP 696*0b57cec5SDimitry Andric while (I != MBB.begin() && std::prev(I)->getOpcode() == R600::JUMP) { 697*0b57cec5SDimitry Andric MachineBasicBlock::iterator PriorI = std::prev(I); 698*0b57cec5SDimitry Andric if (AllowModify) 699*0b57cec5SDimitry Andric I->removeFromParent(); 700*0b57cec5SDimitry Andric I = PriorI; 701*0b57cec5SDimitry Andric } 702*0b57cec5SDimitry Andric MachineInstr &LastInst = *I; 703*0b57cec5SDimitry Andric 704*0b57cec5SDimitry Andric // If there is only one terminator instruction, process it. 705*0b57cec5SDimitry Andric unsigned LastOpc = LastInst.getOpcode(); 706*0b57cec5SDimitry Andric if (I == MBB.begin() || !isJump((--I)->getOpcode())) { 707*0b57cec5SDimitry Andric if (LastOpc == R600::JUMP) { 708*0b57cec5SDimitry Andric TBB = LastInst.getOperand(0).getMBB(); 709*0b57cec5SDimitry Andric return false; 710*0b57cec5SDimitry Andric } else if (LastOpc == R600::JUMP_COND) { 711*0b57cec5SDimitry Andric auto predSet = I; 712*0b57cec5SDimitry Andric while (!isPredicateSetter(predSet->getOpcode())) { 713*0b57cec5SDimitry Andric predSet = --I; 714*0b57cec5SDimitry Andric } 715*0b57cec5SDimitry Andric TBB = LastInst.getOperand(0).getMBB(); 716*0b57cec5SDimitry Andric Cond.push_back(predSet->getOperand(1)); 717*0b57cec5SDimitry Andric Cond.push_back(predSet->getOperand(2)); 718*0b57cec5SDimitry Andric Cond.push_back(MachineOperand::CreateReg(R600::PRED_SEL_ONE, false)); 719*0b57cec5SDimitry Andric return false; 720*0b57cec5SDimitry Andric } 721*0b57cec5SDimitry Andric return true; // Can't handle indirect branch. 722*0b57cec5SDimitry Andric } 723*0b57cec5SDimitry Andric 724*0b57cec5SDimitry Andric // Get the instruction before it if it is a terminator. 725*0b57cec5SDimitry Andric MachineInstr &SecondLastInst = *I; 726*0b57cec5SDimitry Andric unsigned SecondLastOpc = SecondLastInst.getOpcode(); 727*0b57cec5SDimitry Andric 728*0b57cec5SDimitry Andric // If the block ends with a B and a Bcc, handle it. 729*0b57cec5SDimitry Andric if (SecondLastOpc == R600::JUMP_COND && LastOpc == R600::JUMP) { 730*0b57cec5SDimitry Andric auto predSet = --I; 731*0b57cec5SDimitry Andric while (!isPredicateSetter(predSet->getOpcode())) { 732*0b57cec5SDimitry Andric predSet = --I; 733*0b57cec5SDimitry Andric } 734*0b57cec5SDimitry Andric TBB = SecondLastInst.getOperand(0).getMBB(); 735*0b57cec5SDimitry Andric FBB = LastInst.getOperand(0).getMBB(); 736*0b57cec5SDimitry Andric Cond.push_back(predSet->getOperand(1)); 737*0b57cec5SDimitry Andric Cond.push_back(predSet->getOperand(2)); 738*0b57cec5SDimitry Andric Cond.push_back(MachineOperand::CreateReg(R600::PRED_SEL_ONE, false)); 739*0b57cec5SDimitry Andric return false; 740*0b57cec5SDimitry Andric } 741*0b57cec5SDimitry Andric 742*0b57cec5SDimitry Andric // Otherwise, can't handle this. 743*0b57cec5SDimitry Andric return true; 744*0b57cec5SDimitry Andric } 745*0b57cec5SDimitry Andric 746*0b57cec5SDimitry Andric static 747*0b57cec5SDimitry Andric MachineBasicBlock::iterator FindLastAluClause(MachineBasicBlock &MBB) { 748*0b57cec5SDimitry Andric for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend(); 749*0b57cec5SDimitry Andric It != E; ++It) { 750*0b57cec5SDimitry Andric if (It->getOpcode() == R600::CF_ALU || 751*0b57cec5SDimitry Andric It->getOpcode() == R600::CF_ALU_PUSH_BEFORE) 752*0b57cec5SDimitry Andric return It.getReverse(); 753*0b57cec5SDimitry Andric } 754*0b57cec5SDimitry Andric return MBB.end(); 755*0b57cec5SDimitry Andric } 756*0b57cec5SDimitry Andric 757*0b57cec5SDimitry Andric unsigned R600InstrInfo::insertBranch(MachineBasicBlock &MBB, 758*0b57cec5SDimitry Andric MachineBasicBlock *TBB, 759*0b57cec5SDimitry Andric MachineBasicBlock *FBB, 760*0b57cec5SDimitry Andric ArrayRef<MachineOperand> Cond, 761*0b57cec5SDimitry Andric const DebugLoc &DL, 762*0b57cec5SDimitry Andric int *BytesAdded) const { 763*0b57cec5SDimitry Andric assert(TBB && "insertBranch must not be told to insert a fallthrough"); 764*0b57cec5SDimitry Andric assert(!BytesAdded && "code size not handled"); 765*0b57cec5SDimitry Andric 766*0b57cec5SDimitry Andric if (!FBB) { 767*0b57cec5SDimitry Andric if (Cond.empty()) { 768*0b57cec5SDimitry Andric BuildMI(&MBB, DL, get(R600::JUMP)).addMBB(TBB); 769*0b57cec5SDimitry Andric return 1; 770*0b57cec5SDimitry Andric } else { 771*0b57cec5SDimitry Andric MachineInstr *PredSet = findFirstPredicateSetterFrom(MBB, MBB.end()); 772*0b57cec5SDimitry Andric assert(PredSet && "No previous predicate !"); 773*0b57cec5SDimitry Andric addFlag(*PredSet, 0, MO_FLAG_PUSH); 774*0b57cec5SDimitry Andric PredSet->getOperand(2).setImm(Cond[1].getImm()); 775*0b57cec5SDimitry Andric 776*0b57cec5SDimitry Andric BuildMI(&MBB, DL, get(R600::JUMP_COND)) 777*0b57cec5SDimitry Andric .addMBB(TBB) 778*0b57cec5SDimitry Andric .addReg(R600::PREDICATE_BIT, RegState::Kill); 779*0b57cec5SDimitry Andric MachineBasicBlock::iterator CfAlu = FindLastAluClause(MBB); 780*0b57cec5SDimitry Andric if (CfAlu == MBB.end()) 781*0b57cec5SDimitry Andric return 1; 782*0b57cec5SDimitry Andric assert (CfAlu->getOpcode() == R600::CF_ALU); 783*0b57cec5SDimitry Andric CfAlu->setDesc(get(R600::CF_ALU_PUSH_BEFORE)); 784*0b57cec5SDimitry Andric return 1; 785*0b57cec5SDimitry Andric } 786*0b57cec5SDimitry Andric } else { 787*0b57cec5SDimitry Andric MachineInstr *PredSet = findFirstPredicateSetterFrom(MBB, MBB.end()); 788*0b57cec5SDimitry Andric assert(PredSet && "No previous predicate !"); 789*0b57cec5SDimitry Andric addFlag(*PredSet, 0, MO_FLAG_PUSH); 790*0b57cec5SDimitry Andric PredSet->getOperand(2).setImm(Cond[1].getImm()); 791*0b57cec5SDimitry Andric BuildMI(&MBB, DL, get(R600::JUMP_COND)) 792*0b57cec5SDimitry Andric .addMBB(TBB) 793*0b57cec5SDimitry Andric .addReg(R600::PREDICATE_BIT, RegState::Kill); 794*0b57cec5SDimitry Andric BuildMI(&MBB, DL, get(R600::JUMP)).addMBB(FBB); 795*0b57cec5SDimitry Andric MachineBasicBlock::iterator CfAlu = FindLastAluClause(MBB); 796*0b57cec5SDimitry Andric if (CfAlu == MBB.end()) 797*0b57cec5SDimitry Andric return 2; 798*0b57cec5SDimitry Andric assert (CfAlu->getOpcode() == R600::CF_ALU); 799*0b57cec5SDimitry Andric CfAlu->setDesc(get(R600::CF_ALU_PUSH_BEFORE)); 800*0b57cec5SDimitry Andric return 2; 801*0b57cec5SDimitry Andric } 802*0b57cec5SDimitry Andric } 803*0b57cec5SDimitry Andric 804*0b57cec5SDimitry Andric unsigned R600InstrInfo::removeBranch(MachineBasicBlock &MBB, 805*0b57cec5SDimitry Andric int *BytesRemoved) const { 806*0b57cec5SDimitry Andric assert(!BytesRemoved && "code size not handled"); 807*0b57cec5SDimitry Andric 808*0b57cec5SDimitry Andric // Note : we leave PRED* instructions there. 809*0b57cec5SDimitry Andric // They may be needed when predicating instructions. 810*0b57cec5SDimitry Andric 811*0b57cec5SDimitry Andric MachineBasicBlock::iterator I = MBB.end(); 812*0b57cec5SDimitry Andric 813*0b57cec5SDimitry Andric if (I == MBB.begin()) { 814*0b57cec5SDimitry Andric return 0; 815*0b57cec5SDimitry Andric } 816*0b57cec5SDimitry Andric --I; 817*0b57cec5SDimitry Andric switch (I->getOpcode()) { 818*0b57cec5SDimitry Andric default: 819*0b57cec5SDimitry Andric return 0; 820*0b57cec5SDimitry Andric case R600::JUMP_COND: { 821*0b57cec5SDimitry Andric MachineInstr *predSet = findFirstPredicateSetterFrom(MBB, I); 822*0b57cec5SDimitry Andric clearFlag(*predSet, 0, MO_FLAG_PUSH); 823*0b57cec5SDimitry Andric I->eraseFromParent(); 824*0b57cec5SDimitry Andric MachineBasicBlock::iterator CfAlu = FindLastAluClause(MBB); 825*0b57cec5SDimitry Andric if (CfAlu == MBB.end()) 826*0b57cec5SDimitry Andric break; 827*0b57cec5SDimitry Andric assert (CfAlu->getOpcode() == R600::CF_ALU_PUSH_BEFORE); 828*0b57cec5SDimitry Andric CfAlu->setDesc(get(R600::CF_ALU)); 829*0b57cec5SDimitry Andric break; 830*0b57cec5SDimitry Andric } 831*0b57cec5SDimitry Andric case R600::JUMP: 832*0b57cec5SDimitry Andric I->eraseFromParent(); 833*0b57cec5SDimitry Andric break; 834*0b57cec5SDimitry Andric } 835*0b57cec5SDimitry Andric I = MBB.end(); 836*0b57cec5SDimitry Andric 837*0b57cec5SDimitry Andric if (I == MBB.begin()) { 838*0b57cec5SDimitry Andric return 1; 839*0b57cec5SDimitry Andric } 840*0b57cec5SDimitry Andric --I; 841*0b57cec5SDimitry Andric switch (I->getOpcode()) { 842*0b57cec5SDimitry Andric // FIXME: only one case?? 843*0b57cec5SDimitry Andric default: 844*0b57cec5SDimitry Andric return 1; 845*0b57cec5SDimitry Andric case R600::JUMP_COND: { 846*0b57cec5SDimitry Andric MachineInstr *predSet = findFirstPredicateSetterFrom(MBB, I); 847*0b57cec5SDimitry Andric clearFlag(*predSet, 0, MO_FLAG_PUSH); 848*0b57cec5SDimitry Andric I->eraseFromParent(); 849*0b57cec5SDimitry Andric MachineBasicBlock::iterator CfAlu = FindLastAluClause(MBB); 850*0b57cec5SDimitry Andric if (CfAlu == MBB.end()) 851*0b57cec5SDimitry Andric break; 852*0b57cec5SDimitry Andric assert (CfAlu->getOpcode() == R600::CF_ALU_PUSH_BEFORE); 853*0b57cec5SDimitry Andric CfAlu->setDesc(get(R600::CF_ALU)); 854*0b57cec5SDimitry Andric break; 855*0b57cec5SDimitry Andric } 856*0b57cec5SDimitry Andric case R600::JUMP: 857*0b57cec5SDimitry Andric I->eraseFromParent(); 858*0b57cec5SDimitry Andric break; 859*0b57cec5SDimitry Andric } 860*0b57cec5SDimitry Andric return 2; 861*0b57cec5SDimitry Andric } 862*0b57cec5SDimitry Andric 863*0b57cec5SDimitry Andric bool R600InstrInfo::isPredicated(const MachineInstr &MI) const { 864*0b57cec5SDimitry Andric int idx = MI.findFirstPredOperandIdx(); 865*0b57cec5SDimitry Andric if (idx < 0) 866*0b57cec5SDimitry Andric return false; 867*0b57cec5SDimitry Andric 868*0b57cec5SDimitry Andric unsigned Reg = MI.getOperand(idx).getReg(); 869*0b57cec5SDimitry Andric switch (Reg) { 870*0b57cec5SDimitry Andric default: return false; 871*0b57cec5SDimitry Andric case R600::PRED_SEL_ONE: 872*0b57cec5SDimitry Andric case R600::PRED_SEL_ZERO: 873*0b57cec5SDimitry Andric case R600::PREDICATE_BIT: 874*0b57cec5SDimitry Andric return true; 875*0b57cec5SDimitry Andric } 876*0b57cec5SDimitry Andric } 877*0b57cec5SDimitry Andric 878*0b57cec5SDimitry Andric bool R600InstrInfo::isPredicable(const MachineInstr &MI) const { 879*0b57cec5SDimitry Andric // XXX: KILL* instructions can be predicated, but they must be the last 880*0b57cec5SDimitry Andric // instruction in a clause, so this means any instructions after them cannot 881*0b57cec5SDimitry Andric // be predicated. Until we have proper support for instruction clauses in the 882*0b57cec5SDimitry Andric // backend, we will mark KILL* instructions as unpredicable. 883*0b57cec5SDimitry Andric 884*0b57cec5SDimitry Andric if (MI.getOpcode() == R600::KILLGT) { 885*0b57cec5SDimitry Andric return false; 886*0b57cec5SDimitry Andric } else if (MI.getOpcode() == R600::CF_ALU) { 887*0b57cec5SDimitry Andric // If the clause start in the middle of MBB then the MBB has more 888*0b57cec5SDimitry Andric // than a single clause, unable to predicate several clauses. 889*0b57cec5SDimitry Andric if (MI.getParent()->begin() != MachineBasicBlock::const_iterator(MI)) 890*0b57cec5SDimitry Andric return false; 891*0b57cec5SDimitry Andric // TODO: We don't support KC merging atm 892*0b57cec5SDimitry Andric return MI.getOperand(3).getImm() == 0 && MI.getOperand(4).getImm() == 0; 893*0b57cec5SDimitry Andric } else if (isVector(MI)) { 894*0b57cec5SDimitry Andric return false; 895*0b57cec5SDimitry Andric } else { 896*0b57cec5SDimitry Andric return TargetInstrInfo::isPredicable(MI); 897*0b57cec5SDimitry Andric } 898*0b57cec5SDimitry Andric } 899*0b57cec5SDimitry Andric 900*0b57cec5SDimitry Andric bool 901*0b57cec5SDimitry Andric R600InstrInfo::isProfitableToIfCvt(MachineBasicBlock &MBB, 902*0b57cec5SDimitry Andric unsigned NumCycles, 903*0b57cec5SDimitry Andric unsigned ExtraPredCycles, 904*0b57cec5SDimitry Andric BranchProbability Probability) const{ 905*0b57cec5SDimitry Andric return true; 906*0b57cec5SDimitry Andric } 907*0b57cec5SDimitry Andric 908*0b57cec5SDimitry Andric bool 909*0b57cec5SDimitry Andric R600InstrInfo::isProfitableToIfCvt(MachineBasicBlock &TMBB, 910*0b57cec5SDimitry Andric unsigned NumTCycles, 911*0b57cec5SDimitry Andric unsigned ExtraTCycles, 912*0b57cec5SDimitry Andric MachineBasicBlock &FMBB, 913*0b57cec5SDimitry Andric unsigned NumFCycles, 914*0b57cec5SDimitry Andric unsigned ExtraFCycles, 915*0b57cec5SDimitry Andric BranchProbability Probability) const { 916*0b57cec5SDimitry Andric return true; 917*0b57cec5SDimitry Andric } 918*0b57cec5SDimitry Andric 919*0b57cec5SDimitry Andric bool 920*0b57cec5SDimitry Andric R600InstrInfo::isProfitableToDupForIfCvt(MachineBasicBlock &MBB, 921*0b57cec5SDimitry Andric unsigned NumCycles, 922*0b57cec5SDimitry Andric BranchProbability Probability) 923*0b57cec5SDimitry Andric const { 924*0b57cec5SDimitry Andric return true; 925*0b57cec5SDimitry Andric } 926*0b57cec5SDimitry Andric 927*0b57cec5SDimitry Andric bool 928*0b57cec5SDimitry Andric R600InstrInfo::isProfitableToUnpredicate(MachineBasicBlock &TMBB, 929*0b57cec5SDimitry Andric MachineBasicBlock &FMBB) const { 930*0b57cec5SDimitry Andric return false; 931*0b57cec5SDimitry Andric } 932*0b57cec5SDimitry Andric 933*0b57cec5SDimitry Andric bool 934*0b57cec5SDimitry Andric R600InstrInfo::reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { 935*0b57cec5SDimitry Andric MachineOperand &MO = Cond[1]; 936*0b57cec5SDimitry Andric switch (MO.getImm()) { 937*0b57cec5SDimitry Andric case R600::PRED_SETE_INT: 938*0b57cec5SDimitry Andric MO.setImm(R600::PRED_SETNE_INT); 939*0b57cec5SDimitry Andric break; 940*0b57cec5SDimitry Andric case R600::PRED_SETNE_INT: 941*0b57cec5SDimitry Andric MO.setImm(R600::PRED_SETE_INT); 942*0b57cec5SDimitry Andric break; 943*0b57cec5SDimitry Andric case R600::PRED_SETE: 944*0b57cec5SDimitry Andric MO.setImm(R600::PRED_SETNE); 945*0b57cec5SDimitry Andric break; 946*0b57cec5SDimitry Andric case R600::PRED_SETNE: 947*0b57cec5SDimitry Andric MO.setImm(R600::PRED_SETE); 948*0b57cec5SDimitry Andric break; 949*0b57cec5SDimitry Andric default: 950*0b57cec5SDimitry Andric return true; 951*0b57cec5SDimitry Andric } 952*0b57cec5SDimitry Andric 953*0b57cec5SDimitry Andric MachineOperand &MO2 = Cond[2]; 954*0b57cec5SDimitry Andric switch (MO2.getReg()) { 955*0b57cec5SDimitry Andric case R600::PRED_SEL_ZERO: 956*0b57cec5SDimitry Andric MO2.setReg(R600::PRED_SEL_ONE); 957*0b57cec5SDimitry Andric break; 958*0b57cec5SDimitry Andric case R600::PRED_SEL_ONE: 959*0b57cec5SDimitry Andric MO2.setReg(R600::PRED_SEL_ZERO); 960*0b57cec5SDimitry Andric break; 961*0b57cec5SDimitry Andric default: 962*0b57cec5SDimitry Andric return true; 963*0b57cec5SDimitry Andric } 964*0b57cec5SDimitry Andric return false; 965*0b57cec5SDimitry Andric } 966*0b57cec5SDimitry Andric 967*0b57cec5SDimitry Andric bool R600InstrInfo::DefinesPredicate(MachineInstr &MI, 968*0b57cec5SDimitry Andric std::vector<MachineOperand> &Pred) const { 969*0b57cec5SDimitry Andric return isPredicateSetter(MI.getOpcode()); 970*0b57cec5SDimitry Andric } 971*0b57cec5SDimitry Andric 972*0b57cec5SDimitry Andric bool R600InstrInfo::PredicateInstruction(MachineInstr &MI, 973*0b57cec5SDimitry Andric ArrayRef<MachineOperand> Pred) const { 974*0b57cec5SDimitry Andric int PIdx = MI.findFirstPredOperandIdx(); 975*0b57cec5SDimitry Andric 976*0b57cec5SDimitry Andric if (MI.getOpcode() == R600::CF_ALU) { 977*0b57cec5SDimitry Andric MI.getOperand(8).setImm(0); 978*0b57cec5SDimitry Andric return true; 979*0b57cec5SDimitry Andric } 980*0b57cec5SDimitry Andric 981*0b57cec5SDimitry Andric if (MI.getOpcode() == R600::DOT_4) { 982*0b57cec5SDimitry Andric MI.getOperand(getOperandIdx(MI, R600::OpName::pred_sel_X)) 983*0b57cec5SDimitry Andric .setReg(Pred[2].getReg()); 984*0b57cec5SDimitry Andric MI.getOperand(getOperandIdx(MI, R600::OpName::pred_sel_Y)) 985*0b57cec5SDimitry Andric .setReg(Pred[2].getReg()); 986*0b57cec5SDimitry Andric MI.getOperand(getOperandIdx(MI, R600::OpName::pred_sel_Z)) 987*0b57cec5SDimitry Andric .setReg(Pred[2].getReg()); 988*0b57cec5SDimitry Andric MI.getOperand(getOperandIdx(MI, R600::OpName::pred_sel_W)) 989*0b57cec5SDimitry Andric .setReg(Pred[2].getReg()); 990*0b57cec5SDimitry Andric MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI); 991*0b57cec5SDimitry Andric MIB.addReg(R600::PREDICATE_BIT, RegState::Implicit); 992*0b57cec5SDimitry Andric return true; 993*0b57cec5SDimitry Andric } 994*0b57cec5SDimitry Andric 995*0b57cec5SDimitry Andric if (PIdx != -1) { 996*0b57cec5SDimitry Andric MachineOperand &PMO = MI.getOperand(PIdx); 997*0b57cec5SDimitry Andric PMO.setReg(Pred[2].getReg()); 998*0b57cec5SDimitry Andric MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI); 999*0b57cec5SDimitry Andric MIB.addReg(R600::PREDICATE_BIT, RegState::Implicit); 1000*0b57cec5SDimitry Andric return true; 1001*0b57cec5SDimitry Andric } 1002*0b57cec5SDimitry Andric 1003*0b57cec5SDimitry Andric return false; 1004*0b57cec5SDimitry Andric } 1005*0b57cec5SDimitry Andric 1006*0b57cec5SDimitry Andric unsigned int R600InstrInfo::getPredicationCost(const MachineInstr &) const { 1007*0b57cec5SDimitry Andric return 2; 1008*0b57cec5SDimitry Andric } 1009*0b57cec5SDimitry Andric 1010*0b57cec5SDimitry Andric unsigned int R600InstrInfo::getInstrLatency(const InstrItineraryData *ItinData, 1011*0b57cec5SDimitry Andric const MachineInstr &, 1012*0b57cec5SDimitry Andric unsigned *PredCost) const { 1013*0b57cec5SDimitry Andric if (PredCost) 1014*0b57cec5SDimitry Andric *PredCost = 2; 1015*0b57cec5SDimitry Andric return 2; 1016*0b57cec5SDimitry Andric } 1017*0b57cec5SDimitry Andric 1018*0b57cec5SDimitry Andric unsigned R600InstrInfo::calculateIndirectAddress(unsigned RegIndex, 1019*0b57cec5SDimitry Andric unsigned Channel) const { 1020*0b57cec5SDimitry Andric assert(Channel == 0); 1021*0b57cec5SDimitry Andric return RegIndex; 1022*0b57cec5SDimitry Andric } 1023*0b57cec5SDimitry Andric 1024*0b57cec5SDimitry Andric bool R600InstrInfo::expandPostRAPseudo(MachineInstr &MI) const { 1025*0b57cec5SDimitry Andric switch (MI.getOpcode()) { 1026*0b57cec5SDimitry Andric default: { 1027*0b57cec5SDimitry Andric MachineBasicBlock *MBB = MI.getParent(); 1028*0b57cec5SDimitry Andric int OffsetOpIdx = 1029*0b57cec5SDimitry Andric R600::getNamedOperandIdx(MI.getOpcode(), R600::OpName::addr); 1030*0b57cec5SDimitry Andric // addr is a custom operand with multiple MI operands, and only the 1031*0b57cec5SDimitry Andric // first MI operand is given a name. 1032*0b57cec5SDimitry Andric int RegOpIdx = OffsetOpIdx + 1; 1033*0b57cec5SDimitry Andric int ChanOpIdx = 1034*0b57cec5SDimitry Andric R600::getNamedOperandIdx(MI.getOpcode(), R600::OpName::chan); 1035*0b57cec5SDimitry Andric if (isRegisterLoad(MI)) { 1036*0b57cec5SDimitry Andric int DstOpIdx = 1037*0b57cec5SDimitry Andric R600::getNamedOperandIdx(MI.getOpcode(), R600::OpName::dst); 1038*0b57cec5SDimitry Andric unsigned RegIndex = MI.getOperand(RegOpIdx).getImm(); 1039*0b57cec5SDimitry Andric unsigned Channel = MI.getOperand(ChanOpIdx).getImm(); 1040*0b57cec5SDimitry Andric unsigned Address = calculateIndirectAddress(RegIndex, Channel); 1041*0b57cec5SDimitry Andric unsigned OffsetReg = MI.getOperand(OffsetOpIdx).getReg(); 1042*0b57cec5SDimitry Andric if (OffsetReg == R600::INDIRECT_BASE_ADDR) { 1043*0b57cec5SDimitry Andric buildMovInstr(MBB, MI, MI.getOperand(DstOpIdx).getReg(), 1044*0b57cec5SDimitry Andric getIndirectAddrRegClass()->getRegister(Address)); 1045*0b57cec5SDimitry Andric } else { 1046*0b57cec5SDimitry Andric buildIndirectRead(MBB, MI, MI.getOperand(DstOpIdx).getReg(), Address, 1047*0b57cec5SDimitry Andric OffsetReg); 1048*0b57cec5SDimitry Andric } 1049*0b57cec5SDimitry Andric } else if (isRegisterStore(MI)) { 1050*0b57cec5SDimitry Andric int ValOpIdx = 1051*0b57cec5SDimitry Andric R600::getNamedOperandIdx(MI.getOpcode(), R600::OpName::val); 1052*0b57cec5SDimitry Andric unsigned RegIndex = MI.getOperand(RegOpIdx).getImm(); 1053*0b57cec5SDimitry Andric unsigned Channel = MI.getOperand(ChanOpIdx).getImm(); 1054*0b57cec5SDimitry Andric unsigned Address = calculateIndirectAddress(RegIndex, Channel); 1055*0b57cec5SDimitry Andric unsigned OffsetReg = MI.getOperand(OffsetOpIdx).getReg(); 1056*0b57cec5SDimitry Andric if (OffsetReg == R600::INDIRECT_BASE_ADDR) { 1057*0b57cec5SDimitry Andric buildMovInstr(MBB, MI, getIndirectAddrRegClass()->getRegister(Address), 1058*0b57cec5SDimitry Andric MI.getOperand(ValOpIdx).getReg()); 1059*0b57cec5SDimitry Andric } else { 1060*0b57cec5SDimitry Andric buildIndirectWrite(MBB, MI, MI.getOperand(ValOpIdx).getReg(), 1061*0b57cec5SDimitry Andric calculateIndirectAddress(RegIndex, Channel), 1062*0b57cec5SDimitry Andric OffsetReg); 1063*0b57cec5SDimitry Andric } 1064*0b57cec5SDimitry Andric } else { 1065*0b57cec5SDimitry Andric return false; 1066*0b57cec5SDimitry Andric } 1067*0b57cec5SDimitry Andric 1068*0b57cec5SDimitry Andric MBB->erase(MI); 1069*0b57cec5SDimitry Andric return true; 1070*0b57cec5SDimitry Andric } 1071*0b57cec5SDimitry Andric case R600::R600_EXTRACT_ELT_V2: 1072*0b57cec5SDimitry Andric case R600::R600_EXTRACT_ELT_V4: 1073*0b57cec5SDimitry Andric buildIndirectRead(MI.getParent(), MI, MI.getOperand(0).getReg(), 1074*0b57cec5SDimitry Andric RI.getHWRegIndex(MI.getOperand(1).getReg()), // Address 1075*0b57cec5SDimitry Andric MI.getOperand(2).getReg(), 1076*0b57cec5SDimitry Andric RI.getHWRegChan(MI.getOperand(1).getReg())); 1077*0b57cec5SDimitry Andric break; 1078*0b57cec5SDimitry Andric case R600::R600_INSERT_ELT_V2: 1079*0b57cec5SDimitry Andric case R600::R600_INSERT_ELT_V4: 1080*0b57cec5SDimitry Andric buildIndirectWrite(MI.getParent(), MI, MI.getOperand(2).getReg(), // Value 1081*0b57cec5SDimitry Andric RI.getHWRegIndex(MI.getOperand(1).getReg()), // Address 1082*0b57cec5SDimitry Andric MI.getOperand(3).getReg(), // Offset 1083*0b57cec5SDimitry Andric RI.getHWRegChan(MI.getOperand(1).getReg())); // Channel 1084*0b57cec5SDimitry Andric break; 1085*0b57cec5SDimitry Andric } 1086*0b57cec5SDimitry Andric MI.eraseFromParent(); 1087*0b57cec5SDimitry Andric return true; 1088*0b57cec5SDimitry Andric } 1089*0b57cec5SDimitry Andric 1090*0b57cec5SDimitry Andric void R600InstrInfo::reserveIndirectRegisters(BitVector &Reserved, 1091*0b57cec5SDimitry Andric const MachineFunction &MF, 1092*0b57cec5SDimitry Andric const R600RegisterInfo &TRI) const { 1093*0b57cec5SDimitry Andric const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>(); 1094*0b57cec5SDimitry Andric const R600FrameLowering *TFL = ST.getFrameLowering(); 1095*0b57cec5SDimitry Andric 1096*0b57cec5SDimitry Andric unsigned StackWidth = TFL->getStackWidth(MF); 1097*0b57cec5SDimitry Andric int End = getIndirectIndexEnd(MF); 1098*0b57cec5SDimitry Andric 1099*0b57cec5SDimitry Andric if (End == -1) 1100*0b57cec5SDimitry Andric return; 1101*0b57cec5SDimitry Andric 1102*0b57cec5SDimitry Andric for (int Index = getIndirectIndexBegin(MF); Index <= End; ++Index) { 1103*0b57cec5SDimitry Andric for (unsigned Chan = 0; Chan < StackWidth; ++Chan) { 1104*0b57cec5SDimitry Andric unsigned Reg = R600::R600_TReg32RegClass.getRegister((4 * Index) + Chan); 1105*0b57cec5SDimitry Andric TRI.reserveRegisterTuples(Reserved, Reg); 1106*0b57cec5SDimitry Andric } 1107*0b57cec5SDimitry Andric } 1108*0b57cec5SDimitry Andric } 1109*0b57cec5SDimitry Andric 1110*0b57cec5SDimitry Andric const TargetRegisterClass *R600InstrInfo::getIndirectAddrRegClass() const { 1111*0b57cec5SDimitry Andric return &R600::R600_TReg32_XRegClass; 1112*0b57cec5SDimitry Andric } 1113*0b57cec5SDimitry Andric 1114*0b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildIndirectWrite(MachineBasicBlock *MBB, 1115*0b57cec5SDimitry Andric MachineBasicBlock::iterator I, 1116*0b57cec5SDimitry Andric unsigned ValueReg, unsigned Address, 1117*0b57cec5SDimitry Andric unsigned OffsetReg) const { 1118*0b57cec5SDimitry Andric return buildIndirectWrite(MBB, I, ValueReg, Address, OffsetReg, 0); 1119*0b57cec5SDimitry Andric } 1120*0b57cec5SDimitry Andric 1121*0b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildIndirectWrite(MachineBasicBlock *MBB, 1122*0b57cec5SDimitry Andric MachineBasicBlock::iterator I, 1123*0b57cec5SDimitry Andric unsigned ValueReg, unsigned Address, 1124*0b57cec5SDimitry Andric unsigned OffsetReg, 1125*0b57cec5SDimitry Andric unsigned AddrChan) const { 1126*0b57cec5SDimitry Andric unsigned AddrReg; 1127*0b57cec5SDimitry Andric switch (AddrChan) { 1128*0b57cec5SDimitry Andric default: llvm_unreachable("Invalid Channel"); 1129*0b57cec5SDimitry Andric case 0: AddrReg = R600::R600_AddrRegClass.getRegister(Address); break; 1130*0b57cec5SDimitry Andric case 1: AddrReg = R600::R600_Addr_YRegClass.getRegister(Address); break; 1131*0b57cec5SDimitry Andric case 2: AddrReg = R600::R600_Addr_ZRegClass.getRegister(Address); break; 1132*0b57cec5SDimitry Andric case 3: AddrReg = R600::R600_Addr_WRegClass.getRegister(Address); break; 1133*0b57cec5SDimitry Andric } 1134*0b57cec5SDimitry Andric MachineInstr *MOVA = buildDefaultInstruction(*MBB, I, R600::MOVA_INT_eg, 1135*0b57cec5SDimitry Andric R600::AR_X, OffsetReg); 1136*0b57cec5SDimitry Andric setImmOperand(*MOVA, R600::OpName::write, 0); 1137*0b57cec5SDimitry Andric 1138*0b57cec5SDimitry Andric MachineInstrBuilder Mov = buildDefaultInstruction(*MBB, I, R600::MOV, 1139*0b57cec5SDimitry Andric AddrReg, ValueReg) 1140*0b57cec5SDimitry Andric .addReg(R600::AR_X, 1141*0b57cec5SDimitry Andric RegState::Implicit | RegState::Kill); 1142*0b57cec5SDimitry Andric setImmOperand(*Mov, R600::OpName::dst_rel, 1); 1143*0b57cec5SDimitry Andric return Mov; 1144*0b57cec5SDimitry Andric } 1145*0b57cec5SDimitry Andric 1146*0b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildIndirectRead(MachineBasicBlock *MBB, 1147*0b57cec5SDimitry Andric MachineBasicBlock::iterator I, 1148*0b57cec5SDimitry Andric unsigned ValueReg, unsigned Address, 1149*0b57cec5SDimitry Andric unsigned OffsetReg) const { 1150*0b57cec5SDimitry Andric return buildIndirectRead(MBB, I, ValueReg, Address, OffsetReg, 0); 1151*0b57cec5SDimitry Andric } 1152*0b57cec5SDimitry Andric 1153*0b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildIndirectRead(MachineBasicBlock *MBB, 1154*0b57cec5SDimitry Andric MachineBasicBlock::iterator I, 1155*0b57cec5SDimitry Andric unsigned ValueReg, unsigned Address, 1156*0b57cec5SDimitry Andric unsigned OffsetReg, 1157*0b57cec5SDimitry Andric unsigned AddrChan) const { 1158*0b57cec5SDimitry Andric unsigned AddrReg; 1159*0b57cec5SDimitry Andric switch (AddrChan) { 1160*0b57cec5SDimitry Andric default: llvm_unreachable("Invalid Channel"); 1161*0b57cec5SDimitry Andric case 0: AddrReg = R600::R600_AddrRegClass.getRegister(Address); break; 1162*0b57cec5SDimitry Andric case 1: AddrReg = R600::R600_Addr_YRegClass.getRegister(Address); break; 1163*0b57cec5SDimitry Andric case 2: AddrReg = R600::R600_Addr_ZRegClass.getRegister(Address); break; 1164*0b57cec5SDimitry Andric case 3: AddrReg = R600::R600_Addr_WRegClass.getRegister(Address); break; 1165*0b57cec5SDimitry Andric } 1166*0b57cec5SDimitry Andric MachineInstr *MOVA = buildDefaultInstruction(*MBB, I, R600::MOVA_INT_eg, 1167*0b57cec5SDimitry Andric R600::AR_X, 1168*0b57cec5SDimitry Andric OffsetReg); 1169*0b57cec5SDimitry Andric setImmOperand(*MOVA, R600::OpName::write, 0); 1170*0b57cec5SDimitry Andric MachineInstrBuilder Mov = buildDefaultInstruction(*MBB, I, R600::MOV, 1171*0b57cec5SDimitry Andric ValueReg, 1172*0b57cec5SDimitry Andric AddrReg) 1173*0b57cec5SDimitry Andric .addReg(R600::AR_X, 1174*0b57cec5SDimitry Andric RegState::Implicit | RegState::Kill); 1175*0b57cec5SDimitry Andric setImmOperand(*Mov, R600::OpName::src0_rel, 1); 1176*0b57cec5SDimitry Andric 1177*0b57cec5SDimitry Andric return Mov; 1178*0b57cec5SDimitry Andric } 1179*0b57cec5SDimitry Andric 1180*0b57cec5SDimitry Andric int R600InstrInfo::getIndirectIndexBegin(const MachineFunction &MF) const { 1181*0b57cec5SDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 1182*0b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 1183*0b57cec5SDimitry Andric int Offset = -1; 1184*0b57cec5SDimitry Andric 1185*0b57cec5SDimitry Andric if (MFI.getNumObjects() == 0) { 1186*0b57cec5SDimitry Andric return -1; 1187*0b57cec5SDimitry Andric } 1188*0b57cec5SDimitry Andric 1189*0b57cec5SDimitry Andric if (MRI.livein_empty()) { 1190*0b57cec5SDimitry Andric return 0; 1191*0b57cec5SDimitry Andric } 1192*0b57cec5SDimitry Andric 1193*0b57cec5SDimitry Andric const TargetRegisterClass *IndirectRC = getIndirectAddrRegClass(); 1194*0b57cec5SDimitry Andric for (std::pair<unsigned, unsigned> LI : MRI.liveins()) { 1195*0b57cec5SDimitry Andric unsigned Reg = LI.first; 1196*0b57cec5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(Reg) || 1197*0b57cec5SDimitry Andric !IndirectRC->contains(Reg)) 1198*0b57cec5SDimitry Andric continue; 1199*0b57cec5SDimitry Andric 1200*0b57cec5SDimitry Andric unsigned RegIndex; 1201*0b57cec5SDimitry Andric unsigned RegEnd; 1202*0b57cec5SDimitry Andric for (RegIndex = 0, RegEnd = IndirectRC->getNumRegs(); RegIndex != RegEnd; 1203*0b57cec5SDimitry Andric ++RegIndex) { 1204*0b57cec5SDimitry Andric if (IndirectRC->getRegister(RegIndex) == Reg) 1205*0b57cec5SDimitry Andric break; 1206*0b57cec5SDimitry Andric } 1207*0b57cec5SDimitry Andric Offset = std::max(Offset, (int)RegIndex); 1208*0b57cec5SDimitry Andric } 1209*0b57cec5SDimitry Andric 1210*0b57cec5SDimitry Andric return Offset + 1; 1211*0b57cec5SDimitry Andric } 1212*0b57cec5SDimitry Andric 1213*0b57cec5SDimitry Andric int R600InstrInfo::getIndirectIndexEnd(const MachineFunction &MF) const { 1214*0b57cec5SDimitry Andric int Offset = 0; 1215*0b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo(); 1216*0b57cec5SDimitry Andric 1217*0b57cec5SDimitry Andric // Variable sized objects are not supported 1218*0b57cec5SDimitry Andric if (MFI.hasVarSizedObjects()) { 1219*0b57cec5SDimitry Andric return -1; 1220*0b57cec5SDimitry Andric } 1221*0b57cec5SDimitry Andric 1222*0b57cec5SDimitry Andric if (MFI.getNumObjects() == 0) { 1223*0b57cec5SDimitry Andric return -1; 1224*0b57cec5SDimitry Andric } 1225*0b57cec5SDimitry Andric 1226*0b57cec5SDimitry Andric const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>(); 1227*0b57cec5SDimitry Andric const R600FrameLowering *TFL = ST.getFrameLowering(); 1228*0b57cec5SDimitry Andric 1229*0b57cec5SDimitry Andric unsigned IgnoredFrameReg; 1230*0b57cec5SDimitry Andric Offset = TFL->getFrameIndexReference(MF, -1, IgnoredFrameReg); 1231*0b57cec5SDimitry Andric 1232*0b57cec5SDimitry Andric return getIndirectIndexBegin(MF) + Offset; 1233*0b57cec5SDimitry Andric } 1234*0b57cec5SDimitry Andric 1235*0b57cec5SDimitry Andric unsigned R600InstrInfo::getMaxAlusPerClause() const { 1236*0b57cec5SDimitry Andric return 115; 1237*0b57cec5SDimitry Andric } 1238*0b57cec5SDimitry Andric 1239*0b57cec5SDimitry Andric MachineInstrBuilder R600InstrInfo::buildDefaultInstruction(MachineBasicBlock &MBB, 1240*0b57cec5SDimitry Andric MachineBasicBlock::iterator I, 1241*0b57cec5SDimitry Andric unsigned Opcode, 1242*0b57cec5SDimitry Andric unsigned DstReg, 1243*0b57cec5SDimitry Andric unsigned Src0Reg, 1244*0b57cec5SDimitry Andric unsigned Src1Reg) const { 1245*0b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, I, MBB.findDebugLoc(I), get(Opcode), 1246*0b57cec5SDimitry Andric DstReg); // $dst 1247*0b57cec5SDimitry Andric 1248*0b57cec5SDimitry Andric if (Src1Reg) { 1249*0b57cec5SDimitry Andric MIB.addImm(0) // $update_exec_mask 1250*0b57cec5SDimitry Andric .addImm(0); // $update_predicate 1251*0b57cec5SDimitry Andric } 1252*0b57cec5SDimitry Andric MIB.addImm(1) // $write 1253*0b57cec5SDimitry Andric .addImm(0) // $omod 1254*0b57cec5SDimitry Andric .addImm(0) // $dst_rel 1255*0b57cec5SDimitry Andric .addImm(0) // $dst_clamp 1256*0b57cec5SDimitry Andric .addReg(Src0Reg) // $src0 1257*0b57cec5SDimitry Andric .addImm(0) // $src0_neg 1258*0b57cec5SDimitry Andric .addImm(0) // $src0_rel 1259*0b57cec5SDimitry Andric .addImm(0) // $src0_abs 1260*0b57cec5SDimitry Andric .addImm(-1); // $src0_sel 1261*0b57cec5SDimitry Andric 1262*0b57cec5SDimitry Andric if (Src1Reg) { 1263*0b57cec5SDimitry Andric MIB.addReg(Src1Reg) // $src1 1264*0b57cec5SDimitry Andric .addImm(0) // $src1_neg 1265*0b57cec5SDimitry Andric .addImm(0) // $src1_rel 1266*0b57cec5SDimitry Andric .addImm(0) // $src1_abs 1267*0b57cec5SDimitry Andric .addImm(-1); // $src1_sel 1268*0b57cec5SDimitry Andric } 1269*0b57cec5SDimitry Andric 1270*0b57cec5SDimitry Andric //XXX: The r600g finalizer expects this to be 1, once we've moved the 1271*0b57cec5SDimitry Andric //scheduling to the backend, we can change the default to 0. 1272*0b57cec5SDimitry Andric MIB.addImm(1) // $last 1273*0b57cec5SDimitry Andric .addReg(R600::PRED_SEL_OFF) // $pred_sel 1274*0b57cec5SDimitry Andric .addImm(0) // $literal 1275*0b57cec5SDimitry Andric .addImm(0); // $bank_swizzle 1276*0b57cec5SDimitry Andric 1277*0b57cec5SDimitry Andric return MIB; 1278*0b57cec5SDimitry Andric } 1279*0b57cec5SDimitry Andric 1280*0b57cec5SDimitry Andric #define OPERAND_CASE(Label) \ 1281*0b57cec5SDimitry Andric case Label: { \ 1282*0b57cec5SDimitry Andric static const unsigned Ops[] = \ 1283*0b57cec5SDimitry Andric { \ 1284*0b57cec5SDimitry Andric Label##_X, \ 1285*0b57cec5SDimitry Andric Label##_Y, \ 1286*0b57cec5SDimitry Andric Label##_Z, \ 1287*0b57cec5SDimitry Andric Label##_W \ 1288*0b57cec5SDimitry Andric }; \ 1289*0b57cec5SDimitry Andric return Ops[Slot]; \ 1290*0b57cec5SDimitry Andric } 1291*0b57cec5SDimitry Andric 1292*0b57cec5SDimitry Andric static unsigned getSlotedOps(unsigned Op, unsigned Slot) { 1293*0b57cec5SDimitry Andric switch (Op) { 1294*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::update_exec_mask) 1295*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::update_pred) 1296*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::write) 1297*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::omod) 1298*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::dst_rel) 1299*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::clamp) 1300*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src0) 1301*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src0_neg) 1302*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src0_rel) 1303*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src0_abs) 1304*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src0_sel) 1305*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src1) 1306*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src1_neg) 1307*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src1_rel) 1308*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src1_abs) 1309*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::src1_sel) 1310*0b57cec5SDimitry Andric OPERAND_CASE(R600::OpName::pred_sel) 1311*0b57cec5SDimitry Andric default: 1312*0b57cec5SDimitry Andric llvm_unreachable("Wrong Operand"); 1313*0b57cec5SDimitry Andric } 1314*0b57cec5SDimitry Andric } 1315*0b57cec5SDimitry Andric 1316*0b57cec5SDimitry Andric #undef OPERAND_CASE 1317*0b57cec5SDimitry Andric 1318*0b57cec5SDimitry Andric MachineInstr *R600InstrInfo::buildSlotOfVectorInstruction( 1319*0b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineInstr *MI, unsigned Slot, unsigned DstReg) 1320*0b57cec5SDimitry Andric const { 1321*0b57cec5SDimitry Andric assert (MI->getOpcode() == R600::DOT_4 && "Not Implemented"); 1322*0b57cec5SDimitry Andric unsigned Opcode; 1323*0b57cec5SDimitry Andric if (ST.getGeneration() <= AMDGPUSubtarget::R700) 1324*0b57cec5SDimitry Andric Opcode = R600::DOT4_r600; 1325*0b57cec5SDimitry Andric else 1326*0b57cec5SDimitry Andric Opcode = R600::DOT4_eg; 1327*0b57cec5SDimitry Andric MachineBasicBlock::iterator I = MI; 1328*0b57cec5SDimitry Andric MachineOperand &Src0 = MI->getOperand( 1329*0b57cec5SDimitry Andric getOperandIdx(MI->getOpcode(), getSlotedOps(R600::OpName::src0, Slot))); 1330*0b57cec5SDimitry Andric MachineOperand &Src1 = MI->getOperand( 1331*0b57cec5SDimitry Andric getOperandIdx(MI->getOpcode(), getSlotedOps(R600::OpName::src1, Slot))); 1332*0b57cec5SDimitry Andric MachineInstr *MIB = buildDefaultInstruction( 1333*0b57cec5SDimitry Andric MBB, I, Opcode, DstReg, Src0.getReg(), Src1.getReg()); 1334*0b57cec5SDimitry Andric static const unsigned Operands[14] = { 1335*0b57cec5SDimitry Andric R600::OpName::update_exec_mask, 1336*0b57cec5SDimitry Andric R600::OpName::update_pred, 1337*0b57cec5SDimitry Andric R600::OpName::write, 1338*0b57cec5SDimitry Andric R600::OpName::omod, 1339*0b57cec5SDimitry Andric R600::OpName::dst_rel, 1340*0b57cec5SDimitry Andric R600::OpName::clamp, 1341*0b57cec5SDimitry Andric R600::OpName::src0_neg, 1342*0b57cec5SDimitry Andric R600::OpName::src0_rel, 1343*0b57cec5SDimitry Andric R600::OpName::src0_abs, 1344*0b57cec5SDimitry Andric R600::OpName::src0_sel, 1345*0b57cec5SDimitry Andric R600::OpName::src1_neg, 1346*0b57cec5SDimitry Andric R600::OpName::src1_rel, 1347*0b57cec5SDimitry Andric R600::OpName::src1_abs, 1348*0b57cec5SDimitry Andric R600::OpName::src1_sel, 1349*0b57cec5SDimitry Andric }; 1350*0b57cec5SDimitry Andric 1351*0b57cec5SDimitry Andric MachineOperand &MO = MI->getOperand(getOperandIdx(MI->getOpcode(), 1352*0b57cec5SDimitry Andric getSlotedOps(R600::OpName::pred_sel, Slot))); 1353*0b57cec5SDimitry Andric MIB->getOperand(getOperandIdx(Opcode, R600::OpName::pred_sel)) 1354*0b57cec5SDimitry Andric .setReg(MO.getReg()); 1355*0b57cec5SDimitry Andric 1356*0b57cec5SDimitry Andric for (unsigned i = 0; i < 14; i++) { 1357*0b57cec5SDimitry Andric MachineOperand &MO = MI->getOperand( 1358*0b57cec5SDimitry Andric getOperandIdx(MI->getOpcode(), getSlotedOps(Operands[i], Slot))); 1359*0b57cec5SDimitry Andric assert (MO.isImm()); 1360*0b57cec5SDimitry Andric setImmOperand(*MIB, Operands[i], MO.getImm()); 1361*0b57cec5SDimitry Andric } 1362*0b57cec5SDimitry Andric MIB->getOperand(20).setImm(0); 1363*0b57cec5SDimitry Andric return MIB; 1364*0b57cec5SDimitry Andric } 1365*0b57cec5SDimitry Andric 1366*0b57cec5SDimitry Andric MachineInstr *R600InstrInfo::buildMovImm(MachineBasicBlock &BB, 1367*0b57cec5SDimitry Andric MachineBasicBlock::iterator I, 1368*0b57cec5SDimitry Andric unsigned DstReg, 1369*0b57cec5SDimitry Andric uint64_t Imm) const { 1370*0b57cec5SDimitry Andric MachineInstr *MovImm = buildDefaultInstruction(BB, I, R600::MOV, DstReg, 1371*0b57cec5SDimitry Andric R600::ALU_LITERAL_X); 1372*0b57cec5SDimitry Andric setImmOperand(*MovImm, R600::OpName::literal, Imm); 1373*0b57cec5SDimitry Andric return MovImm; 1374*0b57cec5SDimitry Andric } 1375*0b57cec5SDimitry Andric 1376*0b57cec5SDimitry Andric MachineInstr *R600InstrInfo::buildMovInstr(MachineBasicBlock *MBB, 1377*0b57cec5SDimitry Andric MachineBasicBlock::iterator I, 1378*0b57cec5SDimitry Andric unsigned DstReg, unsigned SrcReg) const { 1379*0b57cec5SDimitry Andric return buildDefaultInstruction(*MBB, I, R600::MOV, DstReg, SrcReg); 1380*0b57cec5SDimitry Andric } 1381*0b57cec5SDimitry Andric 1382*0b57cec5SDimitry Andric int R600InstrInfo::getOperandIdx(const MachineInstr &MI, unsigned Op) const { 1383*0b57cec5SDimitry Andric return getOperandIdx(MI.getOpcode(), Op); 1384*0b57cec5SDimitry Andric } 1385*0b57cec5SDimitry Andric 1386*0b57cec5SDimitry Andric int R600InstrInfo::getOperandIdx(unsigned Opcode, unsigned Op) const { 1387*0b57cec5SDimitry Andric return R600::getNamedOperandIdx(Opcode, Op); 1388*0b57cec5SDimitry Andric } 1389*0b57cec5SDimitry Andric 1390*0b57cec5SDimitry Andric void R600InstrInfo::setImmOperand(MachineInstr &MI, unsigned Op, 1391*0b57cec5SDimitry Andric int64_t Imm) const { 1392*0b57cec5SDimitry Andric int Idx = getOperandIdx(MI, Op); 1393*0b57cec5SDimitry Andric assert(Idx != -1 && "Operand not supported for this instruction."); 1394*0b57cec5SDimitry Andric assert(MI.getOperand(Idx).isImm()); 1395*0b57cec5SDimitry Andric MI.getOperand(Idx).setImm(Imm); 1396*0b57cec5SDimitry Andric } 1397*0b57cec5SDimitry Andric 1398*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1399*0b57cec5SDimitry Andric // Instruction flag getters/setters 1400*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1401*0b57cec5SDimitry Andric 1402*0b57cec5SDimitry Andric MachineOperand &R600InstrInfo::getFlagOp(MachineInstr &MI, unsigned SrcIdx, 1403*0b57cec5SDimitry Andric unsigned Flag) const { 1404*0b57cec5SDimitry Andric unsigned TargetFlags = get(MI.getOpcode()).TSFlags; 1405*0b57cec5SDimitry Andric int FlagIndex = 0; 1406*0b57cec5SDimitry Andric if (Flag != 0) { 1407*0b57cec5SDimitry Andric // If we pass something other than the default value of Flag to this 1408*0b57cec5SDimitry Andric // function, it means we are want to set a flag on an instruction 1409*0b57cec5SDimitry Andric // that uses native encoding. 1410*0b57cec5SDimitry Andric assert(HAS_NATIVE_OPERANDS(TargetFlags)); 1411*0b57cec5SDimitry Andric bool IsOP3 = (TargetFlags & R600_InstFlag::OP3) == R600_InstFlag::OP3; 1412*0b57cec5SDimitry Andric switch (Flag) { 1413*0b57cec5SDimitry Andric case MO_FLAG_CLAMP: 1414*0b57cec5SDimitry Andric FlagIndex = getOperandIdx(MI, R600::OpName::clamp); 1415*0b57cec5SDimitry Andric break; 1416*0b57cec5SDimitry Andric case MO_FLAG_MASK: 1417*0b57cec5SDimitry Andric FlagIndex = getOperandIdx(MI, R600::OpName::write); 1418*0b57cec5SDimitry Andric break; 1419*0b57cec5SDimitry Andric case MO_FLAG_NOT_LAST: 1420*0b57cec5SDimitry Andric case MO_FLAG_LAST: 1421*0b57cec5SDimitry Andric FlagIndex = getOperandIdx(MI, R600::OpName::last); 1422*0b57cec5SDimitry Andric break; 1423*0b57cec5SDimitry Andric case MO_FLAG_NEG: 1424*0b57cec5SDimitry Andric switch (SrcIdx) { 1425*0b57cec5SDimitry Andric case 0: 1426*0b57cec5SDimitry Andric FlagIndex = getOperandIdx(MI, R600::OpName::src0_neg); 1427*0b57cec5SDimitry Andric break; 1428*0b57cec5SDimitry Andric case 1: 1429*0b57cec5SDimitry Andric FlagIndex = getOperandIdx(MI, R600::OpName::src1_neg); 1430*0b57cec5SDimitry Andric break; 1431*0b57cec5SDimitry Andric case 2: 1432*0b57cec5SDimitry Andric FlagIndex = getOperandIdx(MI, R600::OpName::src2_neg); 1433*0b57cec5SDimitry Andric break; 1434*0b57cec5SDimitry Andric } 1435*0b57cec5SDimitry Andric break; 1436*0b57cec5SDimitry Andric 1437*0b57cec5SDimitry Andric case MO_FLAG_ABS: 1438*0b57cec5SDimitry Andric assert(!IsOP3 && "Cannot set absolute value modifier for OP3 " 1439*0b57cec5SDimitry Andric "instructions."); 1440*0b57cec5SDimitry Andric (void)IsOP3; 1441*0b57cec5SDimitry Andric switch (SrcIdx) { 1442*0b57cec5SDimitry Andric case 0: 1443*0b57cec5SDimitry Andric FlagIndex = getOperandIdx(MI, R600::OpName::src0_abs); 1444*0b57cec5SDimitry Andric break; 1445*0b57cec5SDimitry Andric case 1: 1446*0b57cec5SDimitry Andric FlagIndex = getOperandIdx(MI, R600::OpName::src1_abs); 1447*0b57cec5SDimitry Andric break; 1448*0b57cec5SDimitry Andric } 1449*0b57cec5SDimitry Andric break; 1450*0b57cec5SDimitry Andric 1451*0b57cec5SDimitry Andric default: 1452*0b57cec5SDimitry Andric FlagIndex = -1; 1453*0b57cec5SDimitry Andric break; 1454*0b57cec5SDimitry Andric } 1455*0b57cec5SDimitry Andric assert(FlagIndex != -1 && "Flag not supported for this instruction"); 1456*0b57cec5SDimitry Andric } else { 1457*0b57cec5SDimitry Andric FlagIndex = GET_FLAG_OPERAND_IDX(TargetFlags); 1458*0b57cec5SDimitry Andric assert(FlagIndex != 0 && 1459*0b57cec5SDimitry Andric "Instruction flags not supported for this instruction"); 1460*0b57cec5SDimitry Andric } 1461*0b57cec5SDimitry Andric 1462*0b57cec5SDimitry Andric MachineOperand &FlagOp = MI.getOperand(FlagIndex); 1463*0b57cec5SDimitry Andric assert(FlagOp.isImm()); 1464*0b57cec5SDimitry Andric return FlagOp; 1465*0b57cec5SDimitry Andric } 1466*0b57cec5SDimitry Andric 1467*0b57cec5SDimitry Andric void R600InstrInfo::addFlag(MachineInstr &MI, unsigned Operand, 1468*0b57cec5SDimitry Andric unsigned Flag) const { 1469*0b57cec5SDimitry Andric unsigned TargetFlags = get(MI.getOpcode()).TSFlags; 1470*0b57cec5SDimitry Andric if (Flag == 0) { 1471*0b57cec5SDimitry Andric return; 1472*0b57cec5SDimitry Andric } 1473*0b57cec5SDimitry Andric if (HAS_NATIVE_OPERANDS(TargetFlags)) { 1474*0b57cec5SDimitry Andric MachineOperand &FlagOp = getFlagOp(MI, Operand, Flag); 1475*0b57cec5SDimitry Andric if (Flag == MO_FLAG_NOT_LAST) { 1476*0b57cec5SDimitry Andric clearFlag(MI, Operand, MO_FLAG_LAST); 1477*0b57cec5SDimitry Andric } else if (Flag == MO_FLAG_MASK) { 1478*0b57cec5SDimitry Andric clearFlag(MI, Operand, Flag); 1479*0b57cec5SDimitry Andric } else { 1480*0b57cec5SDimitry Andric FlagOp.setImm(1); 1481*0b57cec5SDimitry Andric } 1482*0b57cec5SDimitry Andric } else { 1483*0b57cec5SDimitry Andric MachineOperand &FlagOp = getFlagOp(MI, Operand); 1484*0b57cec5SDimitry Andric FlagOp.setImm(FlagOp.getImm() | (Flag << (NUM_MO_FLAGS * Operand))); 1485*0b57cec5SDimitry Andric } 1486*0b57cec5SDimitry Andric } 1487*0b57cec5SDimitry Andric 1488*0b57cec5SDimitry Andric void R600InstrInfo::clearFlag(MachineInstr &MI, unsigned Operand, 1489*0b57cec5SDimitry Andric unsigned Flag) const { 1490*0b57cec5SDimitry Andric unsigned TargetFlags = get(MI.getOpcode()).TSFlags; 1491*0b57cec5SDimitry Andric if (HAS_NATIVE_OPERANDS(TargetFlags)) { 1492*0b57cec5SDimitry Andric MachineOperand &FlagOp = getFlagOp(MI, Operand, Flag); 1493*0b57cec5SDimitry Andric FlagOp.setImm(0); 1494*0b57cec5SDimitry Andric } else { 1495*0b57cec5SDimitry Andric MachineOperand &FlagOp = getFlagOp(MI); 1496*0b57cec5SDimitry Andric unsigned InstFlags = FlagOp.getImm(); 1497*0b57cec5SDimitry Andric InstFlags &= ~(Flag << (NUM_MO_FLAGS * Operand)); 1498*0b57cec5SDimitry Andric FlagOp.setImm(InstFlags); 1499*0b57cec5SDimitry Andric } 1500*0b57cec5SDimitry Andric } 1501*0b57cec5SDimitry Andric 1502*0b57cec5SDimitry Andric unsigned R600InstrInfo::getAddressSpaceForPseudoSourceKind( 1503*0b57cec5SDimitry Andric unsigned Kind) const { 1504*0b57cec5SDimitry Andric switch (Kind) { 1505*0b57cec5SDimitry Andric case PseudoSourceValue::Stack: 1506*0b57cec5SDimitry Andric case PseudoSourceValue::FixedStack: 1507*0b57cec5SDimitry Andric return AMDGPUAS::PRIVATE_ADDRESS; 1508*0b57cec5SDimitry Andric case PseudoSourceValue::ConstantPool: 1509*0b57cec5SDimitry Andric case PseudoSourceValue::GOT: 1510*0b57cec5SDimitry Andric case PseudoSourceValue::JumpTable: 1511*0b57cec5SDimitry Andric case PseudoSourceValue::GlobalValueCallEntry: 1512*0b57cec5SDimitry Andric case PseudoSourceValue::ExternalSymbolCallEntry: 1513*0b57cec5SDimitry Andric case PseudoSourceValue::TargetCustom: 1514*0b57cec5SDimitry Andric return AMDGPUAS::CONSTANT_ADDRESS; 1515*0b57cec5SDimitry Andric } 1516*0b57cec5SDimitry Andric 1517*0b57cec5SDimitry Andric llvm_unreachable("Invalid pseudo source kind"); 1518*0b57cec5SDimitry Andric } 1519