Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/AMDGPU/R600OpenCLImageTypeLoweringPass.cpp
Line
Count
Source (jump to first uncovered line)
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 "AMDGPU.h"
28
#include "llvm/ADT/SmallVector.h"
29
#include "llvm/ADT/StringRef.h"
30
#include "llvm/ADT/Twine.h"
31
#include "llvm/IR/Argument.h"
32
#include "llvm/IR/DerivedTypes.h"
33
#include "llvm/IR/Constants.h"
34
#include "llvm/IR/Function.h"
35
#include "llvm/IR/Instruction.h"
36
#include "llvm/IR/Instructions.h"
37
#include "llvm/IR/Metadata.h"
38
#include "llvm/IR/Module.h"
39
#include "llvm/IR/Type.h"
40
#include "llvm/IR/Use.h"
41
#include "llvm/IR/User.h"
42
#include "llvm/Pass.h"
43
#include "llvm/Support/Casting.h"
44
#include "llvm/Support/ErrorHandling.h"
45
#include "llvm/Transforms/Utils/Cloning.h"
46
#include "llvm/Transforms/Utils/ValueMapper.h"
47
#include <cassert>
48
#include <cstddef>
49
#include <cstdint>
50
#include <tuple>
51
52
using namespace llvm;
53
54
static StringRef GetImageSizeFunc =         "llvm.OpenCL.image.get.size";
55
static StringRef GetImageFormatFunc =       "llvm.OpenCL.image.get.format";
56
static StringRef GetImageResourceIDFunc =   "llvm.OpenCL.image.get.resource.id";
57
static StringRef GetSamplerResourceIDFunc =
58
    "llvm.OpenCL.sampler.get.resource.id";
59
60
static StringRef ImageSizeArgMDType =   "__llvm_image_size";
61
static StringRef ImageFormatArgMDType = "__llvm_image_format";
62
63
static StringRef KernelsMDNodeName = "opencl.kernels";
64
static StringRef KernelArgMDNodeNames[] = {
65
  "kernel_arg_addr_space",
66
  "kernel_arg_access_qual",
67
  "kernel_arg_type",
68
  "kernel_arg_base_type",
69
  "kernel_arg_type_qual"};
70
static const unsigned NumKernelArgMDNodes = 5;
71
72
namespace {
73
74
using MDVector = SmallVector<Metadata *, 8>;
75
struct KernelArgMD {
76
  MDVector ArgVector[NumKernelArgMDNodes];
77
};
78
79
} // end anonymous namespace
80
81
static inline bool
82
276
IsImageType(StringRef TypeString) {
83
276
  return TypeString == "image2d_t" || 
TypeString == "image3d_t"195
;
84
276
}
85
86
static inline bool
87
40
IsSamplerType(StringRef TypeString) {
88
40
  return TypeString == "sampler_t";
89
40
}
90
91
static Function *
92
41
GetFunctionFromMDNode(MDNode *Node) {
93
41
  if (!Node)
94
0
    return nullptr;
95
41
96
41
  size_t NumOps = Node->getNumOperands();
97
41
  if (NumOps != NumKernelArgMDNodes + 1)
98
7
    return nullptr;
99
34
100
34
  auto F = mdconst::dyn_extract<Function>(Node->getOperand(0));
101
34
  if (!F)
102
0
    return nullptr;
103
34
104
34
  // Sanity checks.
105
34
  size_t ExpectNumArgNodeOps = F->arg_size() + 1;
106
202
  for (size_t i = 0; i < NumKernelArgMDNodes; 
++i168
) {
107
169
    MDNode *ArgNode = dyn_cast_or_null<MDNode>(Node->getOperand(i + 1));
108
169
    if (ArgNode->getNumOperands() != ExpectNumArgNodeOps)
109
0
      return nullptr;
110
169
    if (!ArgNode->getOperand(0))
111
0
      return nullptr;
112
169
113
169
    // FIXME: It should be possible to do image lowering when some metadata
114
169
    // args missing or not in the expected order.
115
169
    MDString *StringNode = dyn_cast<MDString>(ArgNode->getOperand(0));
116
169
    if (!StringNode || StringNode->getString() != KernelArgMDNodeNames[i])
117
1
      return nullptr;
118
169
  }
119
34
120
34
  
return F33
;
121
34
}
122
123
static StringRef
124
55
AccessQualFromMD(MDNode *KernelMDNode, unsigned ArgIdx) {
125
55
  MDNode *ArgAQNode = cast<MDNode>(KernelMDNode->getOperand(2));
126
55
  return cast<MDString>(ArgAQNode->getOperand(ArgIdx + 1))->getString();
127
55
}
128
129
static StringRef
130
276
ArgTypeFromMD(MDNode *KernelMDNode, unsigned ArgIdx) {
131
276
  MDNode *ArgTypeNode = cast<MDNode>(KernelMDNode->getOperand(3));
132
276
  return cast<MDString>(ArgTypeNode->getOperand(ArgIdx + 1))->getString();
133
276
}
134
135
static MDVector
136
128
GetArgMD(MDNode *KernelMDNode, unsigned OpIdx) {
137
128
  MDVector Res;
138
768
  for (unsigned i = 0; i < NumKernelArgMDNodes; 
++i640
) {
139
640
    MDNode *Node = cast<MDNode>(KernelMDNode->getOperand(i + 1));
140
640
    Res.push_back(Node->getOperand(OpIdx));
141
640
  }
142
128
  return Res;
143
128
}
144
145
static void
146
238
PushArgMD(KernelArgMD &MD, const MDVector &V) {
147
238
  assert(V.size() == NumKernelArgMDNodes);
148
1.42k
  for (unsigned i = 0; i < NumKernelArgMDNodes; 
++i1.19k
) {
149
1.19k
    MD.ArgVector[i].push_back(V[i]);
150
1.19k
  }
151
238
}
152
153
namespace {
154
155
class R600OpenCLImageTypeLoweringPass : public ModulePass {
156
  static char ID;
157
158
  LLVMContext *Context;
159
  Type *Int32Type;
160
  Type *ImageSizeType;
161
  Type *ImageFormatType;
162
  SmallVector<Instruction *, 4> InstsToErase;
163
164
  bool replaceImageUses(Argument &ImageArg, uint32_t ResourceID,
165
                        Argument &ImageSizeArg,
166
55
                        Argument &ImageFormatArg) {
167
55
    bool Modified = false;
168
55
169
55
    for (auto &Use : ImageArg.uses()) {
170
30
      auto Inst = dyn_cast<CallInst>(Use.getUser());
171
30
      if (!Inst) {
172
0
        continue;
173
0
      }
174
30
175
30
      Function *F = Inst->getCalledFunction();
176
30
      if (!F)
177
0
        continue;
178
30
179
30
      Value *Replacement = nullptr;
180
30
      StringRef Name = F->getName();
181
30
      if (Name.startswith(GetImageResourceIDFunc)) {
182
20
        Replacement = ConstantInt::get(Int32Type, ResourceID);
183
20
      } else 
if (10
Name.startswith(GetImageSizeFunc)10
) {
184
6
        Replacement = &ImageSizeArg;
185
6
      } else 
if (4
Name.startswith(GetImageFormatFunc)4
) {
186
4
        Replacement = &ImageFormatArg;
187
4
      } else {
188
0
        continue;
189
0
      }
190
30
191
30
      Inst->replaceAllUsesWith(Replacement);
192
30
      InstsToErase.push_back(Inst);
193
30
      Modified = true;
194
30
    }
195
55
196
55
    return Modified;
197
55
  }
198
199
7
  bool replaceSamplerUses(Argument &SamplerArg, uint32_t ResourceID) {
200
7
    bool Modified = false;
201
7
202
7
    for (const auto &Use : SamplerArg.uses()) {
203
3
      auto Inst = dyn_cast<CallInst>(Use.getUser());
204
3
      if (!Inst) {
205
0
        continue;
206
0
      }
207
3
208
3
      Function *F = Inst->getCalledFunction();
209
3
      if (!F)
210
0
        continue;
211
3
212
3
      Value *Replacement = nullptr;
213
3
      StringRef Name = F->getName();
214
3
      if (Name == GetSamplerResourceIDFunc) {
215
3
        Replacement = ConstantInt::get(Int32Type, ResourceID);
216
3
      } else {
217
0
        continue;
218
0
      }
219
3
220
3
      Inst->replaceAllUsesWith(Replacement);
221
3
      InstsToErase.push_back(Inst);
222
3
      Modified = true;
223
3
    }
224
7
225
7
    return Modified;
226
7
  }
227
228
33
  bool replaceImageAndSamplerUses(Function *F, MDNode *KernelMDNode) {
229
33
    uint32_t NumReadOnlyImageArgs = 0;
230
33
    uint32_t NumWriteOnlyImageArgs = 0;
231
33
    uint32_t NumSamplerArgs = 0;
232
33
233
33
    bool Modified = false;
234
33
    InstsToErase.clear();
235
128
    for (auto ArgI = F->arg_begin(); ArgI != F->arg_end(); 
++ArgI95
) {
236
95
      Argument &Arg = *ArgI;
237
95
      StringRef Type = ArgTypeFromMD(KernelMDNode, Arg.getArgNo());
238
95
239
95
      // Handle image types.
240
95
      if (IsImageType(Type)) {
241
55
        StringRef AccessQual = AccessQualFromMD(KernelMDNode, Arg.getArgNo());
242
55
        uint32_t ResourceID;
243
55
        if (AccessQual == "read_only") {
244
32
          ResourceID = NumReadOnlyImageArgs++;
245
32
        } else 
if (23
AccessQual == "write_only"23
) {
246
23
          ResourceID = NumWriteOnlyImageArgs++;
247
23
        } else {
248
0
          llvm_unreachable("Wrong image access qualifier.");
249
0
        }
250
55
251
55
        Argument &SizeArg = *(++ArgI);
252
55
        Argument &FormatArg = *(++ArgI);
253
55
        Modified |= replaceImageUses(Arg, ResourceID, SizeArg, FormatArg);
254
55
255
55
      // Handle sampler type.
256
55
      } else 
if (40
IsSamplerType(Type)40
) {
257
7
        uint32_t ResourceID = NumSamplerArgs++;
258
7
        Modified |= replaceSamplerUses(Arg, ResourceID);
259
7
      }
260
95
    }
261
66
    
for (unsigned i = 0; 33
i < InstsToErase.size();
++i33
) {
262
33
      InstsToErase[i]->eraseFromParent();
263
33
    }
264
33
265
33
    return Modified;
266
33
  }
267
268
  std::tuple<Function *, MDNode *>
269
33
  addImplicitArgs(Function *F, MDNode *KernelMDNode) {
270
33
    bool Modified = false;
271
33
272
33
    FunctionType *FT = F->getFunctionType();
273
33
    SmallVector<Type *, 8> ArgTypes;
274
33
275
33
    // Metadata operands for new MDNode.
276
33
    KernelArgMD NewArgMDs;
277
33
    PushArgMD(NewArgMDs, GetArgMD(KernelMDNode, 0));
278
33
279
33
    // Add implicit arguments to the signature.
280
128
    for (unsigned i = 0; i < FT->getNumParams(); 
++i95
) {
281
95
      ArgTypes.push_back(FT->getParamType(i));
282
95
      MDVector ArgMD = GetArgMD(KernelMDNode, i + 1);
283
95
      PushArgMD(NewArgMDs, ArgMD);
284
95
285
95
      if (!IsImageType(ArgTypeFromMD(KernelMDNode, i)))
286
40
        continue;
287
55
288
55
      // Add size implicit argument.
289
55
      ArgTypes.push_back(ImageSizeType);
290
55
      ArgMD[2] = ArgMD[3] = MDString::get(*Context, ImageSizeArgMDType);
291
55
      PushArgMD(NewArgMDs, ArgMD);
292
55
293
55
      // Add format implicit argument.
294
55
      ArgTypes.push_back(ImageFormatType);
295
55
      ArgMD[2] = ArgMD[3] = MDString::get(*Context, ImageFormatArgMDType);
296
55
      PushArgMD(NewArgMDs, ArgMD);
297
55
298
55
      Modified = true;
299
55
    }
300
33
    if (!Modified) {
301
3
      return std::make_tuple(nullptr, nullptr);
302
3
    }
303
30
304
30
    // Create function with new signature and clone the old body into it.
305
30
    auto NewFT = FunctionType::get(FT->getReturnType(), ArgTypes, false);
306
30
    auto NewF = Function::Create(NewFT, F->getLinkage(), F->getName());
307
30
    ValueToValueMapTy VMap;
308
30
    auto NewFArgIt = NewF->arg_begin();
309
86
    for (auto &Arg: F->args()) {
310
86
      auto ArgName = Arg.getName();
311
86
      NewFArgIt->setName(ArgName);
312
86
      VMap[&Arg] = &(*NewFArgIt++);
313
86
      if (IsImageType(ArgTypeFromMD(KernelMDNode, Arg.getArgNo()))) {
314
55
        (NewFArgIt++)->setName(Twine("__size_") + ArgName);
315
55
        (NewFArgIt++)->setName(Twine("__format_") + ArgName);
316
55
      }
317
86
    }
318
30
    SmallVector<ReturnInst*, 8> Returns;
319
30
    CloneFunctionInto(NewF, F, VMap, /*ModuleLevelChanges=*/false, Returns);
320
30
321
30
    // Build new MDNode.
322
30
    SmallVector<Metadata *, 6> KernelMDArgs;
323
30
    KernelMDArgs.push_back(ConstantAsMetadata::get(NewF));
324
180
    for (unsigned i = 0; i < NumKernelArgMDNodes; 
++i150
)
325
150
      KernelMDArgs.push_back(MDNode::get(*Context, NewArgMDs.ArgVector[i]));
326
30
    MDNode *NewMDNode = MDNode::get(*Context, KernelMDArgs);
327
30
328
30
    return std::make_tuple(NewF, NewMDNode);
329
30
  }
330
331
279
  bool transformKernels(Module &M) {
332
279
    NamedMDNode *KernelsMDNode = M.getNamedMetadata(KernelsMDNodeName);
333
279
    if (!KernelsMDNode)
334
273
      return false;
335
6
336
6
    bool Modified = false;
337
47
    for (unsigned i = 0; i < KernelsMDNode->getNumOperands(); 
++i41
) {
338
41
      MDNode *KernelMDNode = KernelsMDNode->getOperand(i);
339
41
      Function *F = GetFunctionFromMDNode(KernelMDNode);
340
41
      if (!F)
341
8
        continue;
342
33
343
33
      Function *NewF;
344
33
      MDNode *NewMDNode;
345
33
      std::tie(NewF, NewMDNode) = addImplicitArgs(F, KernelMDNode);
346
33
      if (NewF) {
347
30
        // Replace old function and metadata with new ones.
348
30
        F->eraseFromParent();
349
30
        M.getFunctionList().push_back(NewF);
350
30
        M.getOrInsertFunction(NewF->getName(), NewF->getFunctionType(),
351
30
                              NewF->getAttributes());
352
30
        KernelsMDNode->setOperand(i, NewMDNode);
353
30
354
30
        F = NewF;
355
30
        KernelMDNode = NewMDNode;
356
30
        Modified = true;
357
30
      }
358
33
359
33
      Modified |= replaceImageAndSamplerUses(F, KernelMDNode);
360
33
    }
361
6
362
6
    return Modified;
363
6
  }
364
365
public:
366
280
  R600OpenCLImageTypeLoweringPass() : ModulePass(ID) {}
367
368
279
  bool runOnModule(Module &M) override {
369
279
    Context = &M.getContext();
370
279
    Int32Type = Type::getInt32Ty(M.getContext());
371
279
    ImageSizeType = ArrayType::get(Int32Type, 3);
372
279
    ImageFormatType = ArrayType::get(Int32Type, 2);
373
279
374
279
    return transformKernels(M);
375
279
  }
376
377
0
  StringRef getPassName() const override {
378
0
    return "R600 OpenCL Image Type Pass";
379
0
  }
380
};
381
382
} // end anonymous namespace
383
384
char R600OpenCLImageTypeLoweringPass::ID = 0;
385
386
280
ModulePass *llvm::createR600OpenCLImageTypeLoweringPass() {
387
280
  return new R600OpenCLImageTypeLoweringPass();
388
280
}