1 //===-- R600KernelParameters.cpp - Lower kernel function arguments --------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This pass lowers kernel function arguments to loads from the vertex buffer.
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.
16 //===----------------------------------------------------------------------===//
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"
38 #define CONSTANT_CACHE_SIZE_DW 127
40 class R600KernelParameters : public FunctionPass {
46 Param() : Val(NULL), PtrVal(NULL), OffsetInDW(0), SizeInDW(0),
47 IsIndirect(true), SpecialID(0) {}
56 std::string SpecialType;
59 int End() { return OffsetInDW + SizeInDW; }
60 // The first 9 dwords are reserved for the grid sizes.
61 int getRatOffset() { return 9 + OffsetInDW; }
64 std::vector<Param> Params;
66 bool IsOpenCLKernel(const Function *Fun);
67 int getLastSpecialID(const std::string& TypeName);
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);
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);
92 char R600KernelParameters::ID = 0;
94 static RegisterPass<R600KernelParameters> X("kerparam",
95 "OpenCL Kernel Parameter conversion", false, false);
97 bool R600KernelParameters::IsOpenCLKernel(const Function* Fun) {
98 Module *Mod = const_cast<Function*>(Fun)->getParent();
99 NamedMDNode * MD = Mod->getOrInsertNamedMetadata("opencl.kernels");
101 if (!MD || !MD->getNumOperands()) {
105 for (int i = 0; i < int(MD->getNumOperands()); i++) {
106 if (!MD->getOperand(i) || !MD->getOperand(i)->getOperand(0)) {
110 assert(MD->getOperand(i)->getNumOperands() == 1);
112 if (MD->getOperand(i)->getOperand(0)->getName() == Fun->getName()) {
120 int R600KernelParameters::getLastSpecialID(const std::string &TypeName) {
123 for (std::vector<Param>::iterator i = Params.begin(); i != Params.end(); i++) {
124 if (i->SpecialType == TypeName) {
125 LastID = i->SpecialID;
132 int R600KernelParameters::getListSize() {
133 if (Params.size() == 0) {
137 return Params.back().End();
140 bool R600KernelParameters::IsIndirect(Value *Val, std::set<Value*> &Visited) {
141 //XXX Direct parameters are not supported yet, so return true here.
144 if (isa<LoadInst>(Val)) {
148 if (isa<IntegerType>(Val->getType())) {
149 assert(0 && "Internal error");
153 if (Visited.count(Val)) {
159 if (isa<getElementPtrInst>(Val)) {
160 getElementPtrInst* GEP = dyn_cast<getElementPtrInst>(Val);
161 getElementPtrInst::op_iterator I = GEP->op_begin();
163 for (++I; I != GEP->op_end(); ++I) {
164 if (!isa<Constant>(*I)) {
170 for (Value::use_iterator I = Val->use_begin(); i != Val->use_end(); ++I) {
171 Value* V2 = dyn_cast<Value>(*I);
174 if (IsIndirect(V2, Visited)) {
184 void R600KernelParameters::AddParam(Argument *Arg) {
187 P.Val = dyn_cast<Value>(Arg);
188 P.OffsetInDW = getListSize();
189 P.SizeInDW = CalculateArgumentSize(Arg);
191 if (isa<PointerType>(Arg->getType()) && Arg->hasByValAttr()) {
192 std::set<Value*> Visited;
193 P.IsIndirect = IsIndirect(P.Val, Visited);
199 int R600KernelParameters::CalculateArgumentSize(Argument *Arg) {
200 Type* T = Arg->getType();
202 if (Arg->hasByValAttr() && dyn_cast<PointerType>(T)) {
203 T = dyn_cast<PointerType>(T)->getElementType();
206 int StoreSizeInDW = (TD->getTypeStoreSize(T) + 3)/4;
208 assert(StoreSizeInDW);
210 return StoreSizeInDW;
214 void R600KernelParameters::RunAna(Function* Fun) {
215 assert(IsOpenCLKernel(Fun));
217 for (Function::arg_iterator I = Fun->arg_begin(); I != Fun->arg_end(); ++I) {
223 void R600KernelParameters::Replace(Function* Fun) {
224 for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
227 if (IsSpecialType(I->Val->getType())) {
228 NewVal = handleSpecial(Fun, *I);
230 NewVal = ConstantRead(Fun, *I);
233 I->Val->replaceAllUsesWith(NewVal);
238 void R600KernelParameters::Propagate(Function* Fun) {
239 for (std::vector<Param>::iterator I = Params.begin(); I != Params.end(); ++I) {
241 Propagate(I->PtrVal, I->Val->getName(), I->IsIndirect);
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);
253 Addrspace = AMDILAS::PARAM_I_ADDRESS;
255 Addrspace = AMDILAS::PARAM_D_ADDRESS;
258 if (GEP && GEP->getType()->getAddressSpace() != Addrspace) {
259 Value *Op = GEP->getPointerOperand();
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));
267 std::vector<Value*> Params(GEP->idx_begin(), GEP->idx_end());
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();
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());
284 Type* NewPtrType = PointerType::get(OrigPtrType->getElementType(),
287 Value* NewPtr = OrigPtr;
289 if (OrigPtr->getType() != NewPtrType) {
290 NewPtr = new BitCastInst(OrigPtr, NewPtrType, "prop_cast", Load);
293 Value* new_Load = new LoadInst(NewPtr, Name, Load);
294 Load->replaceAllUsesWith(new_Load);
295 Load->eraseFromParent();
301 std::vector<User*> Users(V->use_begin(), V->use_end());
303 for (int i = 0; i < int(Users.size()); i++) {
304 Value* V2 = dyn_cast<Value>(Users[i]);
307 Propagate(V2, Name, IsIndirect);
312 Value* R600KernelParameters::ConstantRead(Function *Fun, Param &P) {
313 assert(Fun->front().begin() != Fun->front().end());
315 Instruction *FirstInst = Fun->front().begin();
316 IRBuilder <> Builder (FirstInst);
317 /* First 3 dwords are reserved for the dimmension info */
319 if (!P.Val->hasNUsesOrMore(1)) {
325 Addrspace = AMDILAS::PARAM_I_ADDRESS;
327 Addrspace = AMDILAS::PARAM_D_ADDRESS;
330 Argument *Arg = dyn_cast<Argument>(P.Val);
331 Type * ArgType = P.Val->getType();
332 PointerType * ArgPtrType = dyn_cast<PointerType>(P.Val->getType());
334 if (ArgPtrType && Arg->hasByValAttr()) {
335 Value* ParamAddrSpacePtr = ConstantPointerNull::get(
336 PointerType::get(Type::getInt32Ty(*Context),
338 Value* ParamPtr = GetElementPtrInst::Create(ParamAddrSpacePtr,
339 ConstantInt::get(Type::getInt32Ty(*Context),
340 P.getRatOffset()), Arg->getName(),
342 ParamPtr = new BitCastInst(ParamPtr,
343 PointerType::get(ArgPtrType->getElementType(),
345 Arg->getName(), FirstInst);
349 Value *ParamAddrSpacePtr = ConstantPointerNull::get(PointerType::get(
350 ArgType, Addrspace));
352 Value *ParamPtr = Builder.CreateGEP(ParamAddrSpacePtr,
353 ConstantInt::get(Type::getInt32Ty(*Context), P.getRatOffset()),
356 Value *Param_Value = Builder.CreateLoad(ParamPtr, Arg->getName());
362 Value* R600KernelParameters::handleSpecial(Function* Fun, Param& P) {
363 std::string Name = getSpecialTypeName(P.Val->getType());
366 assert(!Name.empty());
368 if (Name == "image2d_t" || Name == "image3d_t") {
369 int LastID = std::max(getLastSpecialID("image2d_t"),
370 getLastSpecialID("image3d_t"));
373 ID = 2; ///ID0 and ID1 are used internally by the driver
377 } else if (Name == "sampler_t") {
378 int LastID = getLastSpecialID("sampler_t");
386 ///TODO: give some error message
390 P.SpecialType = Name;
393 Instruction *FirstInst = Fun->front().begin();
395 return new IntToPtrInst(ConstantInt::get(Type::getInt32Ty(*Context),
396 P.SpecialID), P.Val->getType(),
397 "resourceID", FirstInst);
401 bool R600KernelParameters::IsSpecialType(Type* T) {
402 return !getSpecialTypeName(T).empty();
405 std::string R600KernelParameters::getSpecialTypeName(Type* T) {
406 PointerType *PT = dyn_cast<PointerType>(T);
407 StructType *ST = NULL;
410 ST = dyn_cast<StructType>(PT->getElementType());
414 std::string Prefix = "struct.opencl_builtin_type_";
416 std::string Name = ST->getName().str();
418 if (Name.substr(0, Prefix.length()) == Prefix) {
419 return Name.substr(Prefix.length(), Name.length());
427 bool R600KernelParameters::runOnFunction (Function &F) {
428 if (!IsOpenCLKernel(&F)) {
439 void R600KernelParameters::getAnalysisUsage(AnalysisUsage &AU) const {
440 FunctionPass::getAnalysisUsage(AU);
441 AU.setPreservesAll();
444 const char *R600KernelParameters::getPassName() const {
445 return "OpenCL Kernel parameter conversion to memory";
448 bool R600KernelParameters::doInitialization(Module &M) {
449 Context = &M.getContext();
455 bool R600KernelParameters::doFinalization(Module &M) {
459 } // End anonymous namespace
461 FunctionPass* llvm::createR600KernelParametersPass(const TargetData* TD) {
462 return new R600KernelParameters(TD);