commit d4711bf22a31337bc4d56858a36a07e02314b267 Author: Jacek Konieczny <j.koniec...@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.sot...@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 _______________________________________________ pld-cvs-commit mailing list pld-cvs-commit@lists.pld-linux.org http://lists.pld-linux.org/mailman/listinfo/pld-cvs-commit