1 //===-- AMDILISelDAGToDAG.cpp - A dag to dag inst selector for AMDIL ------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //==-----------------------------------------------------------------------===// 9 // 10 // This file defines an instruction selector for the AMDIL target. 11 // 12 //===----------------------------------------------------------------------===// 13 #include "AMDGPUInstrInfo.h" 14 #include "AMDGPUISelLowering.h" // For AMDGPUISD 15 #include "AMDGPURegisterInfo.h" 16 #include "AMDILDevices.h" 17 #include "AMDILUtilityFunctions.h" 18 #include "llvm/ADT/ValueMap.h" 19 #include "llvm/CodeGen/PseudoSourceValue.h" 20 #include "llvm/CodeGen/SelectionDAGISel.h" 21 #include "llvm/Support/Compiler.h" 22 #include <list> 23 #include <queue> 24 25 using namespace llvm; 26 27 //===----------------------------------------------------------------------===// 28 // Instruction Selector Implementation 29 //===----------------------------------------------------------------------===// 30 31 //===----------------------------------------------------------------------===// 32 // AMDGPUDAGToDAGISel - AMDGPU specific code to select AMDGPU machine instructions 33 // //for SelectionDAG operations. 34 // 35 namespace { 36 class AMDGPUDAGToDAGISel : public SelectionDAGISel { 37 // Subtarget - Keep a pointer to the AMDGPU Subtarget around so that we can 38 // make the right decision when generating code for different targets. 39 const AMDGPUSubtarget &Subtarget; 40 public: 41 AMDGPUDAGToDAGISel(TargetMachine &TM); 42 virtual ~AMDGPUDAGToDAGISel(); 43 44 SDNode *Select(SDNode *N); 45 virtual const char *getPassName() const; 46 47 private: 48 inline SDValue getSmallIPtrImm(unsigned Imm); 49 50 // Complex pattern selectors 51 bool SelectADDRParam(SDValue Addr, SDValue& R1, SDValue& R2); 52 bool SelectADDR(SDValue N, SDValue &R1, SDValue &R2); 53 bool SelectADDR64(SDValue N, SDValue &R1, SDValue &R2); 54 55 static bool checkType(const Value *ptr, unsigned int addrspace); 56 static const Value *getBasePointerValue(const Value *V); 57 58 static bool isGlobalStore(const StoreSDNode *N); 59 static bool isPrivateStore(const StoreSDNode *N); 60 static bool isLocalStore(const StoreSDNode *N); 61 static bool isRegionStore(const StoreSDNode *N); 62 63 static bool isCPLoad(const LoadSDNode *N); 64 static bool isConstantLoad(const LoadSDNode *N, int cbID); 65 static bool isGlobalLoad(const LoadSDNode *N); 66 static bool isPrivateLoad(const LoadSDNode *N); 67 static bool isLocalLoad(const LoadSDNode *N); 68 static bool isRegionLoad(const LoadSDNode *N); 69 70 bool SelectADDR8BitOffset(SDValue Addr, SDValue& Base, SDValue& Offset); 71 bool SelectADDRReg(SDValue Addr, SDValue& Base, SDValue& Offset); 72 bool SelectADDRVTX_READ(SDValue Addr, SDValue &Base, SDValue &Offset); 73 74 // Include the pieces autogenerated from the target description. 75 #include "AMDGPUGenDAGISel.inc" 76 }; 77 } // end anonymous namespace 78 79 // createAMDGPUISelDag - This pass converts a legalized DAG into a AMDGPU-specific 80 // DAG, ready for instruction scheduling. 81 // 82 FunctionPass *llvm::createAMDGPUISelDag(TargetMachine &TM 83 ) { 84 return new AMDGPUDAGToDAGISel(TM); 85 } 86 87 AMDGPUDAGToDAGISel::AMDGPUDAGToDAGISel(TargetMachine &TM 88 ) 89 : SelectionDAGISel(TM), Subtarget(TM.getSubtarget<AMDGPUSubtarget>()) 90 { 91 } 92 93 AMDGPUDAGToDAGISel::~AMDGPUDAGToDAGISel() { 94 } 95 96 SDValue AMDGPUDAGToDAGISel::getSmallIPtrImm(unsigned int Imm) { 97 return CurDAG->getTargetConstant(Imm, MVT::i32); 98 } 99 100 bool AMDGPUDAGToDAGISel::SelectADDRParam( 101 SDValue Addr, SDValue& R1, SDValue& R2) { 102 103 if (Addr.getOpcode() == ISD::FrameIndex) { 104 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 105 R1 = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 106 R2 = CurDAG->getTargetConstant(0, MVT::i32); 107 } else { 108 R1 = Addr; 109 R2 = CurDAG->getTargetConstant(0, MVT::i32); 110 } 111 } else if (Addr.getOpcode() == ISD::ADD) { 112 R1 = Addr.getOperand(0); 113 R2 = Addr.getOperand(1); 114 } else { 115 R1 = Addr; 116 R2 = CurDAG->getTargetConstant(0, MVT::i32); 117 } 118 return true; 119 } 120 121 bool AMDGPUDAGToDAGISel::SelectADDR(SDValue Addr, SDValue& R1, SDValue& R2) { 122 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 123 Addr.getOpcode() == ISD::TargetGlobalAddress) { 124 return false; 125 } 126 return SelectADDRParam(Addr, R1, R2); 127 } 128 129 130 bool AMDGPUDAGToDAGISel::SelectADDR64(SDValue Addr, SDValue& R1, SDValue& R2) { 131 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 132 Addr.getOpcode() == ISD::TargetGlobalAddress) { 133 return false; 134 } 135 136 if (Addr.getOpcode() == ISD::FrameIndex) { 137 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 138 R1 = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); 139 R2 = CurDAG->getTargetConstant(0, MVT::i64); 140 } else { 141 R1 = Addr; 142 R2 = CurDAG->getTargetConstant(0, MVT::i64); 143 } 144 } else if (Addr.getOpcode() == ISD::ADD) { 145 R1 = Addr.getOperand(0); 146 R2 = Addr.getOperand(1); 147 } else { 148 R1 = Addr; 149 R2 = CurDAG->getTargetConstant(0, MVT::i64); 150 } 151 return true; 152 } 153 154 SDNode *AMDGPUDAGToDAGISel::Select(SDNode *N) { 155 unsigned int Opc = N->getOpcode(); 156 if (N->isMachineOpcode()) { 157 return NULL; // Already selected. 158 } 159 switch (Opc) { 160 default: break; 161 case ISD::FrameIndex: 162 { 163 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) { 164 unsigned int FI = FIN->getIndex(); 165 EVT OpVT = N->getValueType(0); 166 unsigned int NewOpc = AMDGPU::COPY; 167 SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); 168 return CurDAG->SelectNodeTo(N, NewOpc, OpVT, TFI); 169 } 170 } 171 break; 172 } 173 return SelectCode(N); 174 } 175 176 bool AMDGPUDAGToDAGISel::checkType(const Value *ptr, unsigned int addrspace) { 177 if (!ptr) { 178 return false; 179 } 180 Type *ptrType = ptr->getType(); 181 return dyn_cast<PointerType>(ptrType)->getAddressSpace() == addrspace; 182 } 183 184 const Value * AMDGPUDAGToDAGISel::getBasePointerValue(const Value *V) 185 { 186 if (!V) { 187 return NULL; 188 } 189 const Value *ret = NULL; 190 ValueMap<const Value *, bool> ValueBitMap; 191 std::queue<const Value *, std::list<const Value *> > ValueQueue; 192 ValueQueue.push(V); 193 while (!ValueQueue.empty()) { 194 V = ValueQueue.front(); 195 if (ValueBitMap.find(V) == ValueBitMap.end()) { 196 ValueBitMap[V] = true; 197 if (dyn_cast<Argument>(V) && dyn_cast<PointerType>(V->getType())) { 198 ret = V; 199 break; 200 } else if (dyn_cast<GlobalVariable>(V)) { 201 ret = V; 202 break; 203 } else if (dyn_cast<Constant>(V)) { 204 const ConstantExpr *CE = dyn_cast<ConstantExpr>(V); 205 if (CE) { 206 ValueQueue.push(CE->getOperand(0)); 207 } 208 } else if (const AllocaInst *AI = dyn_cast<AllocaInst>(V)) { 209 ret = AI; 210 break; 211 } else if (const Instruction *I = dyn_cast<Instruction>(V)) { 212 uint32_t numOps = I->getNumOperands(); 213 for (uint32_t x = 0; x < numOps; ++x) { 214 ValueQueue.push(I->getOperand(x)); 215 } 216 } else { 217 // assert(0 && "Found a Value that we didn't know how to handle!"); 218 } 219 } 220 ValueQueue.pop(); 221 } 222 return ret; 223 } 224 225 bool AMDGPUDAGToDAGISel::isGlobalStore(const StoreSDNode *N) { 226 return checkType(N->getSrcValue(), AMDGPUAS::GLOBAL_ADDRESS); 227 } 228 229 bool AMDGPUDAGToDAGISel::isPrivateStore(const StoreSDNode *N) { 230 return (!checkType(N->getSrcValue(), AMDGPUAS::LOCAL_ADDRESS) 231 && !checkType(N->getSrcValue(), AMDGPUAS::GLOBAL_ADDRESS) 232 && !checkType(N->getSrcValue(), AMDGPUAS::REGION_ADDRESS)); 233 } 234 235 bool AMDGPUDAGToDAGISel::isLocalStore(const StoreSDNode *N) { 236 return checkType(N->getSrcValue(), AMDGPUAS::LOCAL_ADDRESS); 237 } 238 239 bool AMDGPUDAGToDAGISel::isRegionStore(const StoreSDNode *N) { 240 return checkType(N->getSrcValue(), AMDGPUAS::REGION_ADDRESS); 241 } 242 243 bool AMDGPUDAGToDAGISel::isConstantLoad(const LoadSDNode *N, int cbID) { 244 if (checkType(N->getSrcValue(), AMDGPUAS::CONSTANT_ADDRESS)) { 245 return true; 246 } 247 MachineMemOperand *MMO = N->getMemOperand(); 248 const Value *V = MMO->getValue(); 249 const Value *BV = getBasePointerValue(V); 250 if (MMO 251 && MMO->getValue() 252 && ((V && dyn_cast<GlobalValue>(V)) 253 || (BV && dyn_cast<GlobalValue>( 254 getBasePointerValue(MMO->getValue()))))) { 255 return checkType(N->getSrcValue(), AMDGPUAS::PRIVATE_ADDRESS); 256 } else { 257 return false; 258 } 259 } 260 261 bool AMDGPUDAGToDAGISel::isGlobalLoad(const LoadSDNode *N) { 262 return checkType(N->getSrcValue(), AMDGPUAS::GLOBAL_ADDRESS); 263 } 264 265 bool AMDGPUDAGToDAGISel::isLocalLoad(const LoadSDNode *N) { 266 return checkType(N->getSrcValue(), AMDGPUAS::LOCAL_ADDRESS); 267 } 268 269 bool AMDGPUDAGToDAGISel::isRegionLoad(const LoadSDNode *N) { 270 return checkType(N->getSrcValue(), AMDGPUAS::REGION_ADDRESS); 271 } 272 273 bool AMDGPUDAGToDAGISel::isCPLoad(const LoadSDNode *N) { 274 MachineMemOperand *MMO = N->getMemOperand(); 275 if (checkType(N->getSrcValue(), AMDGPUAS::PRIVATE_ADDRESS)) { 276 if (MMO) { 277 const Value *V = MMO->getValue(); 278 const PseudoSourceValue *PSV = dyn_cast<PseudoSourceValue>(V); 279 if (PSV && PSV == PseudoSourceValue::getConstantPool()) { 280 return true; 281 } 282 } 283 } 284 return false; 285 } 286 287 bool AMDGPUDAGToDAGISel::isPrivateLoad(const LoadSDNode *N) { 288 if (checkType(N->getSrcValue(), AMDGPUAS::PRIVATE_ADDRESS)) { 289 // Check to make sure we are not a constant pool load or a constant load 290 // that is marked as a private load 291 if (isCPLoad(N) || isConstantLoad(N, -1)) { 292 return false; 293 } 294 } 295 if (!checkType(N->getSrcValue(), AMDGPUAS::LOCAL_ADDRESS) 296 && !checkType(N->getSrcValue(), AMDGPUAS::GLOBAL_ADDRESS) 297 && !checkType(N->getSrcValue(), AMDGPUAS::REGION_ADDRESS) 298 && !checkType(N->getSrcValue(), AMDGPUAS::CONSTANT_ADDRESS) 299 && !checkType(N->getSrcValue(), AMDGPUAS::PARAM_D_ADDRESS) 300 && !checkType(N->getSrcValue(), AMDGPUAS::PARAM_I_ADDRESS)) 301 { 302 return true; 303 } 304 return false; 305 } 306 307 const char *AMDGPUDAGToDAGISel::getPassName() const { 308 return "AMDGPU DAG->DAG Pattern Instruction Selection"; 309 } 310 311 #ifdef DEBUGTMP 312 #undef INT64_C 313 #endif 314 #undef DEBUGTMP 315 316 ///==== AMDGPU Functions ====/// 317 318 bool AMDGPUDAGToDAGISel::SelectADDR8BitOffset(SDValue Addr, SDValue& Base, 319 SDValue& Offset) { 320 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 321 Addr.getOpcode() == ISD::TargetGlobalAddress) { 322 return false; 323 } 324 325 326 if (Addr.getOpcode() == ISD::ADD) { 327 bool Match = false; 328 329 // Find the base ptr and the offset 330 for (unsigned i = 0; i < Addr.getNumOperands(); i++) { 331 SDValue Arg = Addr.getOperand(i); 332 ConstantSDNode * OffsetNode = dyn_cast<ConstantSDNode>(Arg); 333 // This arg isn't a constant so it must be the base PTR. 334 if (!OffsetNode) { 335 Base = Addr.getOperand(i); 336 continue; 337 } 338 // Check if the constant argument fits in 8-bits. The offset is in bytes 339 // so we need to convert it to dwords. 340 if (isInt<8>(OffsetNode->getZExtValue() >> 2)) { 341 Match = true; 342 Offset = CurDAG->getTargetConstant(OffsetNode->getZExtValue() >> 2, 343 MVT::i32); 344 } 345 } 346 return Match; 347 } 348 349 // Default case, no offset 350 Base = Addr; 351 Offset = CurDAG->getTargetConstant(0, MVT::i32); 352 return true; 353 } 354 355 bool AMDGPUDAGToDAGISel::SelectADDRVTX_READ(SDValue Addr, SDValue &Base, 356 SDValue &Offset) 357 { 358 ConstantSDNode * IMMOffset; 359 360 if (Addr.getOpcode() == ISD::ADD 361 && (IMMOffset = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) 362 && isInt<16>(IMMOffset->getZExtValue())) { 363 364 Base = Addr.getOperand(0); 365 Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), MVT::i32); 366 return true; 367 // If the pointer address is constant, we can move it to the offset field. 368 } else if ((IMMOffset = dyn_cast<ConstantSDNode>(Addr)) 369 && isInt<16>(IMMOffset->getZExtValue())) { 370 Base = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), 371 CurDAG->getEntryNode().getDebugLoc(), 372 AMDGPU::ZERO, MVT::i32); 373 Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), MVT::i32); 374 return true; 375 } 376 377 // Default case, no offset 378 Base = Addr; 379 Offset = CurDAG->getTargetConstant(0, MVT::i32); 380 return true; 381 } 382 383 bool AMDGPUDAGToDAGISel::SelectADDRReg(SDValue Addr, SDValue& Base, 384 SDValue& Offset) { 385 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 386 Addr.getOpcode() == ISD::TargetGlobalAddress || 387 Addr.getOpcode() != ISD::ADD) { 388 return false; 389 } 390 391 Base = Addr.getOperand(0); 392 Offset = Addr.getOperand(1); 393 394 return true; 395 } 396