LLVM 19.0.0git
R600OpenCLImageTypeLoweringPass.cpp
Go to the documentation of this file.
1//===- R600OpenCLImageTypeLoweringPass.cpp ------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// This pass resolves calls to OpenCL image attribute, image resource ID and
11/// sampler resource ID getter functions.
12///
13/// Image attributes (size and format) are expected to be passed to the kernel
14/// as kernel arguments immediately following the image argument itself,
15/// therefore this pass adds image size and format arguments to the kernel
16/// functions in the module. The kernel functions with image arguments are
17/// re-created using the new signature. The new arguments are added to the
18/// kernel metadata with kernel_arg_type set to "image_size" or "image_format".
19/// Note: this pass may invalidate pointers to functions.
20///
21/// Resource IDs of read-only images, write-only images and samplers are
22/// defined to be their index among the kernel arguments of the same
23/// type and access qualifier.
24//
25//===----------------------------------------------------------------------===//
26
27#include "R600.h"
29#include "llvm/ADT/StringRef.h"
30#include "llvm/IR/Constants.h"
31#include "llvm/IR/Function.h"
33#include "llvm/IR/Metadata.h"
34#include "llvm/IR/Module.h"
35#include "llvm/Pass.h"
37
38using namespace llvm;
39
40static StringRef GetImageSizeFunc = "llvm.OpenCL.image.get.size";
41static StringRef GetImageFormatFunc = "llvm.OpenCL.image.get.format";
42static StringRef GetImageResourceIDFunc = "llvm.OpenCL.image.get.resource.id";
44 "llvm.OpenCL.sampler.get.resource.id";
45
46static StringRef ImageSizeArgMDType = "__llvm_image_size";
47static StringRef ImageFormatArgMDType = "__llvm_image_format";
48
49static StringRef KernelsMDNodeName = "opencl.kernels";
51 "kernel_arg_addr_space",
52 "kernel_arg_access_qual",
53 "kernel_arg_type",
54 "kernel_arg_base_type",
55 "kernel_arg_type_qual"};
56static const unsigned NumKernelArgMDNodes = 5;
57
58namespace {
59
60using MDVector = SmallVector<Metadata *, 8>;
61struct KernelArgMD {
62 MDVector ArgVector[NumKernelArgMDNodes];
63};
64
65} // end anonymous namespace
66
67static inline bool
69 return TypeString == "image2d_t" || TypeString == "image3d_t";
70}
71
72static inline bool
74 return TypeString == "sampler_t";
75}
76
77static Function *
79 if (!Node)
80 return nullptr;
81
82 size_t NumOps = Node->getNumOperands();
83 if (NumOps != NumKernelArgMDNodes + 1)
84 return nullptr;
85
86 auto F = mdconst::dyn_extract<Function>(Node->getOperand(0));
87 if (!F)
88 return nullptr;
89
90 // Validation checks.
91 size_t ExpectNumArgNodeOps = F->arg_size() + 1;
92 for (size_t i = 0; i < NumKernelArgMDNodes; ++i) {
93 MDNode *ArgNode = dyn_cast_or_null<MDNode>(Node->getOperand(i + 1));
94 if (ArgNode->getNumOperands() != ExpectNumArgNodeOps)
95 return nullptr;
96 if (!ArgNode->getOperand(0))
97 return nullptr;
98
99 // FIXME: It should be possible to do image lowering when some metadata
100 // args missing or not in the expected order.
101 MDString *StringNode = dyn_cast<MDString>(ArgNode->getOperand(0));
102 if (!StringNode || StringNode->getString() != KernelArgMDNodeNames[i])
103 return nullptr;
104 }
105
106 return F;
107}
108
109static StringRef
110AccessQualFromMD(MDNode *KernelMDNode, unsigned ArgIdx) {
111 MDNode *ArgAQNode = cast<MDNode>(KernelMDNode->getOperand(2));
112 return cast<MDString>(ArgAQNode->getOperand(ArgIdx + 1))->getString();
113}
114
115static StringRef
116ArgTypeFromMD(MDNode *KernelMDNode, unsigned ArgIdx) {
117 MDNode *ArgTypeNode = cast<MDNode>(KernelMDNode->getOperand(3));
118 return cast<MDString>(ArgTypeNode->getOperand(ArgIdx + 1))->getString();
119}
120
121static MDVector
122GetArgMD(MDNode *KernelMDNode, unsigned OpIdx) {
123 MDVector Res;
124 for (unsigned i = 0; i < NumKernelArgMDNodes; ++i) {
125 MDNode *Node = cast<MDNode>(KernelMDNode->getOperand(i + 1));
126 Res.push_back(Node->getOperand(OpIdx));
127 }
128 return Res;
129}
130
131static void
132PushArgMD(KernelArgMD &MD, const MDVector &V) {
133 assert(V.size() == NumKernelArgMDNodes);
134 for (unsigned i = 0; i < NumKernelArgMDNodes; ++i) {
135 MD.ArgVector[i].push_back(V[i]);
136 }
137}
138
139namespace {
140
141class R600OpenCLImageTypeLoweringPass : public ModulePass {
142 static char ID;
143
144 LLVMContext *Context;
145 Type *Int32Type;
146 Type *ImageSizeType;
147 Type *ImageFormatType;
149
150 bool replaceImageUses(Argument &ImageArg, uint32_t ResourceID,
151 Argument &ImageSizeArg,
152 Argument &ImageFormatArg) {
153 bool Modified = false;
154
155 for (auto &Use : ImageArg.uses()) {
156 auto Inst = dyn_cast<CallInst>(Use.getUser());
157 if (!Inst) {
158 continue;
159 }
160
161 Function *F = Inst->getCalledFunction();
162 if (!F)
163 continue;
164
165 Value *Replacement = nullptr;
166 StringRef Name = F->getName();
167 if (Name.starts_with(GetImageResourceIDFunc)) {
168 Replacement = ConstantInt::get(Int32Type, ResourceID);
169 } else if (Name.starts_with(GetImageSizeFunc)) {
170 Replacement = &ImageSizeArg;
171 } else if (Name.starts_with(GetImageFormatFunc)) {
172 Replacement = &ImageFormatArg;
173 } else {
174 continue;
175 }
176
177 Inst->replaceAllUsesWith(Replacement);
178 InstsToErase.push_back(Inst);
179 Modified = true;
180 }
181
182 return Modified;
183 }
184
185 bool replaceSamplerUses(Argument &SamplerArg, uint32_t ResourceID) {
186 bool Modified = false;
187
188 for (const auto &Use : SamplerArg.uses()) {
189 auto Inst = dyn_cast<CallInst>(Use.getUser());
190 if (!Inst) {
191 continue;
192 }
193
194 Function *F = Inst->getCalledFunction();
195 if (!F)
196 continue;
197
198 Value *Replacement = nullptr;
199 StringRef Name = F->getName();
201 Replacement = ConstantInt::get(Int32Type, ResourceID);
202 } else {
203 continue;
204 }
205
206 Inst->replaceAllUsesWith(Replacement);
207 InstsToErase.push_back(Inst);
208 Modified = true;
209 }
210
211 return Modified;
212 }
213
214 bool replaceImageAndSamplerUses(Function *F, MDNode *KernelMDNode) {
215 uint32_t NumReadOnlyImageArgs = 0;
216 uint32_t NumWriteOnlyImageArgs = 0;
217 uint32_t NumSamplerArgs = 0;
218
219 bool Modified = false;
220 InstsToErase.clear();
221 for (auto ArgI = F->arg_begin(); ArgI != F->arg_end(); ++ArgI) {
222 Argument &Arg = *ArgI;
223 StringRef Type = ArgTypeFromMD(KernelMDNode, Arg.getArgNo());
224
225 // Handle image types.
226 if (IsImageType(Type)) {
227 StringRef AccessQual = AccessQualFromMD(KernelMDNode, Arg.getArgNo());
228 uint32_t ResourceID;
229 if (AccessQual == "read_only") {
230 ResourceID = NumReadOnlyImageArgs++;
231 } else if (AccessQual == "write_only") {
232 ResourceID = NumWriteOnlyImageArgs++;
233 } else {
234 llvm_unreachable("Wrong image access qualifier.");
235 }
236
237 Argument &SizeArg = *(++ArgI);
238 Argument &FormatArg = *(++ArgI);
239 Modified |= replaceImageUses(Arg, ResourceID, SizeArg, FormatArg);
240
241 // Handle sampler type.
242 } else if (IsSamplerType(Type)) {
243 uint32_t ResourceID = NumSamplerArgs++;
244 Modified |= replaceSamplerUses(Arg, ResourceID);
245 }
246 }
247 for (unsigned i = 0; i < InstsToErase.size(); ++i) {
248 InstsToErase[i]->eraseFromParent();
249 }
250
251 return Modified;
252 }
253
254 std::tuple<Function *, MDNode *>
255 addImplicitArgs(Function *F, MDNode *KernelMDNode) {
256 bool Modified = false;
257
258 FunctionType *FT = F->getFunctionType();
259 SmallVector<Type *, 8> ArgTypes;
260
261 // Metadata operands for new MDNode.
262 KernelArgMD NewArgMDs;
263 PushArgMD(NewArgMDs, GetArgMD(KernelMDNode, 0));
264
265 // Add implicit arguments to the signature.
266 for (unsigned i = 0; i < FT->getNumParams(); ++i) {
267 ArgTypes.push_back(FT->getParamType(i));
268 MDVector ArgMD = GetArgMD(KernelMDNode, i + 1);
269 PushArgMD(NewArgMDs, ArgMD);
270
271 if (!IsImageType(ArgTypeFromMD(KernelMDNode, i)))
272 continue;
273
274 // Add size implicit argument.
275 ArgTypes.push_back(ImageSizeType);
276 ArgMD[2] = ArgMD[3] = MDString::get(*Context, ImageSizeArgMDType);
277 PushArgMD(NewArgMDs, ArgMD);
278
279 // Add format implicit argument.
280 ArgTypes.push_back(ImageFormatType);
281 ArgMD[2] = ArgMD[3] = MDString::get(*Context, ImageFormatArgMDType);
282 PushArgMD(NewArgMDs, ArgMD);
283
284 Modified = true;
285 }
286 if (!Modified) {
287 return std::tuple(nullptr, nullptr);
288 }
289
290 // Create function with new signature and clone the old body into it.
291 auto NewFT = FunctionType::get(FT->getReturnType(), ArgTypes, false);
292 auto NewF = Function::Create(NewFT, F->getLinkage(), F->getName());
294 auto NewFArgIt = NewF->arg_begin();
295 for (auto &Arg: F->args()) {
296 auto ArgName = Arg.getName();
297 NewFArgIt->setName(ArgName);
298 VMap[&Arg] = &(*NewFArgIt++);
299 if (IsImageType(ArgTypeFromMD(KernelMDNode, Arg.getArgNo()))) {
300 (NewFArgIt++)->setName(Twine("__size_") + ArgName);
301 (NewFArgIt++)->setName(Twine("__format_") + ArgName);
302 }
303 }
305 CloneFunctionInto(NewF, F, VMap, CloneFunctionChangeType::LocalChangesOnly,
306 Returns);
307
308 // Build new MDNode.
309 SmallVector<Metadata *, 6> KernelMDArgs;
310 KernelMDArgs.push_back(ConstantAsMetadata::get(NewF));
311 for (const MDVector &MDV : NewArgMDs.ArgVector)
312 KernelMDArgs.push_back(MDNode::get(*Context, MDV));
313 MDNode *NewMDNode = MDNode::get(*Context, KernelMDArgs);
314
315 return std::tuple(NewF, NewMDNode);
316 }
317
318 bool transformKernels(Module &M) {
319 NamedMDNode *KernelsMDNode = M.getNamedMetadata(KernelsMDNodeName);
320 if (!KernelsMDNode)
321 return false;
322
323 bool Modified = false;
324 for (unsigned i = 0; i < KernelsMDNode->getNumOperands(); ++i) {
325 MDNode *KernelMDNode = KernelsMDNode->getOperand(i);
326 Function *F = GetFunctionFromMDNode(KernelMDNode);
327 if (!F)
328 continue;
329
330 Function *NewF;
331 MDNode *NewMDNode;
332 std::tie(NewF, NewMDNode) = addImplicitArgs(F, KernelMDNode);
333 if (NewF) {
334 // Replace old function and metadata with new ones.
335 F->eraseFromParent();
336 M.getFunctionList().push_back(NewF);
337 M.getOrInsertFunction(NewF->getName(), NewF->getFunctionType(),
338 NewF->getAttributes());
339 KernelsMDNode->setOperand(i, NewMDNode);
340
341 F = NewF;
342 KernelMDNode = NewMDNode;
343 Modified = true;
344 }
345
346 Modified |= replaceImageAndSamplerUses(F, KernelMDNode);
347 }
348
349 return Modified;
350 }
351
352public:
353 R600OpenCLImageTypeLoweringPass() : ModulePass(ID) {}
354
355 bool runOnModule(Module &M) override {
356 Context = &M.getContext();
357 Int32Type = Type::getInt32Ty(M.getContext());
358 ImageSizeType = ArrayType::get(Int32Type, 3);
359 ImageFormatType = ArrayType::get(Int32Type, 2);
360
361 return transformKernels(M);
362 }
363
364 StringRef getPassName() const override {
365 return "R600 OpenCL Image Type Pass";
366 }
367};
368
369} // end anonymous namespace
370
371char R600OpenCLImageTypeLoweringPass::ID = 0;
372
374 return new R600OpenCLImageTypeLoweringPass();
375}
This file contains the declarations for the subclasses of Constant, which represent the different fla...
std::string Name
#define F(x, y, z)
Definition: MD5.cpp:55
This file contains the declarations for metadata subclasses.
Module.h This file contains the declarations for the Module class.
static bool IsImageType(StringRef TypeString)
static StringRef KernelsMDNodeName
static StringRef ArgTypeFromMD(MDNode *KernelMDNode, unsigned ArgIdx)
static StringRef GetImageSizeFunc
static StringRef GetSamplerResourceIDFunc
static const unsigned NumKernelArgMDNodes
static Function * GetFunctionFromMDNode(MDNode *Node)
static bool IsSamplerType(StringRef TypeString)
static void PushArgMD(KernelArgMD &MD, const MDVector &V)
static StringRef AccessQualFromMD(MDNode *KernelMDNode, unsigned ArgIdx)
static StringRef GetImageFormatFunc
static StringRef KernelArgMDNodeNames[]
static StringRef ImageSizeArgMDType
static MDVector GetArgMD(MDNode *KernelMDNode, unsigned OpIdx)
static StringRef GetImageResourceIDFunc
static StringRef ImageFormatArgMDType
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
This class represents an incoming formal argument to a Function.
Definition: Argument.h:31
unsigned getArgNo() const
Return the index of this formal argument in its containing function.
Definition: Argument.h:49
static ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
Definition: Type.cpp:647
static ConstantAsMetadata * get(Constant *C)
Definition: Metadata.h:528
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:165
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.h:207
AttributeList getAttributes() const
Return the attribute list for this Function.
Definition: Function.h:350
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
Metadata node.
Definition: Metadata.h:1067
const MDOperand & getOperand(unsigned I) const
Definition: Metadata.h:1428
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition: Metadata.h:1541
unsigned getNumOperands() const
Return number of MDNode operands.
Definition: Metadata.h:1434
A single uniqued string.
Definition: Metadata.h:720
StringRef getString() const
Definition: Metadata.cpp:610
static MDString * get(LLVMContext &Context, StringRef Str)
Definition: Metadata.cpp:600
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:251
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
A tuple of MDNodes.
Definition: Metadata.h:1729
void setOperand(unsigned I, MDNode *New)
Definition: Metadata.cpp:1389
MDNode * getOperand(unsigned i) const
Definition: Metadata.cpp:1381
unsigned getNumOperands() const
Definition: Metadata.cpp:1377
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
size_t size() const
Definition: SmallVector.h:91
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static IntegerType * getInt32Ty(LLVMContext &C)
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43
User * getUser() const
Returns the User that contains this Use.
Definition: Use.h:72
LLVM Value Representation.
Definition: Value.h:74
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:534
iterator_range< use_iterator > uses()
Definition: Value.h:376
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:309
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
ModulePass * createR600OpenCLImageTypeLoweringPass()
void CloneFunctionInto(Function *NewFunc, const Function *OldFunc, ValueToValueMapTy &VMap, CloneFunctionChangeType Changes, SmallVectorImpl< ReturnInst * > &Returns, const char *NameSuffix="", ClonedCodeInfo *CodeInfo=nullptr, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr)
Clone OldFunc into NewFunc, transforming the old arguments into references to VMap values.