R600KernelParameters.cpp revision a75c6163e605f35b14f26930dd9227e4f337ec9e
1//===-- R600KernelParameters.cpp - TODO: Add brief description -------===// 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// TODO: Add full description 11// 12//===----------------------------------------------------------------------===// 13 14#include <llvm-c/Core.h> 15#include "R600KernelParameters.h" 16#include "R600OpenCLUtils.h" 17#include "llvm/Constants.h" 18#include "llvm/Intrinsics.h" 19#include "llvm/Support/IRBuilder.h" 20#include "llvm/Support/TypeBuilder.h" 21// #include "llvm/CodeGen/Function.h" 22 23namespace AMDILAS { 24enum AddressSpaces { 25 PRIVATE_ADDRESS = 0, // Address space for private memory. 26 GLOBAL_ADDRESS = 1, // Address space for global memory (RAT0, VTX0). 27 CONSTANT_ADDRESS = 2, // Address space for constant memory. 28 LOCAL_ADDRESS = 3, // Address space for local memory. 29 REGION_ADDRESS = 4, // Address space for region memory. 30 ADDRESS_NONE = 5, // Address space for unknown memory. 31 PARAM_D_ADDRESS = 6, // Address space for direct addressible parameter memory (CONST0) 32 PARAM_I_ADDRESS = 7, // Address space for indirect addressible parameter memory (VTX1) 33 LAST_ADDRESS = 8 34}; 35} 36 37 38#include <map> 39#include <set> 40 41using namespace llvm; 42using namespace std; 43 44#define CONSTANT_CACHE_SIZE_DW 127 45 46class R600KernelParameters : public llvm::FunctionPass 47{ 48 const llvm::TargetData * TD; 49 LLVMContext* Context; 50 Module *mod; 51 52 struct param 53 { 54 param() : val(NULL), ptr_val(NULL), offset_in_dw(0), size_in_dw(0), indirect(false), specialID(0) {} 55 56 llvm::Value* val; 57 llvm::Value* ptr_val; 58 int offset_in_dw; 59 int size_in_dw; 60 61 bool indirect; 62 63 string specialType; 64 int specialID; 65 66 int end() { return offset_in_dw + size_in_dw; } 67 /* The first 9 dwords are reserved for the grid sizes. */ 68 int get_rat_offset() { return 9 + offset_in_dw; } 69 }; 70 71 std::vector<param> params; 72 73 int getLastSpecialID(const string& TypeName); 74 75 int getListSize(); 76 void AddParam(llvm::Argument* arg); 77 int calculateArgumentSize(llvm::Argument* arg); 78 void RunAna(llvm::Function* fun); 79 void Replace(llvm::Function* fun); 80 bool isIndirect(Value* val, set<Value*>& visited); 81 void Propagate(llvm::Function* fun); 82 void Propagate(llvm::Value* v, const llvm::Twine& name, bool indirect = false); 83 Value* ConstantRead(Function* fun, param& p); 84 Value* handleSpecial(Function* fun, param& p); 85 bool isSpecialType(Type*); 86 string getSpecialTypeName(Type*); 87public: 88 static char ID; 89 R600KernelParameters() : FunctionPass(ID) {}; 90 R600KernelParameters(const llvm::TargetData* TD) : FunctionPass(ID), TD(TD) {} 91// bool runOnFunction (llvm::Function &F); 92 bool runOnFunction (llvm::Function &F); 93 void getAnalysisUsage(AnalysisUsage &AU) const; 94 const char *getPassName() const; 95 bool doInitialization(Module &M); 96 bool doFinalization(Module &M); 97}; 98 99char R600KernelParameters::ID = 0; 100 101static RegisterPass<R600KernelParameters> X("kerparam", "OpenCL Kernel Parameter conversion", false, false); 102 103int R600KernelParameters::getLastSpecialID(const string& TypeName) 104{ 105 int lastID = -1; 106 107 for (vector<param>::iterator i = params.begin(); i != params.end(); i++) 108 { 109 if (i->specialType == TypeName) 110 { 111 lastID = i->specialID; 112 } 113 } 114 115 return lastID; 116} 117 118int R600KernelParameters::getListSize() 119{ 120 if (params.size() == 0) 121 { 122 return 0; 123 } 124 125 return params.back().end(); 126} 127 128bool R600KernelParameters::isIndirect(Value* val, set<Value*>& visited) 129{ 130 if (isa<LoadInst>(val)) 131 { 132 return false; 133 } 134 135 if (isa<IntegerType>(val->getType())) 136 { 137 assert(0 and "Internal error"); 138 return false; 139 } 140 141 if (visited.count(val)) 142 { 143 return false; 144 } 145 146 visited.insert(val); 147 148 if (isa<GetElementPtrInst>(val)) 149 { 150 GetElementPtrInst* GEP = dyn_cast<GetElementPtrInst>(val); 151 GetElementPtrInst::op_iterator i = GEP->op_begin(); 152 153 for (i++; i != GEP->op_end(); i++) 154 { 155 if (!isa<Constant>(*i)) 156 { 157 return true; 158 } 159 } 160 } 161 162 for (Value::use_iterator i = val->use_begin(); i != val->use_end(); i++) 163 { 164 Value* v2 = dyn_cast<Value>(*i); 165 166 if (v2) 167 { 168 if (isIndirect(v2, visited)) 169 { 170 return true; 171 } 172 } 173 } 174 175 return false; 176} 177 178void R600KernelParameters::AddParam(llvm::Argument* arg) 179{ 180 param p; 181 182 p.val = dyn_cast<Value>(arg); 183 p.offset_in_dw = getListSize(); 184 p.size_in_dw = calculateArgumentSize(arg); 185 186 if (isa<PointerType>(arg->getType()) and arg->hasByValAttr()) 187 { 188 set<Value*> visited; 189 p.indirect = isIndirect(p.val, visited); 190 } 191 192 params.push_back(p); 193} 194 195int R600KernelParameters::calculateArgumentSize(llvm::Argument* arg) 196{ 197 Type* t = arg->getType(); 198 199 if (arg->hasByValAttr() and dyn_cast<PointerType>(t)) 200 { 201 t = dyn_cast<PointerType>(t)->getElementType(); 202 } 203 204 int store_size_in_dw = (TD->getTypeStoreSize(t) + 3)/4; 205 206 assert(store_size_in_dw); 207 208 return store_size_in_dw; 209} 210 211 212void R600KernelParameters::RunAna(llvm::Function* fun) 213{ 214 assert(isOpenCLKernel(fun)); 215 216 for (Function::arg_iterator i = fun->arg_begin(); i != fun->arg_end(); i++) 217 { 218 AddParam(i); 219 } 220 221} 222 223void R600KernelParameters::Replace(llvm::Function* fun) 224{ 225 for (std::vector<param>::iterator i = params.begin(); i != params.end(); i++) 226 { 227 Value *new_val; 228 229 if (isSpecialType(i->val->getType())) 230 { 231 new_val = handleSpecial(fun, *i); 232 } 233 else 234 { 235 new_val = ConstantRead(fun, *i); 236 } 237 if (new_val) 238 { 239 i->val->replaceAllUsesWith(new_val); 240 } 241 } 242} 243 244void R600KernelParameters::Propagate(llvm::Function* fun) 245{ 246 for (std::vector<param>::iterator i = params.begin(); i != params.end(); i++) 247 { 248 if (i->ptr_val) 249 { 250 Propagate(i->ptr_val, i->val->getName(), i->indirect); 251 } 252 } 253} 254 255void R600KernelParameters::Propagate(Value* v, const Twine& name, bool indirect) 256{ 257 LoadInst* load = dyn_cast<LoadInst>(v); 258 GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(v); 259 260 unsigned addrspace; 261 262 if (indirect) 263 { 264 addrspace = AMDILAS::PARAM_I_ADDRESS; 265 } 266 else 267 { 268 addrspace = AMDILAS::PARAM_D_ADDRESS; 269 } 270 271 if (GEP and GEP->getType()->getAddressSpace() != addrspace) 272 { 273 Value* op = GEP->getPointerOperand(); 274 275 if (dyn_cast<PointerType>(op->getType())->getAddressSpace() != addrspace) 276 { 277 op = new BitCastInst(op, PointerType::get(dyn_cast<PointerType>(op->getType())->getElementType(), addrspace), name, dyn_cast<Instruction>(v)); 278 } 279 280 vector<Value*> params(GEP->idx_begin(), GEP->idx_end()); 281 282 GetElementPtrInst* GEP2 = GetElementPtrInst::Create(op, params, name, dyn_cast<Instruction>(v)); 283 GEP2->setIsInBounds(GEP->isInBounds()); 284 v = dyn_cast<Value>(GEP2); 285 GEP->replaceAllUsesWith(GEP2); 286 GEP->eraseFromParent(); 287 load = NULL; 288 } 289 290 if (load) 291 { 292 if (load->getPointerAddressSpace() != addrspace) ///normally at this point we have the right address space 293 { 294 Value *orig_ptr = load->getPointerOperand(); 295 PointerType *orig_ptr_type = dyn_cast<PointerType>(orig_ptr->getType()); 296 297 Type* new_ptr_type = PointerType::get(orig_ptr_type->getElementType(), addrspace); 298 299 Value* new_ptr = orig_ptr; 300 301 if (orig_ptr->getType() != new_ptr_type) 302 { 303 new_ptr = new BitCastInst(orig_ptr, new_ptr_type, "prop_cast", load); 304 } 305 306 Value* new_load = new LoadInst(new_ptr, name, load); 307 load->replaceAllUsesWith(new_load); 308 load->eraseFromParent(); 309 } 310 311 return; 312 } 313 314 vector<User*> users(v->use_begin(), v->use_end()); 315 316 for (int i = 0; i < int(users.size()); i++) 317 { 318 Value* v2 = dyn_cast<Value>(users[i]); 319 320 if (v2) 321 { 322 Propagate(v2, name, indirect); 323 } 324 } 325} 326 327Value* R600KernelParameters::ConstantRead(Function* fun, param& p) 328{ 329 assert(fun->front().begin() != fun->front().end()); 330 331 Instruction *first_inst = fun->front().begin(); 332 IRBuilder <> builder (first_inst); 333/* First 3 dwords are reserved for the dimmension info */ 334 335 if (!p.val->hasNUsesOrMore(1)) 336 { 337 return NULL; 338 } 339 unsigned addrspace; 340 341 if (p.indirect) 342 { 343 addrspace = AMDILAS::PARAM_I_ADDRESS; 344 } 345 else 346 { 347 addrspace = AMDILAS::PARAM_D_ADDRESS; 348 } 349 350 Argument *arg = dyn_cast<Argument>(p.val); 351 Type * argType = p.val->getType(); 352 PointerType * argPtrType = dyn_cast<PointerType>(p.val->getType()); 353 354 if (argPtrType and arg->hasByValAttr()) 355 { 356 Value* param_addr_space_ptr = ConstantPointerNull::get(PointerType::get(Type::getInt32Ty(*Context), addrspace)); 357 Value* param_ptr = GetElementPtrInst::Create(param_addr_space_ptr, ConstantInt::get(Type::getInt32Ty(*Context), p.get_rat_offset()), arg->getName(), first_inst); 358 param_ptr = new BitCastInst(param_ptr, PointerType::get(argPtrType->getElementType(), addrspace), arg->getName(), first_inst); 359 p.ptr_val = param_ptr; 360 return param_ptr; 361 } 362 else 363 { 364 Value* param_addr_space_ptr = ConstantPointerNull::get(PointerType::get(argType, addrspace)); 365 366 Value* param_ptr = builder.CreateGEP(param_addr_space_ptr, 367 ConstantInt::get(Type::getInt32Ty(*Context), p.get_rat_offset()), arg->getName()); 368 369 Value* param_value = builder.CreateLoad(param_ptr, arg->getName()); 370 371 return param_value; 372 } 373} 374 375Value* R600KernelParameters::handleSpecial(Function* fun, param& p) 376{ 377 string name = getSpecialTypeName(p.val->getType()); 378 int ID; 379 380 assert(!name.empty()); 381 382 if (name == "image2d_t" or name == "image3d_t") 383 { 384 int lastID = max(getLastSpecialID("image2d_t"), getLastSpecialID("image3d_t")); 385 386 if (lastID == -1) 387 { 388 ID = 2; ///ID0 and ID1 are used internally by the driver 389 } 390 else 391 { 392 ID = lastID + 1; 393 } 394 } 395 else if (name == "sampler_t") 396 { 397 int lastID = getLastSpecialID("sampler_t"); 398 399 if (lastID == -1) 400 { 401 ID = 0; 402 } 403 else 404 { 405 ID = lastID + 1; 406 } 407 } 408 else 409 { 410 ///TODO: give some error message 411 return NULL; 412 } 413 414 p.specialType = name; 415 p.specialID = ID; 416 417 Instruction *first_inst = fun->front().begin(); 418 419 return new IntToPtrInst(ConstantInt::get(Type::getInt32Ty(*Context), p.specialID), p.val->getType(), "resourceID", first_inst); 420} 421 422 423bool R600KernelParameters::isSpecialType(Type* t) 424{ 425 return !getSpecialTypeName(t).empty(); 426} 427 428string R600KernelParameters::getSpecialTypeName(Type* t) 429{ 430 PointerType *pt = dyn_cast<PointerType>(t); 431 StructType *st = NULL; 432 433 if (pt) 434 { 435 st = dyn_cast<StructType>(pt->getElementType()); 436 } 437 438 if (st) 439 { 440 string prefix = "struct.opencl_builtin_type_"; 441 442 string name = st->getName().str(); 443 444 if (name.substr(0, prefix.length()) == prefix) 445 { 446 return name.substr(prefix.length(), name.length()); 447 } 448 } 449 450 return ""; 451} 452 453 454bool R600KernelParameters::runOnFunction (Function &F) 455{ 456 if (!isOpenCLKernel(&F)) 457 { 458 return false; 459 } 460 461// F.dump(); 462 463 RunAna(&F); 464 Replace(&F); 465 Propagate(&F); 466 467 mod->dump(); 468 return false; 469} 470 471void R600KernelParameters::getAnalysisUsage(AnalysisUsage &AU) const 472{ 473// AU.addRequired<FunctionAnalysis>(); 474 FunctionPass::getAnalysisUsage(AU); 475 AU.setPreservesAll(); 476} 477 478const char *R600KernelParameters::getPassName() const 479{ 480 return "OpenCL Kernel parameter conversion to memory"; 481} 482 483bool R600KernelParameters::doInitialization(Module &M) 484{ 485 Context = &M.getContext(); 486 mod = &M; 487 488 return false; 489} 490 491bool R600KernelParameters::doFinalization(Module &M) 492{ 493 return false; 494} 495 496llvm::FunctionPass* createR600KernelParametersPass(const llvm::TargetData* TD) 497{ 498 FunctionPass *p = new R600KernelParameters(TD); 499 500 return p; 501} 502 503 504