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