Home | History | Annotate | Download | only in radeon
      1 //===-- R600KernelParameters.cpp - Lower kernel function arguments --------===//
      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 pass lowers kernel function arguments to loads from the vertex buffer.
     11 //
     12 // Kernel arguemnts are stored in the vertex buffer at an offset of 9 dwords,
     13 // so arg0 needs to be loaded from VTX_BUFFER[9] and arg1 is loaded from
     14 // VTX_BUFFER[10], etc.
     15 //
     16 //===----------------------------------------------------------------------===//
     17 
     18 #include "AMDGPU.h"
     19 #include "AMDIL.h"
     20 #include "llvm/CodeGen/MachineFunctionPass.h"
     21 #include "llvm/Constants.h"
     22 #include "llvm/Function.h"
     23 #include "llvm/Intrinsics.h"
     24 #include "llvm/Metadata.h"
     25 #include "llvm/Module.h"
     26 #include "llvm/Target/TargetData.h"
     27 #include "llvm/Support/IRBuilder.h"
     28 #include "llvm/Support/TypeBuilder.h"
     29 
     30 #include <map>
     31 #include <set>
     32 
     33 using namespace llvm;
     34 
     35 namespace {
     36 
     37 #define CONSTANT_CACHE_SIZE_DW 127
     38 
     39 class R600KernelParameters : public FunctionPass {
     40   const TargetData *TD;
     41   LLVMContext* Context;
     42   Module *Mod;
     43 
     44   struct Param {
     45     Param() : Val(NULL), PtrVal(NULL), OffsetInDW(0), SizeInDW(0),
     46               IsIndirect(true), SpecialID(0) {}
     47 
     48     Value* Val;
     49     Value* PtrVal;
     50     int OffsetInDW;
     51     int SizeInDW;
     52 
     53     bool IsIndirect;
     54 
     55     std::string SpecialType;
     56     int SpecialID;
     57 
     58     int End() { return OffsetInDW + SizeInDW; }
     59     // The first 9 dwords are reserved for the grid sizes.
     60     int getRatOffset() { return 9 + OffsetInDW; }
     61   };
     62 
     63   std::vector<Param> Params;
     64 
     65   bool IsOpenCLKernel(const Function *Fun);
     66   int getLastSpecialID(const std::string& TypeName);
     67 
     68   int getListSize();
     69   void AddParam(Argument *Arg);
     70   int CalculateArgumentSize(Argument *Arg);
     71   void RunAna(Function *Fun);
     72   void Replace(Function *Fun);
     73   bool IsIndirect(Value *Val, std::set<Value*> &Visited);
     74   void Propagate(Function* Fun);
     75   void Propagate(Value *V, const Twine &Name, bool IsIndirect = true);
     76   Value* ConstantRead(Function *Fun, Param &P);
     77   Value* handleSpecial(Function *Fun, Param &P);
     78   bool IsSpecialType(Type *T);
     79   std::string getSpecialTypeName(Type *T);
     80 public:
     81   static char ID;
     82   R600KernelParameters() : FunctionPass(ID) {};
     83   R600KernelParameters(const TargetData* TD) : FunctionPass(ID), TD(TD) {}
     84   bool runOnFunction (Function &F);
     85   void getAnalysisUsage(AnalysisUsage &AU) const;
     86   const char *getPassName() const;
     87   bool doInitialization(Module &M);
     88   bool doFinalization(Module &M);
     89 };
     90 
     91 char R600KernelParameters::ID = 0;
     92 
     93 static RegisterPass<R600KernelParameters> X("kerparam",
     94                             "OpenCL Kernel Parameter conversion", false, false);
     95 
     96 bool R600KernelParameters::IsOpenCLKernel(const Function* Fun) {
     97   Module *Mod = const_cast<Function*>(Fun)->getParent();
     98   NamedMDNode * MD = Mod->getOrInsertNamedMetadata("opencl.kernels");
     99 
    100   if (!MD || !MD->getNumOperands()) {
    101     return false;
    102   }
    103 
    104   for (int i = 0; i < int(MD->getNumOperands()); i++) {
    105     if (!MD->getOperand(i) || !MD->getOperand(i)->getOperand(0)) {
    106       continue;
    107     }
    108 
    109     assert(MD->getOperand(i)->getNumOperands() == 1);
    110 
    111     if (MD->getOperand(i)->getOperand(0)->getName() == Fun->getName()) {
    112       return true;
    113     }
    114   }
    115 
    116   return false;
    117 }
    118 
    119 int R600KernelParameters::getLastSpecialID(const std::string &TypeName) {
    120   int LastID = -1;
    121 
    122   for (std::vector<Param>::iterator i = Params.begin(); i != Params.end(); i++) {
    123     if (i->SpecialType == TypeName) {
    124       LastID = i->SpecialID;
    125     }
    126   }
    127 
    128   return LastID;
    129 }
    130 
    131 int R600KernelParameters::getListSize() {
    132   if (Params.size() == 0) {
    133     return 0;
    134   }
    135 
    136   return Params.back().End();
    137 }
    138 
    139 bool R600KernelParameters::IsIndirect(Value *Val, std::set<Value*> &Visited) {
    140   //XXX Direct parameters are not supported yet, so return true here.
    141   return true;
    142 #if 0
    143   if (isa<LoadInst>(Val)) {
    144     return false;
    145   }
    146 
    147   if (isa<IntegerType>(Val->getType())) {
    148     assert(0 && "Internal error");
    149     return false;
    150   }
    151 
    152   if (Visited.count(Val)) {
    153     return false;
    154   }
    155 
    156   Visited.insert(Val);
    157 
    158   if (isa<getElementPtrInst>(Val)) {
    159     getElementPtrInst* GEP = dyn_cast<getElementPtrInst>(Val);
    160     getElementPtrInst::op_iterator I = GEP->op_begin();
    161 
    162     for (++I; I != GEP->op_end(); ++I) {
    163       if (!isa<Constant>(*I)) {
    164         return true;
    165       }
    166     }
    167   }
    168 
    169   for (Value::use_iterator I = Val->use_begin(); i != Val->use_end(); ++I) {
    170     Value* V2 = dyn_cast<Value>(*I);
    171 
    172     if (V2) {
    173       if (IsIndirect(V2, Visited)) {
    174         return true;
    175       }
    176     }
    177   }
    178 
    179   return false;
    180 #endif
    181 }
    182 
    183 void R600KernelParameters::AddParam(Argument *Arg) {
    184   Param P;
    185 
    186   P.Val = dyn_cast<Value>(Arg);
    187   P.OffsetInDW = getListSize();
    188   P.SizeInDW = CalculateArgumentSize(Arg);
    189 
    190   if (isa<PointerType>(Arg->getType()) && Arg->hasByValAttr()) {
    191     std::set<Value*> Visited;
    192     P.IsIndirect = IsIndirect(P.Val, Visited);
    193   }
    194 
    195   Params.push_back(P);
    196 }
    197 
    198 int R600KernelParameters::CalculateArgumentSize(Argument *Arg) {
    199   Type* T = Arg->getType();
    200 
    201   if (Arg->hasByValAttr() && dyn_cast<PointerType>(T)) {
    202     T = dyn_cast<PointerType>(T)->getElementType();
    203   }
    204 
    205   int StoreSizeInDW = (TD->getTypeStoreSize(T) + 3)/4;
    206 
    207   assert(StoreSizeInDW);
    208 
    209   return StoreSizeInDW;
    210 }
    211 
    212 
    213 void R600KernelParameters::RunAna(Function* Fun) {
    214   assert(IsOpenCLKernel(Fun));
    215 
    216   for (Function::arg_iterator I = Fun->arg_begin(); I != Fun->arg_end(); ++I) {
    217     AddParam(I);
    218   }
    219 
    220 }
    221 
    222 void R600KernelParameters::Replace(Function* Fun) {
    223   for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
    224     Value *NewVal;
    225 
    226     if (IsSpecialType(I->Val->getType())) {
    227       NewVal = handleSpecial(Fun, *I);
    228     } else {
    229       NewVal = ConstantRead(Fun, *I);
    230     }
    231     if (NewVal) {
    232       I->Val->replaceAllUsesWith(NewVal);
    233     }
    234   }
    235 }
    236 
    237 void R600KernelParameters::Propagate(Function* Fun) {
    238   for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
    239     if (I->PtrVal) {
    240       Propagate(I->PtrVal, I->Val->getName(), I->IsIndirect);
    241     }
    242   }
    243 }
    244 
    245 void R600KernelParameters::Propagate(Value* V, const Twine& Name, bool IsIndirect) {
    246   LoadInst* Load = dyn_cast<LoadInst>(V);
    247   GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V);
    248 
    249   unsigned Addrspace;
    250 
    251   if (IsIndirect) {
    252     Addrspace = AMDGPUAS::PARAM_I_ADDRESS;
    253   }  else {
    254     Addrspace = AMDGPUAS::PARAM_D_ADDRESS;
    255   }
    256 
    257   if (GEP && GEP->getType()->getAddressSpace() != Addrspace) {
    258     Value *Op = GEP->getPointerOperand();
    259 
    260     if (dyn_cast<PointerType>(Op->getType())->getAddressSpace() != Addrspace) {
    261       Op = new BitCastInst(Op, PointerType::get(dyn_cast<PointerType>(
    262                            Op->getType())->getElementType(), Addrspace),
    263                            Name, dyn_cast<Instruction>(V));
    264     }
    265 
    266     std::vector<Value*> Params(GEP->idx_begin(), GEP->idx_end());
    267 
    268     GetElementPtrInst* GEP2 = GetElementPtrInst::Create(Op, Params, Name,
    269                                                       dyn_cast<Instruction>(V));
    270     GEP2->setIsInBounds(GEP->isInBounds());
    271     V = dyn_cast<Value>(GEP2);
    272     GEP->replaceAllUsesWith(GEP2);
    273     GEP->eraseFromParent();
    274     Load = NULL;
    275   }
    276 
    277   if (Load) {
    278     ///normally at this point we have the right address space
    279     if (Load->getPointerAddressSpace() != Addrspace) {
    280       Value *OrigPtr = Load->getPointerOperand();
    281       PointerType *OrigPtrType = dyn_cast<PointerType>(OrigPtr->getType());
    282 
    283       Type* NewPtrType = PointerType::get(OrigPtrType->getElementType(),
    284                                             Addrspace);
    285 
    286       Value* NewPtr = OrigPtr;
    287 
    288       if (OrigPtr->getType() != NewPtrType) {
    289         NewPtr = new BitCastInst(OrigPtr, NewPtrType, "prop_cast", Load);
    290       }
    291 
    292       Value* new_Load = new LoadInst(NewPtr, Name, Load);
    293       Load->replaceAllUsesWith(new_Load);
    294       Load->eraseFromParent();
    295     }
    296 
    297     return;
    298   }
    299 
    300   std::vector<User*> Users(V->use_begin(), V->use_end());
    301 
    302   for (int i = 0; i < int(Users.size()); i++) {
    303     Value* V2 = dyn_cast<Value>(Users[i]);
    304 
    305     if (V2) {
    306       Propagate(V2, Name, IsIndirect);
    307     }
    308   }
    309 }
    310 
    311 Value* R600KernelParameters::ConstantRead(Function *Fun, Param &P) {
    312   assert(Fun->front().begin() != Fun->front().end());
    313 
    314   Instruction *FirstInst = Fun->front().begin();
    315   IRBuilder <> Builder (FirstInst);
    316 /* First 3 dwords are reserved for the dimmension info */
    317 
    318   if (!P.Val->hasNUsesOrMore(1)) {
    319     return NULL;
    320   }
    321   unsigned Addrspace;
    322 
    323   if (P.IsIndirect) {
    324     Addrspace = AMDGPUAS::PARAM_I_ADDRESS;
    325   } else {
    326     Addrspace = AMDGPUAS::PARAM_D_ADDRESS;
    327   }
    328 
    329   Argument *Arg = dyn_cast<Argument>(P.Val);
    330   Type * ArgType = P.Val->getType();
    331   PointerType * ArgPtrType = dyn_cast<PointerType>(P.Val->getType());
    332 
    333   if (ArgPtrType && Arg->hasByValAttr()) {
    334     Value* ParamAddrSpacePtr = ConstantPointerNull::get(
    335                                     PointerType::get(Type::getInt32Ty(*Context),
    336                                     Addrspace));
    337     Value* ParamPtr = GetElementPtrInst::Create(ParamAddrSpacePtr,
    338                                     ConstantInt::get(Type::getInt32Ty(*Context),
    339                                     P.getRatOffset()), Arg->getName(),
    340                                     FirstInst);
    341     ParamPtr = new BitCastInst(ParamPtr,
    342                                 PointerType::get(ArgPtrType->getElementType(),
    343                                                  Addrspace),
    344                                 Arg->getName(), FirstInst);
    345     P.PtrVal = ParamPtr;
    346     return ParamPtr;
    347   } else {
    348     Value *ParamAddrSpacePtr = ConstantPointerNull::get(PointerType::get(
    349                                                         ArgType, Addrspace));
    350 
    351     Value *ParamPtr = Builder.CreateGEP(ParamAddrSpacePtr,
    352              ConstantInt::get(Type::getInt32Ty(*Context), P.getRatOffset()),
    353                               Arg->getName());
    354 
    355     Value *Param_Value = Builder.CreateLoad(ParamPtr, Arg->getName());
    356 
    357     return Param_Value;
    358   }
    359 }
    360 
    361 Value* R600KernelParameters::handleSpecial(Function* Fun, Param& P) {
    362   std::string Name = getSpecialTypeName(P.Val->getType());
    363   int ID;
    364 
    365   assert(!Name.empty());
    366 
    367   if (Name == "image2d_t" || Name == "image3d_t") {
    368     int LastID = std::max(getLastSpecialID("image2d_t"),
    369                      getLastSpecialID("image3d_t"));
    370 
    371     if (LastID == -1) {
    372       ID = 2; ///ID0 and ID1 are used internally by the driver
    373     } else {
    374       ID = LastID + 1;
    375     }
    376   } else if (Name == "sampler_t") {
    377     int LastID = getLastSpecialID("sampler_t");
    378 
    379     if (LastID == -1) {
    380       ID = 0;
    381     } else {
    382       ID = LastID + 1;
    383     }
    384   } else {
    385     ///TODO: give some error message
    386     return NULL;
    387   }
    388 
    389   P.SpecialType = Name;
    390   P.SpecialID = ID;
    391 
    392   Instruction *FirstInst = Fun->front().begin();
    393 
    394   return new IntToPtrInst(ConstantInt::get(Type::getInt32Ty(*Context),
    395                                            P.SpecialID), P.Val->getType(),
    396                                            "resourceID", FirstInst);
    397 }
    398 
    399 
    400 bool R600KernelParameters::IsSpecialType(Type* T) {
    401   return !getSpecialTypeName(T).empty();
    402 }
    403 
    404 std::string R600KernelParameters::getSpecialTypeName(Type* T) {
    405   PointerType *PT = dyn_cast<PointerType>(T);
    406   StructType *ST = NULL;
    407 
    408   if (PT) {
    409     ST = dyn_cast<StructType>(PT->getElementType());
    410   }
    411 
    412   if (ST) {
    413     std::string Prefix = "struct.opencl_builtin_type_";
    414 
    415     std::string Name = ST->getName().str();
    416 
    417     if (Name.substr(0, Prefix.length()) == Prefix) {
    418       return Name.substr(Prefix.length(), Name.length());
    419     }
    420   }
    421 
    422   return "";
    423 }
    424 
    425 
    426 bool R600KernelParameters::runOnFunction (Function &F) {
    427   if (!IsOpenCLKernel(&F)) {
    428     return false;
    429   }
    430 
    431   RunAna(&F);
    432   Replace(&F);
    433   Propagate(&F);
    434 
    435   return false;
    436 }
    437 
    438 void R600KernelParameters::getAnalysisUsage(AnalysisUsage &AU) const {
    439   FunctionPass::getAnalysisUsage(AU);
    440   AU.setPreservesAll();
    441 }
    442 
    443 const char *R600KernelParameters::getPassName() const {
    444   return "OpenCL Kernel parameter conversion to memory";
    445 }
    446 
    447 bool R600KernelParameters::doInitialization(Module &M) {
    448   Context = &M.getContext();
    449   Mod = &M;
    450 
    451   return false;
    452 }
    453 
    454 bool R600KernelParameters::doFinalization(Module &M) {
    455   return false;
    456 }
    457 
    458 } // End anonymous namespace
    459 
    460 FunctionPass* llvm::createR600KernelParametersPass(const TargetData* TD) {
    461   return new R600KernelParameters(TD);
    462 }
    463