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