[packages/SPIRV-LLVM-Translator] new package

jajcus jajcus at pld-linux.org
Mon Jul 1 15:52:18 CEST 2019


commit d4711bf22a31337bc4d56858a36a07e02314b267
Author: Jacek Konieczny <j.konieczny at eggsoft.pl>
Date:   Mon Jul 1 15:52:01 2019 +0200

    new package

 ...rOpenCL-pass-to-handle-new-blocks-represn.patch | 433 +++++++++++++++++++++
 SPIRV-LLVM-Translator.spec                         |  76 ++++
 2 files changed, 509 insertions(+)
---
diff --git a/SPIRV-LLVM-Translator.spec b/SPIRV-LLVM-Translator.spec
new file mode 100644
index 0000000..0977552
--- /dev/null
+++ b/SPIRV-LLVM-Translator.spec
@@ -0,0 +1,76 @@
+
+%define llvm_version 7.0.1
+
+Summary:	LLVM/SPIR-V Bi-Directional Translator
+Name:		SPIRV-LLVM-Translator
+Version:	7.0.1
+Release:	1
+License:	University of Illinois/NCSA Open Source License
+Group:		Libraries
+Source0:	https://github.com/KhronosGroup/SPIRV-LLVM-Translator/archive/%{version}-1/%{name}-%{version}-1.tar.gz
+# Source0-md5:	e73c5ebffb4fc5dc606cd217f69ec97c
+# from Intel opencl-clang
+Patch0:		0001-Update-LowerOpenCL-pass-to-handle-new-blocks-represn.patch
+URL:		https://github.com/KhronosGroup/SPIRV-LLVM-Translator/
+BuildRequires:	cmake >= 3.3
+BuildRequires:	llvm-devel >= %{llvm_version}
+BuildRequires:	pkgconfig
+BuildRoot:	%{tmpdir}/%{name}-%{version}-root-%(id -u -n)
+
+%description
+LLVM/SPIR-V Bi-Directional Translator - a library and tool for
+translation between LLVM IR and SPIR-V.
+
+%package devel
+Summary:	Header files for %{name} library
+Summary(pl.UTF-8):	Pliki nagłówkowe biblioteki %{name}
+Group:		Development/Libraries
+Requires:	%{name} = %{version}-%{release}
+
+%description devel
+Header files for %{name} library.
+
+%description devel -l pl.UTF-8
+Pliki nagłówkowe biblioteki %{name}.
+
+%prep
+%setup -qn %{name}-%{version}-1
+
+%build
+
+install -d build
+cd build
+%cmake \
+	../
+%{__make}
+
+cd ..
+
+%install
+rm -rf $RPM_BUILD_ROOT
+
+%{__make} -C build install \
+	DESTDIR=$RPM_BUILD_ROOT
+
+mv $RPM_BUILD_ROOT%{_libdir}/libLLVMSPIRVLib.so.7 $RPM_BUILD_ROOT%{_libdir}/libLLVMSPIRVLib.so.%{version}
+ln -s libLLVMSPIRVLib.so.%{version} $RPM_BUILD_ROOT%{_libdir}/libLLVMSPIRVLib.so.7
+ln -sf libLLVMSPIRVLib.so.%{version} $RPM_BUILD_ROOT%{_libdir}/libLLVMSPIRVLib.so
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post	-p /sbin/ldconfig
+%postun	-p /sbin/ldconfig
+
+%files
+%defattr(644,root,root,755)
+%doc README.md LICENSE.TXT
+%attr(755,root,root) %{_libdir}/libLLVMSPIRVLib.so.7.*.*
+%ghost %attr(755,root,root) %{_libdir}/libLLVMSPIRVLib.so.7
+
+%files devel
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libLLVMSPIRVLib.so
+%{_includedir}/LLVMSPIRVLib
+%{_pkgconfigdir}/LLVMSPIRVLib.pc
diff --git a/0001-Update-LowerOpenCL-pass-to-handle-new-blocks-represn.patch b/0001-Update-LowerOpenCL-pass-to-handle-new-blocks-represn.patch
new file mode 100644
index 0000000..56d6709
--- /dev/null
+++ b/0001-Update-LowerOpenCL-pass-to-handle-new-blocks-represn.patch
@@ -0,0 +1,433 @@
+From 9ce0fe02fd6cda5fb29fbb0d5037a1798a810b8a Mon Sep 17 00:00:00 2001
+From: Alexey Sotkin <alexey.sotkin at intel.com>
+Date: Thu, 21 Feb 2019 17:14:36 +0300
+Subject: [PATCH 1/3] Update LowerOpenCL pass to handle new blocks
+ represntation in LLVM IR
+
+---
+ lib/SPIRV/SPIRVLowerOCLBlocks.cpp         | 413 ++++++++----------------------
+ test/global_block.ll                      |  71 ++---
+ test/literal-struct.ll                    |  31 ++-
+ test/transcoding/block_w_struct_return.ll |  47 ++--
+ test/transcoding/enqueue_kernel.ll        | 237 ++++++++++-------
+ 5 files changed, 317 insertions(+), 482 deletions(-)
+
+diff --git a/lib/SPIRV/SPIRVLowerOCLBlocks.cpp b/lib/SPIRV/SPIRVLowerOCLBlocks.cpp
+index 50e1838..b42a4ec 100644
+--- a/lib/SPIRV/SPIRVLowerOCLBlocks.cpp
++++ b/lib/SPIRV/SPIRVLowerOCLBlocks.cpp
+@@ -1,303 +1,110 @@
+-//===- SPIRVLowerOCLBlocks.cpp - OCL Utilities ----------------------------===//
+-//
+-//                     The LLVM/SPIRV Translator
+-//
+-// This file is distributed under the University of Illinois Open Source
+-// License. See LICENSE.TXT for details.
+-//
+-// Copyright (c) 2018 Intel Corporation. All rights reserved.
+-//
+-// Permission is hereby granted, free of charge, to any person obtaining a
+-// copy of this software and associated documentation files (the "Software"),
+-// to deal with the Software without restriction, including without limitation
+-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+-// and/or sell copies of the Software, and to permit persons to whom the
+-// Software is furnished to do so, subject to the following conditions:
+-//
+-// Redistributions of source code must retain the above copyright notice,
+-// this list of conditions and the following disclaimers.
+-// Redistributions in binary form must reproduce the above copyright notice,
+-// this list of conditions and the following disclaimers in the documentation
+-// and/or other materials provided with the distribution.
+-// Neither the names of Intel Corporation, nor the names of its
+-// contributors may be used to endorse or promote products derived from this
+-// Software without specific prior written permission.
+-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+-// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
+-// THE SOFTWARE.
+-//
+-//===----------------------------------------------------------------------===//
+-//
+-// SPIR-V specification doesn't allow function pointers, so SPIR-V translator
+-// is designed to fail if a value with function type (except calls) is occured.
+-// Currently there is only two cases, when function pointers are generating in
+-// LLVM IR in OpenCL - block calls and device side enqueue built-in calls.
+-//
+-// In both cases values with function type used as intermediate representation
+-// for block literal structure.
+-//
+-// This pass is designed to find such cases and simplify them to avoid any
+-// function pointer types occurrences in LLVM IR in 4 steps.
+-//
+-// 1. Find all function pointer allocas, like
+-//      %block = alloca void () *
+-//
+-//    Then find a single store to that alloca:
+-//      %blockLit = alloca <{ i32, i32, ...}>, align 4
+-//      %0 = bitcast <{ i32, i32, ... }>* %blockLit to void ()*
+-//    > store void ()* %0, void ()** %block, align 4
+-//
+-//    And replace the alloca users by new instructions which used stored value
+-//    %blockLit itself instead of function pointer alloca %block.
+-//
+-// 2. Find consecutive casts from block literal type to i8 addrspace(4)*
+-//    used function pointers as an intermediate type:
+-//      %0 = bitcast <{ i32, i32 }> %block to void() *
+-//      %1 = addrspacecast void() * %0 to i8 addrspace(4)*
+-//    And simplify them:
+-//      %2 = addrspacecast <{ i32, i32 }> %block to i8 addrspace(4)*
+-//
+-// 3. Find all unused instructions with function pointer type occured after
+-//    pp.1-2 and remove them.
+-//
+-// 4. Find unused globals with function pointer type, like
+-//    @block = constant void ()*
+-//             bitcast ({ i32, i32 }* @__block_literal_global to void ()*
+-//
+-//    And remove them.
+-//
+-//===----------------------------------------------------------------------===//
+-#define DEBUG_TYPE "spv-lower-ocl-blocks"
+-
+-#include "OCLUtil.h"
+-#include "SPIRVInternal.h"
+-
+-#include "llvm/ADT/SetVector.h"
+-#include "llvm/Analysis/ValueTracking.h"
+-#include "llvm/IR/GlobalVariable.h"
+-#include "llvm/IR/InstIterator.h"
+-#include "llvm/IR/Module.h"
+-#include "llvm/Pass.h"
+-#include "llvm/PassSupport.h"
+-#include "llvm/Support/Casting.h"
+-
+-using namespace llvm;
+-
+-namespace {
+-
+-static void
+-removeUnusedFunctionPtrInst(Instruction *I,
+-                            SmallSetVector<Instruction *, 16> &FuncPtrInsts) {
+-  for (unsigned OpIdx = 0, Ops = I->getNumOperands(); OpIdx != Ops; ++OpIdx) {
+-    Instruction *OpI = dyn_cast<Instruction>(I->getOperand(OpIdx));
+-    I->setOperand(OpIdx, nullptr);
+-    if (OpI && OpI != I && OpI->user_empty())
+-      FuncPtrInsts.insert(OpI);
+-  }
+-  I->eraseFromParent();
+-}
+-
+-static bool isFuncPtrAlloca(const AllocaInst *AI) {
+-  auto *ET = dyn_cast<PointerType>(AI->getAllocatedType());
+-  return ET && ET->getElementType()->isFunctionTy();
+-}
+-
+-static bool hasFuncPtrType(const Value *V) {
+-  auto *PT = dyn_cast<PointerType>(V->getType());
+-  return PT && PT->getElementType()->isFunctionTy();
+-}
+-
+-static bool isFuncPtrInst(const Instruction *I) {
+-  if (auto *AI = dyn_cast<AllocaInst>(I))
+-    return isFuncPtrAlloca(AI);
+-
+-  for (auto &Op : I->operands()) {
+-    if (auto *AI = dyn_cast<AllocaInst>(Op))
+-      return isFuncPtrAlloca(AI);
+-
+-    auto *OpI = dyn_cast<Instruction>(&Op);
+-    if (OpI && OpI != I && hasFuncPtrType(OpI))
+-      return true;
+-  }
+-  return false;
+-}
+-
+-static StoreInst *findSingleStore(AllocaInst *AI) {
+-  StoreInst *Store = nullptr;
+-  for (auto *U : AI->users()) {
+-    if (!isa<StoreInst>(U))
+-      continue; // not a store
+-    if (Store)
+-      return nullptr; // there are more than one stores
+-    Store = dyn_cast<StoreInst>(U);
+-  }
+-  return Store;
+-}
+-
+-static void fixFunctionPtrAllocaUsers(AllocaInst *AI) {
+-  // Find and remove a single store to alloca
+-  auto *SingleStore = findSingleStore(AI);
+-  assert(SingleStore && "More than one store to the function pointer alloca");
+-  auto *StoredVal = SingleStore->getValueOperand();
+-  SingleStore->eraseFromParent();
+-
+-  // Find loads from the alloca and replace thier users
+-  for (auto *U : AI->users()) {
+-    auto *LI = dyn_cast<LoadInst>(U);
+-    if (!LI)
+-      continue;
+-
+-    for (auto *U : LI->users()) {
+-      auto *UInst = cast<Instruction>(U);
+-      auto *Cast = CastInst::CreatePointerBitCastOrAddrSpaceCast(
+-          StoredVal, UInst->getType(), "", UInst);
+-      UInst->replaceAllUsesWith(Cast);
+-    }
+-  }
+-}
+-
+-static int getBlockLiteralIdx(const Function &F) {
+-  StringRef FName = F.getName();
+-  if (isEnqueueKernelBI(FName))
+-    return FName.contains("events") ? 7 : 4;
+-  if (isKernelQueryBI(FName))
+-    return FName.contains("for_ndrange") ? 2 : 1;
+-  if (FName.startswith("__") && FName.contains("_block_invoke"))
+-    return F.hasStructRetAttr() ? 1 : 0;
+-
+-  return -1; // No block literal argument
+-}
+-
+-static bool hasBlockLiteralArg(const Function &F) {
+-  return getBlockLiteralIdx(F) != -1;
+-}
+-
+-static bool simplifyFunctionPtrCasts(Function &F) {
+-  bool Changed = false;
+-  int BlockLiteralIdx = getBlockLiteralIdx(F);
+-  for (auto *U : F.users()) {
+-    auto *Call = dyn_cast<CallInst>(U);
+-    if (!Call)
+-      continue;
+-    if (Call->getFunction()->getName() == F.getName().str() + "_kernel")
+-      continue; // Skip block invoke function calls inside block invoke kernels
+-
+-    const DataLayout &DL = F.getParent()->getDataLayout();
+-    auto *BlockLiteral = Call->getOperand(BlockLiteralIdx);
+-    auto *BlockLiteralVal = GetUnderlyingObject(BlockLiteral, DL);
+-    if (isa<GlobalVariable>(BlockLiteralVal))
+-      continue; // nothing to do with globals
+-
+-    auto *BlockLiteralAlloca = cast<AllocaInst>(BlockLiteralVal);
+-    assert(!BlockLiteralAlloca->getAllocatedType()->isFunctionTy() &&
+-           "Function type shouldn't be there");
+-
+-    auto *NewBlockLiteral = CastInst::CreatePointerBitCastOrAddrSpaceCast(
+-        BlockLiteralAlloca, BlockLiteral->getType(), "", Call);
+-    BlockLiteral->replaceAllUsesWith(NewBlockLiteral);
+-    Changed |= true;
+-  }
+-  return Changed;
+-}
+-
+-static void
+-findFunctionPtrAllocas(Module &M,
+-                       SmallVectorImpl<AllocaInst *> &FuncPtrAllocas) {
+-  for (auto &F : M) {
+-    if (F.isDeclaration())
+-      continue;
+-    for (auto &I : instructions(F)) {
+-      auto *AI = dyn_cast<AllocaInst>(&I);
+-      if (!AI || !isFuncPtrAlloca(AI))
+-        continue;
+-      FuncPtrAllocas.push_back(AI);
+-    }
+-  }
+-}
+-
+-static void
+-findUnusedFunctionPtrInsts(Module &M,
+-                           SmallSetVector<Instruction *, 16> &FuncPtrInsts) {
+-  for (auto &F : M) {
+-    if (F.isDeclaration())
+-      continue;
+-    for (auto &I : instructions(F))
+-      if (I.user_empty() && isFuncPtrInst(&I))
+-        FuncPtrInsts.insert(&I);
+-  }
+-}
+-
+-static void
+-findUnusedFunctionPtrGlbs(Module &M,
+-                          SmallVectorImpl<GlobalVariable *> &FuncPtrGlbs) {
+-  for (auto &GV : M.globals()) {
+-    if (!GV.user_empty())
+-      continue;
+-    auto *GVType = dyn_cast<PointerType>(GV.getType()->getElementType());
+-    if (GVType && GVType->getElementType()->isFunctionTy())
+-      FuncPtrGlbs.push_back(&GV);
+-  }
+-}
+-
+-class SPIRVLowerOCLBlocks : public ModulePass {
+-
+-public:
+-  SPIRVLowerOCLBlocks() : ModulePass(ID) {}
+-
+-  bool runOnModule(Module &M) {
+-    bool Changed = false;
+-
+-    // 1. Find function pointer allocas and fix their users
+-    SmallVector<AllocaInst *, 16> FuncPtrAllocas;
+-    findFunctionPtrAllocas(M, FuncPtrAllocas);
+-
+-    Changed |= !FuncPtrAllocas.empty();
+-    for (auto *AI : FuncPtrAllocas)
+-      fixFunctionPtrAllocaUsers(AI);
+-
+-    // 2. Simplify consecutive casts which use function pointer types
+-    for (auto &F : M)
+-      if (hasBlockLiteralArg(F))
+-        Changed |= simplifyFunctionPtrCasts(F);
+-
+-    // 3. Cleanup unused instructions with function pointer type
+-    // which are occured after pp. 1-2
+-    SmallSetVector<Instruction *, 16> FuncPtrInsts;
+-    findUnusedFunctionPtrInsts(M, FuncPtrInsts);
+-
+-    Changed |= !FuncPtrInsts.empty();
+-    while (!FuncPtrInsts.empty()) {
+-      Instruction *I = FuncPtrInsts.pop_back_val();
+-      removeUnusedFunctionPtrInst(I, FuncPtrInsts);
+-    }
+-
+-    // 4. Find and remove unused global variables with function pointer type
+-    SmallVector<GlobalVariable *, 16> FuncPtrGlbs;
+-    findUnusedFunctionPtrGlbs(M, FuncPtrGlbs);
+-
+-    Changed |= !FuncPtrGlbs.empty();
+-    for (auto *GV : FuncPtrGlbs)
+-      GV->eraseFromParent();
+-
+-    return Changed;
+-  }
+-
+-  static char ID;
+-}; // class SPIRVLowerOCLBlocks
+-
+-char SPIRVLowerOCLBlocks::ID = 0;
+-
+-} // namespace
+-
+-INITIALIZE_PASS(
+-    SPIRVLowerOCLBlocks, "spv-lower-ocl-blocks",
+-    "Remove function pointers occured in case of using OpenCL blocks", false,
+-    false)
+-
+-llvm::ModulePass *llvm::createSPIRVLowerOCLBlocks() {
+-  return new SPIRVLowerOCLBlocks();
+-}
++//===- SPIRVLowerOCLBlocks.cpp - OCL Utilities ----------------------------===//
++//
++//                     The LLVM/SPIRV Translator
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++// Copyright (c) 2018 Intel Corporation. All rights reserved.
++//
++// Permission is hereby granted, free of charge, to any person obtaining a
++// copy of this software and associated documentation files (the "Software"),
++// to deal with the Software without restriction, including without limitation
++// the rights to use, copy, modify, merge, publish, distribute, sublicense,
++// and/or sell copies of the Software, and to permit persons to whom the
++// Software is furnished to do so, subject to the following conditions:
++//
++// Redistributions of source code must retain the above copyright notice,
++// this list of conditions and the following disclaimers.
++// Redistributions in binary form must reproduce the above copyright notice,
++// this list of conditions and the following disclaimers in the documentation
++// and/or other materials provided with the distribution.
++// Neither the names of Intel Corporation, nor the names of its
++// contributors may be used to endorse or promote products derived from this
++// Software without specific prior written permission.
++// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
++// THE SOFTWARE.
++//
++//===----------------------------------------------------------------------===//
++//
++// SPIR-V specification doesn't allow function pointers, so SPIR-V translator
++// is designed to fail if a value with function type (except calls) is occured.
++// Currently there is only two cases, when function pointers are generating in
++// LLVM IR in OpenCL - block calls and device side enqueue built-in calls.
++//
++// In both cases values with function type used as intermediate representation
++// for block literal structure.
++//
++// In LLVM IR produced by clang, blocks are represented with the following
++// structure:
++// %struct.__opencl_block_literal_generic = type { i32, i32, i8 addrspace(4)* }
++// Pointers to block invoke functions are stored in the third field. Clang
++// replaces inderect function calls in all cases except if block is passed as a
++// function argument. Note that it is somewhat unclear if the OpenCL C spec
++// should allow passing blocks as function argumernts. This pass is not supposed
++// to work correctly with such functions.
++// Clang though has to store function pointers to this structure. Purpose of
++// this pass is to replace store of function pointers(not allowed in SPIR-V)
++// with null pointers.
++//
++//===----------------------------------------------------------------------===//
++#define DEBUG_TYPE "spv-lower-ocl-blocks"
++
++#include "SPIRVInternal.h"
++
++#include "llvm/IR/Module.h"
++#include "llvm/Pass.h"
++#include "llvm/Support/Regex.h"
++
++using namespace llvm;
++
++namespace {
++
++static bool isBlockInvoke(Function &F) {
++  static Regex BlockInvokeRegex("_block_invoke_?[0-9]*$");
++  return BlockInvokeRegex.match(F.getName());
++}
++
++class SPIRVLowerOCLBlocks : public ModulePass {
++
++public:
++  SPIRVLowerOCLBlocks() : ModulePass(ID) {}
++
++  bool runOnModule(Module &M) {
++    bool Changed = false;
++    for (Function &F : M) {
++      if (!isBlockInvoke(F))
++        continue;
++      for (User *U : F.users()) {
++        if (!isa<Constant>(U))
++          continue;
++        Constant *Null = Constant::getNullValue(U->getType());
++        if (U != Null) {
++          U->replaceAllUsesWith(Null);
++          Changed = true;
++        }
++      }
++    }
++    return Changed;
++  }
++
++  static char ID;
++};
++
++char SPIRVLowerOCLBlocks::ID = 0;
++
++} // namespace
++
++INITIALIZE_PASS(
++    SPIRVLowerOCLBlocks, "spv-lower-ocl-blocks",
++    "Remove function pointers occured in case of using OpenCL blocks", false,
++    false)
++
++llvm::ModulePass *llvm::createSPIRVLowerOCLBlocks() {
++  return new SPIRVLowerOCLBlocks();
++}
+
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/SPIRV-LLVM-Translator.git/commitdiff/d4711bf22a31337bc4d56858a36a07e02314b267



More information about the pld-cvs-commit mailing list