• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
Param__anon2cd916a90111::R600KernelParameters::Param45     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 
End__anon2cd916a90111::R600KernelParameters::Param58     int End() { return OffsetInDW + SizeInDW; }
59     // The first 9 dwords are reserved for the grid sizes.
getRatOffset__anon2cd916a90111::R600KernelParameters::Param60     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;
R600KernelParameters()82   R600KernelParameters() : FunctionPass(ID) {};
R600KernelParameters(const TargetData * TD)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 
IsOpenCLKernel(const Function * Fun)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 
getLastSpecialID(const std::string & TypeName)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 
getListSize()131 int R600KernelParameters::getListSize() {
132   if (Params.size() == 0) {
133     return 0;
134   }
135 
136   return Params.back().End();
137 }
138 
IsIndirect(Value * Val,std::set<Value * > & Visited)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 
AddParam(Argument * Arg)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 
CalculateArgumentSize(Argument * Arg)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 
RunAna(Function * Fun)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 
Replace(Function * Fun)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 
Propagate(Function * Fun)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 
Propagate(Value * V,const Twine & Name,bool IsIndirect)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 
ConstantRead(Function * Fun,Param & P)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 
handleSpecial(Function * Fun,Param & P)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 
IsSpecialType(Type * T)400 bool R600KernelParameters::IsSpecialType(Type* T) {
401   return !getSpecialTypeName(T).empty();
402 }
403 
getSpecialTypeName(Type * T)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 
runOnFunction(Function & F)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 
getAnalysisUsage(AnalysisUsage & AU) const438 void R600KernelParameters::getAnalysisUsage(AnalysisUsage &AU) const {
439   FunctionPass::getAnalysisUsage(AU);
440   AU.setPreservesAll();
441 }
442 
getPassName() const443 const char *R600KernelParameters::getPassName() const {
444   return "OpenCL Kernel parameter conversion to memory";
445 }
446 
doInitialization(Module & M)447 bool R600KernelParameters::doInitialization(Module &M) {
448   Context = &M.getContext();
449   Mod = &M;
450 
451   return false;
452 }
453 
doFinalization(Module & M)454 bool R600KernelParameters::doFinalization(Module &M) {
455   return false;
456 }
457 
458 } // End anonymous namespace
459 
createR600KernelParametersPass(const TargetData * TD)460 FunctionPass* llvm::createR600KernelParametersPass(const TargetData* TD) {
461   return new R600KernelParameters(TD);
462 }
463