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