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