Home | History | Annotate | Download | only in radeon
      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