1349cc55cSDimitry Andric //===-- R600ISelDAGToDAG.cpp - A dag to dag inst selector for R600 --------===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //==-----------------------------------------------------------------------===// 8349cc55cSDimitry Andric // 9349cc55cSDimitry Andric /// \file 10349cc55cSDimitry Andric /// Defines an instruction selector for the R600 subtarget. 11349cc55cSDimitry Andric // 12349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 13349cc55cSDimitry Andric 14349cc55cSDimitry Andric #include "AMDGPU.h" 15349cc55cSDimitry Andric #include "AMDGPUISelDAGToDAG.h" 16349cc55cSDimitry Andric #include "MCTargetDesc/R600MCTargetDesc.h" 17349cc55cSDimitry Andric #include "R600.h" 18349cc55cSDimitry Andric #include "R600Subtarget.h" 19349cc55cSDimitry Andric #include "llvm/Analysis/ValueTracking.h" 20349cc55cSDimitry Andric 21bdd1243dSDimitry Andric namespace { 22349cc55cSDimitry Andric class R600DAGToDAGISel : public AMDGPUDAGToDAGISel { 2306c3fb27SDimitry Andric const R600Subtarget *Subtarget = nullptr; 24349cc55cSDimitry Andric 25349cc55cSDimitry Andric bool isConstantLoad(const MemSDNode *N, int cbID) const; 26349cc55cSDimitry Andric bool SelectGlobalValueConstantOffset(SDValue Addr, SDValue &IntPtr); 27349cc55cSDimitry Andric bool SelectGlobalValueVariableOffset(SDValue Addr, SDValue &BaseReg, 28349cc55cSDimitry Andric SDValue &Offset); 29349cc55cSDimitry Andric 30349cc55cSDimitry Andric public: 31bdd1243dSDimitry Andric R600DAGToDAGISel() = delete; 32bdd1243dSDimitry Andric 335f757f3fSDimitry Andric explicit R600DAGToDAGISel(TargetMachine &TM, CodeGenOptLevel OptLevel) 34349cc55cSDimitry Andric : AMDGPUDAGToDAGISel(TM, OptLevel) {} 35349cc55cSDimitry Andric 36349cc55cSDimitry Andric void Select(SDNode *N) override; 37349cc55cSDimitry Andric 38349cc55cSDimitry Andric bool SelectADDRIndirect(SDValue Addr, SDValue &Base, 39349cc55cSDimitry Andric SDValue &Offset) override; 40349cc55cSDimitry Andric bool SelectADDRVTX_READ(SDValue Addr, SDValue &Base, 41349cc55cSDimitry Andric SDValue &Offset) override; 42349cc55cSDimitry Andric 43349cc55cSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 44349cc55cSDimitry Andric 45349cc55cSDimitry Andric void PreprocessISelDAG() override {} 46349cc55cSDimitry Andric 47349cc55cSDimitry Andric protected: 48349cc55cSDimitry Andric // Include the pieces autogenerated from the target description. 49349cc55cSDimitry Andric #include "R600GenDAGISel.inc" 50349cc55cSDimitry Andric }; 51*0fca6ea1SDimitry Andric 52*0fca6ea1SDimitry Andric class R600DAGToDAGISelLegacy : public SelectionDAGISelLegacy { 53*0fca6ea1SDimitry Andric public: 54*0fca6ea1SDimitry Andric static char ID; 55*0fca6ea1SDimitry Andric explicit R600DAGToDAGISelLegacy(TargetMachine &TM, CodeGenOptLevel OptLevel) 56*0fca6ea1SDimitry Andric : SelectionDAGISelLegacy( 57*0fca6ea1SDimitry Andric ID, std::make_unique<R600DAGToDAGISel>(TM, OptLevel)) {} 58*0fca6ea1SDimitry Andric }; 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric char R600DAGToDAGISelLegacy::ID = 0; 61*0fca6ea1SDimitry Andric 62bdd1243dSDimitry Andric } // namespace 63349cc55cSDimitry Andric 64349cc55cSDimitry Andric bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { 65349cc55cSDimitry Andric Subtarget = &MF.getSubtarget<R600Subtarget>(); 66349cc55cSDimitry Andric return SelectionDAGISel::runOnMachineFunction(MF); 67349cc55cSDimitry Andric } 68349cc55cSDimitry Andric 69349cc55cSDimitry Andric bool R600DAGToDAGISel::isConstantLoad(const MemSDNode *N, int CbId) const { 70349cc55cSDimitry Andric if (!N->readMem()) 71349cc55cSDimitry Andric return false; 72349cc55cSDimitry Andric if (CbId == -1) 73349cc55cSDimitry Andric return N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS || 74349cc55cSDimitry Andric N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS_32BIT; 75349cc55cSDimitry Andric 76349cc55cSDimitry Andric return N->getAddressSpace() == AMDGPUAS::CONSTANT_BUFFER_0 + CbId; 77349cc55cSDimitry Andric } 78349cc55cSDimitry Andric 79349cc55cSDimitry Andric bool R600DAGToDAGISel::SelectGlobalValueConstantOffset(SDValue Addr, 80349cc55cSDimitry Andric SDValue &IntPtr) { 81349cc55cSDimitry Andric if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Addr)) { 82349cc55cSDimitry Andric IntPtr = 83349cc55cSDimitry Andric CurDAG->getIntPtrConstant(Cst->getZExtValue() / 4, SDLoc(Addr), true); 84349cc55cSDimitry Andric return true; 85349cc55cSDimitry Andric } 86349cc55cSDimitry Andric return false; 87349cc55cSDimitry Andric } 88349cc55cSDimitry Andric 89349cc55cSDimitry Andric bool R600DAGToDAGISel::SelectGlobalValueVariableOffset(SDValue Addr, 90349cc55cSDimitry Andric SDValue &BaseReg, 91349cc55cSDimitry Andric SDValue &Offset) { 92349cc55cSDimitry Andric if (!isa<ConstantSDNode>(Addr)) { 93349cc55cSDimitry Andric BaseReg = Addr; 94349cc55cSDimitry Andric Offset = CurDAG->getIntPtrConstant(0, SDLoc(Addr), true); 95349cc55cSDimitry Andric return true; 96349cc55cSDimitry Andric } 97349cc55cSDimitry Andric return false; 98349cc55cSDimitry Andric } 99349cc55cSDimitry Andric 100349cc55cSDimitry Andric void R600DAGToDAGISel::Select(SDNode *N) { 101349cc55cSDimitry Andric unsigned int Opc = N->getOpcode(); 102349cc55cSDimitry Andric if (N->isMachineOpcode()) { 103349cc55cSDimitry Andric N->setNodeId(-1); 104349cc55cSDimitry Andric return; // Already selected. 105349cc55cSDimitry Andric } 106349cc55cSDimitry Andric 107349cc55cSDimitry Andric switch (Opc) { 108349cc55cSDimitry Andric default: 109349cc55cSDimitry Andric break; 110349cc55cSDimitry Andric case AMDGPUISD::BUILD_VERTICAL_VECTOR: 111349cc55cSDimitry Andric case ISD::SCALAR_TO_VECTOR: 112349cc55cSDimitry Andric case ISD::BUILD_VECTOR: { 113349cc55cSDimitry Andric EVT VT = N->getValueType(0); 114349cc55cSDimitry Andric unsigned NumVectorElts = VT.getVectorNumElements(); 115349cc55cSDimitry Andric unsigned RegClassID; 116349cc55cSDimitry Andric // BUILD_VECTOR was lowered into an IMPLICIT_DEF + 4 INSERT_SUBREG 117349cc55cSDimitry Andric // that adds a 128 bits reg copy when going through TwoAddressInstructions 118349cc55cSDimitry Andric // pass. We want to avoid 128 bits copies as much as possible because they 119349cc55cSDimitry Andric // can't be bundled by our scheduler. 120349cc55cSDimitry Andric switch (NumVectorElts) { 121349cc55cSDimitry Andric case 2: 122349cc55cSDimitry Andric RegClassID = R600::R600_Reg64RegClassID; 123349cc55cSDimitry Andric break; 124349cc55cSDimitry Andric case 4: 125349cc55cSDimitry Andric if (Opc == AMDGPUISD::BUILD_VERTICAL_VECTOR) 126349cc55cSDimitry Andric RegClassID = R600::R600_Reg128VerticalRegClassID; 127349cc55cSDimitry Andric else 128349cc55cSDimitry Andric RegClassID = R600::R600_Reg128RegClassID; 129349cc55cSDimitry Andric break; 130349cc55cSDimitry Andric default: 131349cc55cSDimitry Andric llvm_unreachable("Do not know how to lower this BUILD_VECTOR"); 132349cc55cSDimitry Andric } 133349cc55cSDimitry Andric SelectBuildVector(N, RegClassID); 134349cc55cSDimitry Andric return; 135349cc55cSDimitry Andric } 136349cc55cSDimitry Andric } 137349cc55cSDimitry Andric 138349cc55cSDimitry Andric SelectCode(N); 139349cc55cSDimitry Andric } 140349cc55cSDimitry Andric 141349cc55cSDimitry Andric bool R600DAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base, 142349cc55cSDimitry Andric SDValue &Offset) { 143349cc55cSDimitry Andric ConstantSDNode *C; 144349cc55cSDimitry Andric SDLoc DL(Addr); 145349cc55cSDimitry Andric 146349cc55cSDimitry Andric if ((C = dyn_cast<ConstantSDNode>(Addr))) { 147349cc55cSDimitry Andric Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32); 148349cc55cSDimitry Andric Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32); 149349cc55cSDimitry Andric } else if ((Addr.getOpcode() == AMDGPUISD::DWORDADDR) && 150349cc55cSDimitry Andric (C = dyn_cast<ConstantSDNode>(Addr.getOperand(0)))) { 151349cc55cSDimitry Andric Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32); 152349cc55cSDimitry Andric Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32); 153349cc55cSDimitry Andric } else if ((Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) && 154349cc55cSDimitry Andric (C = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))) { 155349cc55cSDimitry Andric Base = Addr.getOperand(0); 156349cc55cSDimitry Andric Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32); 157349cc55cSDimitry Andric } else { 158349cc55cSDimitry Andric Base = Addr; 159349cc55cSDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, MVT::i32); 160349cc55cSDimitry Andric } 161349cc55cSDimitry Andric 162349cc55cSDimitry Andric return true; 163349cc55cSDimitry Andric } 164349cc55cSDimitry Andric 165349cc55cSDimitry Andric bool R600DAGToDAGISel::SelectADDRVTX_READ(SDValue Addr, SDValue &Base, 166349cc55cSDimitry Andric SDValue &Offset) { 167349cc55cSDimitry Andric ConstantSDNode *IMMOffset; 168349cc55cSDimitry Andric 169349cc55cSDimitry Andric if (Addr.getOpcode() == ISD::ADD && 170349cc55cSDimitry Andric (IMMOffset = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) && 171349cc55cSDimitry Andric isInt<16>(IMMOffset->getZExtValue())) { 172349cc55cSDimitry Andric 173349cc55cSDimitry Andric Base = Addr.getOperand(0); 174349cc55cSDimitry Andric Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr), 175349cc55cSDimitry Andric MVT::i32); 176349cc55cSDimitry Andric return true; 177349cc55cSDimitry Andric // If the pointer address is constant, we can move it to the offset field. 178*0fca6ea1SDimitry Andric } 179*0fca6ea1SDimitry Andric if ((IMMOffset = dyn_cast<ConstantSDNode>(Addr)) && 180349cc55cSDimitry Andric isInt<16>(IMMOffset->getZExtValue())) { 181349cc55cSDimitry Andric Base = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), 182349cc55cSDimitry Andric SDLoc(CurDAG->getEntryNode()), R600::ZERO, 183349cc55cSDimitry Andric MVT::i32); 184349cc55cSDimitry Andric Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr), 185349cc55cSDimitry Andric MVT::i32); 186349cc55cSDimitry Andric return true; 187349cc55cSDimitry Andric } 188349cc55cSDimitry Andric 189349cc55cSDimitry Andric // Default case, no offset 190349cc55cSDimitry Andric Base = Addr; 191349cc55cSDimitry Andric Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 192349cc55cSDimitry Andric return true; 193349cc55cSDimitry Andric } 194349cc55cSDimitry Andric 195349cc55cSDimitry Andric /// This pass converts a legalized DAG into a R600-specific 196349cc55cSDimitry Andric // DAG, ready for instruction scheduling. 197bdd1243dSDimitry Andric FunctionPass *llvm::createR600ISelDag(TargetMachine &TM, 1985f757f3fSDimitry Andric CodeGenOptLevel OptLevel) { 199*0fca6ea1SDimitry Andric return new R600DAGToDAGISelLegacy(TM, OptLevel); 200349cc55cSDimitry Andric } 201