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/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"
37 #define CONSTANT_CACHE_SIZE_DW 127
39 class R600KernelParameters
: public FunctionPass
{
45 Param() : Val(NULL
), PtrVal(NULL
), OffsetInDW(0), SizeInDW(0),
46 IsIndirect(true), SpecialID(0) {}
55 std::string SpecialType
;
58 int End() { return OffsetInDW
+ SizeInDW
; }
59 // The first 9 dwords are reserved for the grid sizes.
60 int getRatOffset() { return 9 + OffsetInDW
; }
63 std::vector
<Param
> Params
;
65 bool IsOpenCLKernel(const Function
*Fun
);
66 int getLastSpecialID(const std::string
& TypeName
);
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
);
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
);
91 char R600KernelParameters::ID
= 0;
93 static RegisterPass
<R600KernelParameters
> X("kerparam",
94 "OpenCL Kernel Parameter conversion", false, false);
96 bool R600KernelParameters::IsOpenCLKernel(const Function
* Fun
) {
97 Module
*Mod
= const_cast<Function
*>(Fun
)->getParent();
98 NamedMDNode
* MD
= Mod
->getOrInsertNamedMetadata("opencl.kernels");
100 if (!MD
or !MD
->getNumOperands()) {
104 for (int i
= 0; i
< int(MD
->getNumOperands()); i
++) {
105 if (!MD
->getOperand(i
) or !MD
->getOperand(i
)->getOperand(0)) {
109 assert(MD
->getOperand(i
)->getNumOperands() == 1);
111 if (MD
->getOperand(i
)->getOperand(0)->getName() == Fun
->getName()) {
119 int R600KernelParameters::getLastSpecialID(const std::string
&TypeName
) {
122 for (std::vector
<Param
>::iterator i
= Params
.begin(); i
!= Params
.end(); i
++) {
123 if (i
->SpecialType
== TypeName
) {
124 LastID
= i
->SpecialID
;
131 int R600KernelParameters::getListSize() {
132 if (Params
.size() == 0) {
136 return Params
.back().End();
139 bool R600KernelParameters::IsIndirect(Value
*Val
, std::set
<Value
*> &Visited
) {
140 //XXX Direct parameters are not supported yet, so return true here.
143 if (isa
<LoadInst
>(Val
)) {
147 if (isa
<IntegerType
>(Val
->getType())) {
148 assert(0 and "Internal error");
152 if (Visited
.count(Val
)) {
158 if (isa
<getElementPtrInst
>(Val
)) {
159 getElementPtrInst
* GEP
= dyn_cast
<getElementPtrInst
>(Val
);
160 getElementPtrInst::op_iterator I
= GEP
->op_begin();
162 for (++I
; I
!= GEP
->op_end(); ++I
) {
163 if (!isa
<Constant
>(*I
)) {
169 for (Value::use_iterator I
= Val
->use_begin(); i
!= Val
->use_end(); ++I
) {
170 Value
* V2
= dyn_cast
<Value
>(*I
);
173 if (IsIndirect(V2
, Visited
)) {
183 void R600KernelParameters::AddParam(Argument
*Arg
) {
186 P
.Val
= dyn_cast
<Value
>(Arg
);
187 P
.OffsetInDW
= getListSize();
188 P
.SizeInDW
= CalculateArgumentSize(Arg
);
190 if (isa
<PointerType
>(Arg
->getType()) and Arg
->hasByValAttr()) {
191 std::set
<Value
*> Visited
;
192 P
.IsIndirect
= IsIndirect(P
.Val
, Visited
);
198 int R600KernelParameters::CalculateArgumentSize(Argument
*Arg
) {
199 Type
* T
= Arg
->getType();
201 if (Arg
->hasByValAttr() and dyn_cast
<PointerType
>(T
)) {
202 T
= dyn_cast
<PointerType
>(T
)->getElementType();
205 int StoreSizeInDW
= (TD
->getTypeStoreSize(T
) + 3)/4;
207 assert(StoreSizeInDW
);
209 return StoreSizeInDW
;
213 void R600KernelParameters::RunAna(Function
* Fun
) {
214 assert(IsOpenCLKernel(Fun
));
216 for (Function::arg_iterator I
= Fun
->arg_begin(); I
!= Fun
->arg_end(); ++I
) {
222 void R600KernelParameters::Replace(Function
* Fun
) {
223 for (std::vector
<Param
>::iterator I
= Params
.begin(); I
!= Params
.end(); ++I
) {
226 if (IsSpecialType(I
->Val
->getType())) {
227 NewVal
= handleSpecial(Fun
, *I
);
229 NewVal
= ConstantRead(Fun
, *I
);
232 I
->Val
->replaceAllUsesWith(NewVal
);
237 void R600KernelParameters::Propagate(Function
* Fun
) {
238 for (std::vector
<Param
>::iterator I
= Params
.begin(); I
!= Params
.end(); ++I
) {
240 Propagate(I
->PtrVal
, I
->Val
->getName(), I
->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
);
252 Addrspace
= AMDILAS::PARAM_I_ADDRESS
;
254 Addrspace
= AMDILAS::PARAM_D_ADDRESS
;
257 if (GEP
and GEP
->getType()->getAddressSpace() != Addrspace
) {
258 Value
*Op
= GEP
->getPointerOperand();
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
));
266 std::vector
<Value
*> Params(GEP
->idx_begin(), GEP
->idx_end());
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();
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());
283 Type
* NewPtrType
= PointerType::get(OrigPtrType
->getElementType(),
286 Value
* NewPtr
= OrigPtr
;
288 if (OrigPtr
->getType() != NewPtrType
) {
289 NewPtr
= new BitCastInst(OrigPtr
, NewPtrType
, "prop_cast", Load
);
292 Value
* new_Load
= new LoadInst(NewPtr
, Name
, Load
);
293 Load
->replaceAllUsesWith(new_Load
);
294 Load
->eraseFromParent();
300 std::vector
<User
*> Users(V
->use_begin(), V
->use_end());
302 for (int i
= 0; i
< int(Users
.size()); i
++) {
303 Value
* V2
= dyn_cast
<Value
>(Users
[i
]);
306 Propagate(V2
, Name
, IsIndirect
);
311 Value
* R600KernelParameters::ConstantRead(Function
*Fun
, Param
&P
) {
312 assert(Fun
->front().begin() != Fun
->front().end());
314 Instruction
*FirstInst
= Fun
->front().begin();
315 IRBuilder
<> Builder (FirstInst
);
316 /* First 3 dwords are reserved for the dimmension info */
318 if (!P
.Val
->hasNUsesOrMore(1)) {
324 Addrspace
= AMDILAS::PARAM_I_ADDRESS
;
326 Addrspace
= AMDILAS::PARAM_D_ADDRESS
;
329 Argument
*Arg
= dyn_cast
<Argument
>(P
.Val
);
330 Type
* ArgType
= P
.Val
->getType();
331 PointerType
* ArgPtrType
= dyn_cast
<PointerType
>(P
.Val
->getType());
333 if (ArgPtrType
and Arg
->hasByValAttr()) {
334 Value
* ParamAddrSpacePtr
= ConstantPointerNull::get(
335 PointerType::get(Type::getInt32Ty(*Context
),
337 Value
* ParamPtr
= GetElementPtrInst::Create(ParamAddrSpacePtr
,
338 ConstantInt::get(Type::getInt32Ty(*Context
),
339 P
.getRatOffset()), Arg
->getName(),
341 ParamPtr
= new BitCastInst(ParamPtr
,
342 PointerType::get(ArgPtrType
->getElementType(),
344 Arg
->getName(), FirstInst
);
348 Value
*ParamAddrSpacePtr
= ConstantPointerNull::get(PointerType::get(
349 ArgType
, Addrspace
));
351 Value
*ParamPtr
= Builder
.CreateGEP(ParamAddrSpacePtr
,
352 ConstantInt::get(Type::getInt32Ty(*Context
), P
.getRatOffset()),
355 Value
*Param_Value
= Builder
.CreateLoad(ParamPtr
, Arg
->getName());
361 Value
* R600KernelParameters::handleSpecial(Function
* Fun
, Param
& P
) {
362 std::string Name
= getSpecialTypeName(P
.Val
->getType());
365 assert(!Name
.empty());
367 if (Name
== "image2d_t" or Name
== "image3d_t") {
368 int LastID
= std::max(getLastSpecialID("image2d_t"),
369 getLastSpecialID("image3d_t"));
372 ID
= 2; ///ID0 and ID1 are used internally by the driver
376 } else if (Name
== "sampler_t") {
377 int LastID
= getLastSpecialID("sampler_t");
385 ///TODO: give some error message
389 P
.SpecialType
= Name
;
392 Instruction
*FirstInst
= Fun
->front().begin();
394 return new IntToPtrInst(ConstantInt::get(Type::getInt32Ty(*Context
),
395 P
.SpecialID
), P
.Val
->getType(),
396 "resourceID", FirstInst
);
400 bool R600KernelParameters::IsSpecialType(Type
* T
) {
401 return !getSpecialTypeName(T
).empty();
404 std::string
R600KernelParameters::getSpecialTypeName(Type
* T
) {
405 PointerType
*PT
= dyn_cast
<PointerType
>(T
);
406 StructType
*ST
= NULL
;
409 ST
= dyn_cast
<StructType
>(PT
->getElementType());
413 std::string Prefix
= "struct.opencl_builtin_type_";
415 std::string Name
= ST
->getName().str();
417 if (Name
.substr(0, Prefix
.length()) == Prefix
) {
418 return Name
.substr(Prefix
.length(), Name
.length());
426 bool R600KernelParameters::runOnFunction (Function
&F
) {
427 if (!IsOpenCLKernel(&F
)) {
438 void R600KernelParameters::getAnalysisUsage(AnalysisUsage
&AU
) const {
439 FunctionPass::getAnalysisUsage(AU
);
440 AU
.setPreservesAll();
443 const char *R600KernelParameters::getPassName() const {
444 return "OpenCL Kernel parameter conversion to memory";
447 bool R600KernelParameters::doInitialization(Module
&M
) {
448 Context
= &M
.getContext();
454 bool R600KernelParameters::doFinalization(Module
&M
) {
458 } // End anonymous namespace
460 FunctionPass
* llvm::createR600KernelParametersPass(const TargetData
* TD
) {
461 return new R600KernelParameters(TD
);