]> git.pld-linux.org Git - packages/SPIRV-LLVM-Translator.git/blob - 0001-Update-LowerOpenCL-pass-to-handle-new-blocks-represn.patch
macros for %cmake
[packages/SPIRV-LLVM-Translator.git] / 0001-Update-LowerOpenCL-pass-to-handle-new-blocks-represn.patch
1 From 9ce0fe02fd6cda5fb29fbb0d5037a1798a810b8a Mon Sep 17 00:00:00 2001
2 From: Alexey Sotkin <alexey.sotkin@intel.com>
3 Date: Thu, 21 Feb 2019 17:14:36 +0300
4 Subject: [PATCH 1/3] Update LowerOpenCL pass to handle new blocks
5  represntation in LLVM IR
6
7 ---
8  lib/SPIRV/SPIRVLowerOCLBlocks.cpp         | 413 ++++++++----------------------
9  test/global_block.ll                      |  71 ++---
10  test/literal-struct.ll                    |  31 ++-
11  test/transcoding/block_w_struct_return.ll |  47 ++--
12  test/transcoding/enqueue_kernel.ll        | 237 ++++++++++-------
13  5 files changed, 317 insertions(+), 482 deletions(-)
14
15 diff --git a/lib/SPIRV/SPIRVLowerOCLBlocks.cpp b/lib/SPIRV/SPIRVLowerOCLBlocks.cpp
16 index 50e1838..b42a4ec 100644
17 --- a/lib/SPIRV/SPIRVLowerOCLBlocks.cpp
18 +++ b/lib/SPIRV/SPIRVLowerOCLBlocks.cpp
19 @@ -1,303 +1,110 @@
20 -//===- SPIRVLowerOCLBlocks.cpp - OCL Utilities ----------------------------===//\r
21 -//\r
22 -//                     The LLVM/SPIRV Translator\r
23 -//\r
24 -// This file is distributed under the University of Illinois Open Source\r
25 -// License. See LICENSE.TXT for details.\r
26 -//\r
27 -// Copyright (c) 2018 Intel Corporation. All rights reserved.\r
28 -//\r
29 -// Permission is hereby granted, free of charge, to any person obtaining a\r
30 -// copy of this software and associated documentation files (the "Software"),\r
31 -// to deal with the Software without restriction, including without limitation\r
32 -// the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
33 -// and/or sell copies of the Software, and to permit persons to whom the\r
34 -// Software is furnished to do so, subject to the following conditions:\r
35 -//\r
36 -// Redistributions of source code must retain the above copyright notice,\r
37 -// this list of conditions and the following disclaimers.\r
38 -// Redistributions in binary form must reproduce the above copyright notice,\r
39 -// this list of conditions and the following disclaimers in the documentation\r
40 -// and/or other materials provided with the distribution.\r
41 -// Neither the names of Intel Corporation, nor the names of its\r
42 -// contributors may be used to endorse or promote products derived from this\r
43 -// Software without specific prior written permission.\r
44 -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
45 -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
46 -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
47 -// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
48 -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
49 -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH\r
50 -// THE SOFTWARE.\r
51 -//\r
52 -//===----------------------------------------------------------------------===//\r
53 -//\r
54 -// SPIR-V specification doesn't allow function pointers, so SPIR-V translator\r
55 -// is designed to fail if a value with function type (except calls) is occured.\r
56 -// Currently there is only two cases, when function pointers are generating in\r
57 -// LLVM IR in OpenCL - block calls and device side enqueue built-in calls.\r
58 -//\r
59 -// In both cases values with function type used as intermediate representation\r
60 -// for block literal structure.\r
61 -//\r
62 -// This pass is designed to find such cases and simplify them to avoid any\r
63 -// function pointer types occurrences in LLVM IR in 4 steps.\r
64 -//\r
65 -// 1. Find all function pointer allocas, like\r
66 -//      %block = alloca void () *\r
67 -//\r
68 -//    Then find a single store to that alloca:\r
69 -//      %blockLit = alloca <{ i32, i32, ...}>, align 4\r
70 -//      %0 = bitcast <{ i32, i32, ... }>* %blockLit to void ()*\r
71 -//    > store void ()* %0, void ()** %block, align 4\r
72 -//\r
73 -//    And replace the alloca users by new instructions which used stored value\r
74 -//    %blockLit itself instead of function pointer alloca %block.\r
75 -//\r
76 -// 2. Find consecutive casts from block literal type to i8 addrspace(4)*\r
77 -//    used function pointers as an intermediate type:\r
78 -//      %0 = bitcast <{ i32, i32 }> %block to void() *\r
79 -//      %1 = addrspacecast void() * %0 to i8 addrspace(4)*\r
80 -//    And simplify them:\r
81 -//      %2 = addrspacecast <{ i32, i32 }> %block to i8 addrspace(4)*\r
82 -//\r
83 -// 3. Find all unused instructions with function pointer type occured after\r
84 -//    pp.1-2 and remove them.\r
85 -//\r
86 -// 4. Find unused globals with function pointer type, like\r
87 -//    @block = constant void ()*\r
88 -//             bitcast ({ i32, i32 }* @__block_literal_global to void ()*\r
89 -//\r
90 -//    And remove them.\r
91 -//\r
92 -//===----------------------------------------------------------------------===//\r
93 -#define DEBUG_TYPE "spv-lower-ocl-blocks"\r
94 -\r
95 -#include "OCLUtil.h"\r
96 -#include "SPIRVInternal.h"\r
97 -\r
98 -#include "llvm/ADT/SetVector.h"\r
99 -#include "llvm/Analysis/ValueTracking.h"\r
100 -#include "llvm/IR/GlobalVariable.h"\r
101 -#include "llvm/IR/InstIterator.h"\r
102 -#include "llvm/IR/Module.h"\r
103 -#include "llvm/Pass.h"\r
104 -#include "llvm/PassSupport.h"\r
105 -#include "llvm/Support/Casting.h"\r
106 -\r
107 -using namespace llvm;\r
108 -\r
109 -namespace {\r
110 -\r
111 -static void\r
112 -removeUnusedFunctionPtrInst(Instruction *I,\r
113 -                            SmallSetVector<Instruction *, 16> &FuncPtrInsts) {\r
114 -  for (unsigned OpIdx = 0, Ops = I->getNumOperands(); OpIdx != Ops; ++OpIdx) {\r
115 -    Instruction *OpI = dyn_cast<Instruction>(I->getOperand(OpIdx));\r
116 -    I->setOperand(OpIdx, nullptr);\r
117 -    if (OpI && OpI != I && OpI->user_empty())\r
118 -      FuncPtrInsts.insert(OpI);\r
119 -  }\r
120 -  I->eraseFromParent();\r
121 -}\r
122 -\r
123 -static bool isFuncPtrAlloca(const AllocaInst *AI) {\r
124 -  auto *ET = dyn_cast<PointerType>(AI->getAllocatedType());\r
125 -  return ET && ET->getElementType()->isFunctionTy();\r
126 -}\r
127 -\r
128 -static bool hasFuncPtrType(const Value *V) {\r
129 -  auto *PT = dyn_cast<PointerType>(V->getType());\r
130 -  return PT && PT->getElementType()->isFunctionTy();\r
131 -}\r
132 -\r
133 -static bool isFuncPtrInst(const Instruction *I) {\r
134 -  if (auto *AI = dyn_cast<AllocaInst>(I))\r
135 -    return isFuncPtrAlloca(AI);\r
136 -\r
137 -  for (auto &Op : I->operands()) {\r
138 -    if (auto *AI = dyn_cast<AllocaInst>(Op))\r
139 -      return isFuncPtrAlloca(AI);\r
140 -\r
141 -    auto *OpI = dyn_cast<Instruction>(&Op);\r
142 -    if (OpI && OpI != I && hasFuncPtrType(OpI))\r
143 -      return true;\r
144 -  }\r
145 -  return false;\r
146 -}\r
147 -\r
148 -static StoreInst *findSingleStore(AllocaInst *AI) {\r
149 -  StoreInst *Store = nullptr;\r
150 -  for (auto *U : AI->users()) {\r
151 -    if (!isa<StoreInst>(U))\r
152 -      continue; // not a store\r
153 -    if (Store)\r
154 -      return nullptr; // there are more than one stores\r
155 -    Store = dyn_cast<StoreInst>(U);\r
156 -  }\r
157 -  return Store;\r
158 -}\r
159 -\r
160 -static void fixFunctionPtrAllocaUsers(AllocaInst *AI) {\r
161 -  // Find and remove a single store to alloca\r
162 -  auto *SingleStore = findSingleStore(AI);\r
163 -  assert(SingleStore && "More than one store to the function pointer alloca");\r
164 -  auto *StoredVal = SingleStore->getValueOperand();\r
165 -  SingleStore->eraseFromParent();\r
166 -\r
167 -  // Find loads from the alloca and replace thier users\r
168 -  for (auto *U : AI->users()) {\r
169 -    auto *LI = dyn_cast<LoadInst>(U);\r
170 -    if (!LI)\r
171 -      continue;\r
172 -\r
173 -    for (auto *U : LI->users()) {\r
174 -      auto *UInst = cast<Instruction>(U);\r
175 -      auto *Cast = CastInst::CreatePointerBitCastOrAddrSpaceCast(\r
176 -          StoredVal, UInst->getType(), "", UInst);\r
177 -      UInst->replaceAllUsesWith(Cast);\r
178 -    }\r
179 -  }\r
180 -}\r
181 -\r
182 -static int getBlockLiteralIdx(const Function &F) {\r
183 -  StringRef FName = F.getName();\r
184 -  if (isEnqueueKernelBI(FName))\r
185 -    return FName.contains("events") ? 7 : 4;\r
186 -  if (isKernelQueryBI(FName))\r
187 -    return FName.contains("for_ndrange") ? 2 : 1;\r
188 -  if (FName.startswith("__") && FName.contains("_block_invoke"))\r
189 -    return F.hasStructRetAttr() ? 1 : 0;\r
190 -\r
191 -  return -1; // No block literal argument\r
192 -}\r
193 -\r
194 -static bool hasBlockLiteralArg(const Function &F) {\r
195 -  return getBlockLiteralIdx(F) != -1;\r
196 -}\r
197 -\r
198 -static bool simplifyFunctionPtrCasts(Function &F) {\r
199 -  bool Changed = false;\r
200 -  int BlockLiteralIdx = getBlockLiteralIdx(F);\r
201 -  for (auto *U : F.users()) {\r
202 -    auto *Call = dyn_cast<CallInst>(U);\r
203 -    if (!Call)\r
204 -      continue;\r
205 -    if (Call->getFunction()->getName() == F.getName().str() + "_kernel")\r
206 -      continue; // Skip block invoke function calls inside block invoke kernels\r
207 -\r
208 -    const DataLayout &DL = F.getParent()->getDataLayout();\r
209 -    auto *BlockLiteral = Call->getOperand(BlockLiteralIdx);\r
210 -    auto *BlockLiteralVal = GetUnderlyingObject(BlockLiteral, DL);\r
211 -    if (isa<GlobalVariable>(BlockLiteralVal))\r
212 -      continue; // nothing to do with globals\r
213 -\r
214 -    auto *BlockLiteralAlloca = cast<AllocaInst>(BlockLiteralVal);\r
215 -    assert(!BlockLiteralAlloca->getAllocatedType()->isFunctionTy() &&\r
216 -           "Function type shouldn't be there");\r
217 -\r
218 -    auto *NewBlockLiteral = CastInst::CreatePointerBitCastOrAddrSpaceCast(\r
219 -        BlockLiteralAlloca, BlockLiteral->getType(), "", Call);\r
220 -    BlockLiteral->replaceAllUsesWith(NewBlockLiteral);\r
221 -    Changed |= true;\r
222 -  }\r
223 -  return Changed;\r
224 -}\r
225 -\r
226 -static void\r
227 -findFunctionPtrAllocas(Module &M,\r
228 -                       SmallVectorImpl<AllocaInst *> &FuncPtrAllocas) {\r
229 -  for (auto &F : M) {\r
230 -    if (F.isDeclaration())\r
231 -      continue;\r
232 -    for (auto &I : instructions(F)) {\r
233 -      auto *AI = dyn_cast<AllocaInst>(&I);\r
234 -      if (!AI || !isFuncPtrAlloca(AI))\r
235 -        continue;\r
236 -      FuncPtrAllocas.push_back(AI);\r
237 -    }\r
238 -  }\r
239 -}\r
240 -\r
241 -static void\r
242 -findUnusedFunctionPtrInsts(Module &M,\r
243 -                           SmallSetVector<Instruction *, 16> &FuncPtrInsts) {\r
244 -  for (auto &F : M) {\r
245 -    if (F.isDeclaration())\r
246 -      continue;\r
247 -    for (auto &I : instructions(F))\r
248 -      if (I.user_empty() && isFuncPtrInst(&I))\r
249 -        FuncPtrInsts.insert(&I);\r
250 -  }\r
251 -}\r
252 -\r
253 -static void\r
254 -findUnusedFunctionPtrGlbs(Module &M,\r
255 -                          SmallVectorImpl<GlobalVariable *> &FuncPtrGlbs) {\r
256 -  for (auto &GV : M.globals()) {\r
257 -    if (!GV.user_empty())\r
258 -      continue;\r
259 -    auto *GVType = dyn_cast<PointerType>(GV.getType()->getElementType());\r
260 -    if (GVType && GVType->getElementType()->isFunctionTy())\r
261 -      FuncPtrGlbs.push_back(&GV);\r
262 -  }\r
263 -}\r
264 -\r
265 -class SPIRVLowerOCLBlocks : public ModulePass {\r
266 -\r
267 -public:\r
268 -  SPIRVLowerOCLBlocks() : ModulePass(ID) {}\r
269 -\r
270 -  bool runOnModule(Module &M) {\r
271 -    bool Changed = false;\r
272 -\r
273 -    // 1. Find function pointer allocas and fix their users\r
274 -    SmallVector<AllocaInst *, 16> FuncPtrAllocas;\r
275 -    findFunctionPtrAllocas(M, FuncPtrAllocas);\r
276 -\r
277 -    Changed |= !FuncPtrAllocas.empty();\r
278 -    for (auto *AI : FuncPtrAllocas)\r
279 -      fixFunctionPtrAllocaUsers(AI);\r
280 -\r
281 -    // 2. Simplify consecutive casts which use function pointer types\r
282 -    for (auto &F : M)\r
283 -      if (hasBlockLiteralArg(F))\r
284 -        Changed |= simplifyFunctionPtrCasts(F);\r
285 -\r
286 -    // 3. Cleanup unused instructions with function pointer type\r
287 -    // which are occured after pp. 1-2\r
288 -    SmallSetVector<Instruction *, 16> FuncPtrInsts;\r
289 -    findUnusedFunctionPtrInsts(M, FuncPtrInsts);\r
290 -\r
291 -    Changed |= !FuncPtrInsts.empty();\r
292 -    while (!FuncPtrInsts.empty()) {\r
293 -      Instruction *I = FuncPtrInsts.pop_back_val();\r
294 -      removeUnusedFunctionPtrInst(I, FuncPtrInsts);\r
295 -    }\r
296 -\r
297 -    // 4. Find and remove unused global variables with function pointer type\r
298 -    SmallVector<GlobalVariable *, 16> FuncPtrGlbs;\r
299 -    findUnusedFunctionPtrGlbs(M, FuncPtrGlbs);\r
300 -\r
301 -    Changed |= !FuncPtrGlbs.empty();\r
302 -    for (auto *GV : FuncPtrGlbs)\r
303 -      GV->eraseFromParent();\r
304 -\r
305 -    return Changed;\r
306 -  }\r
307 -\r
308 -  static char ID;\r
309 -}; // class SPIRVLowerOCLBlocks\r
310 -\r
311 -char SPIRVLowerOCLBlocks::ID = 0;\r
312 -\r
313 -} // namespace\r
314 -\r
315 -INITIALIZE_PASS(\r
316 -    SPIRVLowerOCLBlocks, "spv-lower-ocl-blocks",\r
317 -    "Remove function pointers occured in case of using OpenCL blocks", false,\r
318 -    false)\r
319 -\r
320 -llvm::ModulePass *llvm::createSPIRVLowerOCLBlocks() {\r
321 -  return new SPIRVLowerOCLBlocks();\r
322 -}\r
323 +//===- SPIRVLowerOCLBlocks.cpp - OCL Utilities ----------------------------===//
324 +//
325 +//                     The LLVM/SPIRV Translator
326 +//
327 +// This file is distributed under the University of Illinois Open Source
328 +// License. See LICENSE.TXT for details.
329 +//
330 +// Copyright (c) 2018 Intel Corporation. All rights reserved.
331 +//
332 +// Permission is hereby granted, free of charge, to any person obtaining a
333 +// copy of this software and associated documentation files (the "Software"),
334 +// to deal with the Software without restriction, including without limitation
335 +// the rights to use, copy, modify, merge, publish, distribute, sublicense,
336 +// and/or sell copies of the Software, and to permit persons to whom the
337 +// Software is furnished to do so, subject to the following conditions:
338 +//
339 +// Redistributions of source code must retain the above copyright notice,
340 +// this list of conditions and the following disclaimers.
341 +// Redistributions in binary form must reproduce the above copyright notice,
342 +// this list of conditions and the following disclaimers in the documentation
343 +// and/or other materials provided with the distribution.
344 +// Neither the names of Intel Corporation, nor the names of its
345 +// contributors may be used to endorse or promote products derived from this
346 +// Software without specific prior written permission.
347 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
348 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
349 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
350 +// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
351 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
352 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
353 +// THE SOFTWARE.
354 +//
355 +//===----------------------------------------------------------------------===//
356 +//
357 +// SPIR-V specification doesn't allow function pointers, so SPIR-V translator
358 +// is designed to fail if a value with function type (except calls) is occured.
359 +// Currently there is only two cases, when function pointers are generating in
360 +// LLVM IR in OpenCL - block calls and device side enqueue built-in calls.
361 +//
362 +// In both cases values with function type used as intermediate representation
363 +// for block literal structure.
364 +//
365 +// In LLVM IR produced by clang, blocks are represented with the following
366 +// structure:
367 +// %struct.__opencl_block_literal_generic = type { i32, i32, i8 addrspace(4)* }
368 +// Pointers to block invoke functions are stored in the third field. Clang
369 +// replaces inderect function calls in all cases except if block is passed as a
370 +// function argument. Note that it is somewhat unclear if the OpenCL C spec
371 +// should allow passing blocks as function argumernts. This pass is not supposed
372 +// to work correctly with such functions.
373 +// Clang though has to store function pointers to this structure. Purpose of
374 +// this pass is to replace store of function pointers(not allowed in SPIR-V)
375 +// with null pointers.
376 +//
377 +//===----------------------------------------------------------------------===//
378 +#define DEBUG_TYPE "spv-lower-ocl-blocks"
379 +
380 +#include "SPIRVInternal.h"
381 +
382 +#include "llvm/IR/Module.h"
383 +#include "llvm/Pass.h"
384 +#include "llvm/Support/Regex.h"
385 +
386 +using namespace llvm;
387 +
388 +namespace {
389 +
390 +static bool isBlockInvoke(Function &F) {
391 +  static Regex BlockInvokeRegex("_block_invoke_?[0-9]*$");
392 +  return BlockInvokeRegex.match(F.getName());
393 +}
394 +
395 +class SPIRVLowerOCLBlocks : public ModulePass {
396 +
397 +public:
398 +  SPIRVLowerOCLBlocks() : ModulePass(ID) {}
399 +
400 +  bool runOnModule(Module &M) {
401 +    bool Changed = false;
402 +    for (Function &F : M) {
403 +      if (!isBlockInvoke(F))
404 +        continue;
405 +      for (User *U : F.users()) {
406 +        if (!isa<Constant>(U))
407 +          continue;
408 +        Constant *Null = Constant::getNullValue(U->getType());
409 +        if (U != Null) {
410 +          U->replaceAllUsesWith(Null);
411 +          Changed = true;
412 +        }
413 +      }
414 +    }
415 +    return Changed;
416 +  }
417 +
418 +  static char ID;
419 +};
420 +
421 +char SPIRVLowerOCLBlocks::ID = 0;
422 +
423 +} // namespace
424 +
425 +INITIALIZE_PASS(
426 +    SPIRVLowerOCLBlocks, "spv-lower-ocl-blocks",
427 +    "Remove function pointers occured in case of using OpenCL blocks", false,
428 +    false)
429 +
430 +llvm::ModulePass *llvm::createSPIRVLowerOCLBlocks() {
431 +  return new SPIRVLowerOCLBlocks();
432 +}
433
This page took 0.132569 seconds and 3 git commands to generate.