1 //===-- R600ISelDAGToDAG.cpp - A dag to dag inst selector for R600 --------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //==-----------------------------------------------------------------------===// 8 // 9 /// \file 10 /// Defines an instruction selector for the R600 subtarget. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "AMDGPU.h" 15 #include "AMDGPUISelDAGToDAG.h" 16 #include "MCTargetDesc/R600MCTargetDesc.h" 17 #include "R600.h" 18 #include "R600Subtarget.h" 19 20 using namespace llvm; 21 22 namespace { 23 class R600DAGToDAGISel : public AMDGPUDAGToDAGISel { 24 const R600Subtarget *Subtarget = nullptr; 25 26 bool isConstantLoad(const MemSDNode *N, int cbID) const; 27 bool SelectGlobalValueConstantOffset(SDValue Addr, SDValue &IntPtr); 28 bool SelectGlobalValueVariableOffset(SDValue Addr, SDValue &BaseReg, 29 SDValue &Offset); 30 31 public: 32 R600DAGToDAGISel() = delete; 33 34 explicit R600DAGToDAGISel(TargetMachine &TM, CodeGenOptLevel OptLevel) 35 : AMDGPUDAGToDAGISel(TM, OptLevel) {} 36 37 void Select(SDNode *N) override; 38 39 bool SelectADDRIndirect(SDValue Addr, SDValue &Base, 40 SDValue &Offset) override; 41 bool SelectADDRVTX_READ(SDValue Addr, SDValue &Base, 42 SDValue &Offset) override; 43 44 bool runOnMachineFunction(MachineFunction &MF) override; 45 46 void PreprocessISelDAG() override {} 47 48 protected: 49 // Include the pieces autogenerated from the target description. 50 #include "R600GenDAGISel.inc" 51 }; 52 53 class R600DAGToDAGISelLegacy : public SelectionDAGISelLegacy { 54 public: 55 static char ID; 56 explicit R600DAGToDAGISelLegacy(TargetMachine &TM, CodeGenOptLevel OptLevel) 57 : SelectionDAGISelLegacy( 58 ID, std::make_unique<R600DAGToDAGISel>(TM, OptLevel)) {} 59 }; 60 61 char R600DAGToDAGISelLegacy::ID = 0; 62 63 } // namespace 64 65 bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { 66 Subtarget = &MF.getSubtarget<R600Subtarget>(); 67 return SelectionDAGISel::runOnMachineFunction(MF); 68 } 69 70 bool R600DAGToDAGISel::isConstantLoad(const MemSDNode *N, int CbId) const { 71 if (!N->readMem()) 72 return false; 73 if (CbId == -1) 74 return N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS || 75 N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS_32BIT; 76 77 return N->getAddressSpace() == AMDGPUAS::CONSTANT_BUFFER_0 + CbId; 78 } 79 80 bool R600DAGToDAGISel::SelectGlobalValueConstantOffset(SDValue Addr, 81 SDValue &IntPtr) { 82 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Addr)) { 83 IntPtr = 84 CurDAG->getIntPtrConstant(Cst->getZExtValue() / 4, SDLoc(Addr), true); 85 return true; 86 } 87 return false; 88 } 89 90 bool R600DAGToDAGISel::SelectGlobalValueVariableOffset(SDValue Addr, 91 SDValue &BaseReg, 92 SDValue &Offset) { 93 if (!isa<ConstantSDNode>(Addr)) { 94 BaseReg = Addr; 95 Offset = CurDAG->getIntPtrConstant(0, SDLoc(Addr), true); 96 return true; 97 } 98 return false; 99 } 100 101 void R600DAGToDAGISel::Select(SDNode *N) { 102 unsigned int Opc = N->getOpcode(); 103 if (N->isMachineOpcode()) { 104 N->setNodeId(-1); 105 return; // Already selected. 106 } 107 108 switch (Opc) { 109 default: 110 break; 111 case AMDGPUISD::BUILD_VERTICAL_VECTOR: 112 case ISD::SCALAR_TO_VECTOR: 113 case ISD::BUILD_VECTOR: { 114 EVT VT = N->getValueType(0); 115 unsigned NumVectorElts = VT.getVectorNumElements(); 116 unsigned RegClassID; 117 // BUILD_VECTOR was lowered into an IMPLICIT_DEF + 4 INSERT_SUBREG 118 // that adds a 128 bits reg copy when going through TwoAddressInstructions 119 // pass. We want to avoid 128 bits copies as much as possible because they 120 // can't be bundled by our scheduler. 121 switch (NumVectorElts) { 122 case 2: 123 RegClassID = R600::R600_Reg64RegClassID; 124 break; 125 case 4: 126 if (Opc == AMDGPUISD::BUILD_VERTICAL_VECTOR) 127 RegClassID = R600::R600_Reg128VerticalRegClassID; 128 else 129 RegClassID = R600::R600_Reg128RegClassID; 130 break; 131 default: 132 llvm_unreachable("Do not know how to lower this BUILD_VECTOR"); 133 } 134 SelectBuildVector(N, RegClassID); 135 return; 136 } 137 } 138 139 SelectCode(N); 140 } 141 142 bool R600DAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base, 143 SDValue &Offset) { 144 ConstantSDNode *C; 145 SDLoc DL(Addr); 146 147 if ((C = dyn_cast<ConstantSDNode>(Addr))) { 148 Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32); 149 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32); 150 } else if ((Addr.getOpcode() == AMDGPUISD::DWORDADDR) && 151 (C = dyn_cast<ConstantSDNode>(Addr.getOperand(0)))) { 152 Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32); 153 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32); 154 } else if ((Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) && 155 (C = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))) { 156 Base = Addr.getOperand(0); 157 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32); 158 } else { 159 Base = Addr; 160 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32); 161 } 162 163 return true; 164 } 165 166 bool R600DAGToDAGISel::SelectADDRVTX_READ(SDValue Addr, SDValue &Base, 167 SDValue &Offset) { 168 ConstantSDNode *IMMOffset; 169 170 if (Addr.getOpcode() == ISD::ADD && 171 (IMMOffset = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) && 172 isInt<16>(IMMOffset->getZExtValue())) { 173 174 Base = Addr.getOperand(0); 175 Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr), 176 MVT::i32); 177 return true; 178 // If the pointer address is constant, we can move it to the offset field. 179 } 180 if ((IMMOffset = dyn_cast<ConstantSDNode>(Addr)) && 181 isInt<16>(IMMOffset->getZExtValue())) { 182 Base = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), 183 SDLoc(CurDAG->getEntryNode()), R600::ZERO, 184 MVT::i32); 185 Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr), 186 MVT::i32); 187 return true; 188 } 189 190 // Default case, no offset 191 Base = Addr; 192 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 193 return true; 194 } 195 196 /// This pass converts a legalized DAG into a R600-specific 197 // DAG, ready for instruction scheduling. 198 FunctionPass *llvm::createR600ISelDag(TargetMachine &TM, 199 CodeGenOptLevel OptLevel) { 200 return new R600DAGToDAGISelLegacy(TM, OptLevel); 201 } 202