summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/SPIRV/CMakeLists.txt3
-rw-r--r--lib/SPIRV/OCL20To12.cpp140
-rw-r--r--lib/SPIRV/OCLUtil.cpp114
-rw-r--r--lib/SPIRV/OCLUtil.h87
-rw-r--r--lib/SPIRV/SPRVInternal.h156
-rw-r--r--lib/SPIRV/SPRVReader.cpp68
-rw-r--r--lib/SPIRV/SPRVRegularizeOCL20.cpp273
-rw-r--r--lib/SPIRV/SPRVToOCL20.cpp189
-rw-r--r--lib/SPIRV/SPRVUtil.cpp52
-rw-r--r--lib/SPIRV/SPRVWriter.cpp259
-rw-r--r--lib/SPIRV/libSPIRV/SPRVEnum.h47
-rw-r--r--lib/SPIRV/libSPIRV/SPRVInstruction.h34
-rw-r--r--lib/SPIRV/libSPIRV/SPRVModule.cpp18
-rw-r--r--lib/SPIRV/libSPIRV/SPRVModule.h8
-rw-r--r--tools/llvm-spirv/llvm-spirv.cpp2
15 files changed, 1067 insertions, 383 deletions
diff --git a/lib/SPIRV/CMakeLists.txt b/lib/SPIRV/CMakeLists.txt
index 2eea62b..ce431ea 100644
--- a/lib/SPIRV/CMakeLists.txt
+++ b/lib/SPIRV/CMakeLists.txt
@@ -17,10 +17,13 @@ add_llvm_library(LLVMSPIRVLib
Mangler/Mangler.cpp
Mangler/ManglingUtils.cpp
Mangler/ParameterType.cpp
+ OCL20To12.cpp
+ OCLUtil.cpp
SPRVLowerBool.cpp
SPRVLowerOCLBlocks.cpp
SPRVReader.cpp
SPRVRegularizeOCL20.cpp
+ SPRVToOCL20.cpp
SPRVUtil.cpp
SPRVWriter.cpp
)
diff --git a/lib/SPIRV/OCL20To12.cpp b/lib/SPIRV/OCL20To12.cpp
new file mode 100644
index 0000000..ab645ad
--- /dev/null
+++ b/lib/SPIRV/OCL20To12.cpp
@@ -0,0 +1,140 @@
+//===- OCL20To12.cpp - Transform OCL 2.0 builtins to OCL 1.2 builtins -----===//
+//
+// The LLVM/SPIRV Translator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// Copyright (c) 2014 Advanced Micro Devices, Inc. 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 Advanced Micro Devices, Inc., 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements transform OCL 2.0 builtins to OCL 1.2 builtins.
+//
+//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "ocl20to12"
+
+#include "SPRVInternal.h"
+#include "OCLUtil.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/InstVisitor.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Pass.h"
+#include "llvm/PassSupport.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace SPRV;
+using namespace OCLUtil;
+
+namespace SPRV {
+class OCL20To12: public ModulePass,
+ public InstVisitor<OCL20To12> {
+public:
+ OCL20To12():ModulePass(ID), M(nullptr), Ctx(nullptr) {
+ initializeOCL20To12Pass(*PassRegistry::getPassRegistry());
+ }
+ virtual bool runOnModule(Module &M);
+ virtual void visitCallInst(CallInst &CI);
+
+ /// Transform atomic_work_item_fence to mem_fence.
+ /// atomic_work_item_fence(flag, relaxed, work_group) =>
+ /// mem_fence(flag)
+ void visitCallAtomicWorkItemFence(CallInst *CI);
+
+ static char ID;
+private:
+ Module *M;
+ LLVMContext *Ctx;
+};
+
+char OCL20To12::ID = 0;
+
+bool
+OCL20To12::runOnModule(Module& Module) {
+ M = &Module;
+ if (getOCLVersion(M) >= 20)
+ return false;
+
+ Ctx = &M->getContext();
+ visit(*M);
+
+ DEBUG(dbgs() << "After OCL20To12:\n" << *M);
+
+ std::string Err;
+ raw_string_ostream ErrorOS(Err);
+ if (verifyModule(*M, &ErrorOS)){
+ DEBUG(errs() << "Fails to verify module: " << ErrorOS.str());
+ }
+ return true;
+}
+
+void
+OCL20To12::visitCallInst(CallInst& CI) {
+ DEBUG(dbgs() << "[visistCallInst] " << CI << '\n');
+ auto F = CI.getCalledFunction();
+ if (!F)
+ return;
+
+ auto MangledName = F->getName();
+ std::string DemangledName;
+ if (!oclIsBuiltin(MangledName, 20, &DemangledName))
+ return;
+ DEBUG(dbgs() << "DemangledName = " << DemangledName.c_str() << '\n');
+
+ if (DemangledName == kOCLBuiltinName::AtomicWorkItemFence) {
+ visitCallAtomicWorkItemFence(&CI);
+ return;
+ }
+}
+
+void OCL20To12::visitCallAtomicWorkItemFence(CallInst* CI) {
+ auto Lit = getAtomicWorkItemFenceLiterals(CI);
+ if (std::get<1>(Lit) != OCLLegacyAtomicMemOrder ||
+ std::get<2>(Lit) != OCLLegacyAtomicMemScope)
+ report_fatal_error("OCL 2.0 builtin atomic_work_item_fence used in 1.2",
+ false);
+
+ AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
+ mutateCallInst(M, CI, [=](CallInst *, std::vector<Value *> &Args){
+ Args.resize(1);
+ Args[0] = getInt32(M, std::get<0>(Lit));
+ return kOCLBuiltinName::MemFence;
+ }, true, &Attrs);
+}
+
+}
+
+INITIALIZE_PASS(OCL20To12, "ocl20to12",
+ "Translate OCL 2.0 builtins to OCL 1.2 builtins", false, false)
+
+ModulePass *llvm::createOCL20To12() {
+ return new OCL20To12();
+}
diff --git a/lib/SPIRV/OCLUtil.cpp b/lib/SPIRV/OCLUtil.cpp
new file mode 100644
index 0000000..f458177
--- /dev/null
+++ b/lib/SPIRV/OCLUtil.cpp
@@ -0,0 +1,114 @@
+//===- OCLUtil.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) 2014 Advanced Micro Devices, Inc. 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 Advanced Micro Devices, Inc., 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements OCL utility functions.
+//
+//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "oclutil"
+
+#include "SPRVInternal.h"
+#include "OCLUtil.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/InstVisitor.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Pass.h"
+#include "llvm/PassSupport.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace SPRV;
+
+namespace OCLUtil {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Functions for getting builtin call info
+//
+///////////////////////////////////////////////////////////////////////////////
+AtomicWorkItemFenceLiterals getAtomicWorkItemFenceLiterals(CallInst* CI) {
+ AtomicWorkItemFenceLiterals Tup;
+ auto getArg = [=](unsigned I){
+ return cast<ConstantInt>(CI->getArgOperand(I))->getZExtValue();
+ };
+ return std::make_tuple(getArg(0),
+ static_cast<OCLMemOrderKind>(getArg(1)),
+ static_cast<OCLMemScopeKind>(getArg(2)));
+}
+
+size_t getAtomicBuiltinNumMemoryOrderArgs(StringRef Name) {
+ if (Name.find("compare_exchange_strong") != StringRef::npos)
+ return 2;
+ return 1;
+}
+///////////////////////////////////////////////////////////////////////////////
+//
+// Functions for getting metadata
+//
+///////////////////////////////////////////////////////////////////////////////
+int
+getMDOperandAsInt(MDNode* N, unsigned I) {
+ return mdconst::dyn_extract<ConstantInt>(N->getOperand(I))->getZExtValue();
+}
+
+std::string
+getMDOperandAsString(MDNode* N, unsigned I) {
+ Metadata* Op = N->getOperand(I);
+
+ if (!Op)
+ return "";
+ if (MDString* Str = dyn_cast<MDString>(Op)) {
+ return Str->getString().str();
+ }
+ return "";
+}
+
+Type*
+getMDOperandAsType(MDNode* N, unsigned I) {
+ return cast<ValueAsMetadata>(N->getOperand(I))->getType();
+}
+
+unsigned getOCLVersion(Module *M) {
+ NamedMDNode *NamedMD = M->getNamedMetadata(SPIR_MD_OCL_VERSION);
+ assert (NamedMD && "Invalid SPIR");
+ assert (NamedMD->getNumOperands() == 1 && "Invalid SPIR");
+ MDNode *MD = NamedMD->getOperand(0);
+ unsigned Major = getMDOperandAsInt(MD, 0);
+ unsigned Minor = getMDOperandAsInt(MD, 1);
+ return Major * 10 + Minor;
+}
+}
+
diff --git a/lib/SPIRV/OCLUtil.h b/lib/SPIRV/OCLUtil.h
new file mode 100644
index 0000000..ee71a86
--- /dev/null
+++ b/lib/SPIRV/OCLUtil.h
@@ -0,0 +1,87 @@
+//===- OCLUtil.h - OCL Utilities declarations -------------------*- C++ -*-===//
+//
+// The LLVM/SPIRV Translator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// Copyright (c) 2014 Advanced Micro Devices, Inc. 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 Advanced Micro Devices, Inc., 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares OCL utility functions.
+//
+//===----------------------------------------------------------------------===//
+#include "SPRVInternal.h"
+
+#include <utility>
+#include <tuple>
+#include <functional>
+using namespace SPRV;
+using namespace llvm;
+
+namespace OCLUtil {
+
+typedef std::tuple<unsigned, OCLMemOrderKind, OCLMemScopeKind>
+ AtomicWorkItemFenceLiterals;
+
+/// Information for translating OCL builtin.
+struct OCLBuiltinTransInfo {
+ std::string UniqName;
+ /// Postprocessor of operands
+ std::function<void(std::vector<Value *>&)> PostProc;
+ OCLBuiltinTransInfo(){
+ PostProc = [](std::vector<Value *>&){};
+ }
+};
+
+/// OCL 1.x atomic memory order when translated to 2.0 atomics.
+const OCLMemOrderKind OCLLegacyAtomicMemOrder = OCLMO_seq_cst;
+
+/// OCL 1.x atomic memory scope when translated to 2.0 atomics.
+const OCLMemScopeKind OCLLegacyAtomicMemScope = OCLMS_device;
+
+/// Get literal arguments of call of atomic_work_item_fence.
+AtomicWorkItemFenceLiterals getAtomicWorkItemFenceLiterals(CallInst* CI);
+
+/// Get number of memory order arguments for atomic builtin function.
+size_t getAtomicBuiltinNumMemoryOrderArgs(StringRef Name);
+
+/// Get metadata operand as int.
+int getMDOperandAsInt(MDNode* N, unsigned I);
+
+/// Get metadata operand as string.
+std::string getMDOperandAsString(MDNode* N, unsigned I);
+
+/// Get metadata operand as type.
+Type* getMDOperandAsType(MDNode* N, unsigned I);
+
+/// Get OCL version from metadata opencl.ocl.version.
+/// \return 20 for OCL 2.0, 12 for OCL 1.2.
+unsigned getOCLVersion(Module *M);
+
+}
+
diff --git a/lib/SPIRV/SPRVInternal.h b/lib/SPIRV/SPRVInternal.h
index 363627d..f08b485 100644
--- a/lib/SPIRV/SPRVInternal.h
+++ b/lib/SPIRV/SPRVInternal.h
@@ -49,6 +49,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/Support/SPIRV.h"
+#include <utility>
#include <functional>
using namespace SPRV;
@@ -177,29 +178,26 @@ enum SPIRAddressSpace {
SPIRAS_Count,
};
-enum SPIRMemFenceFlagKind {
-#define _SPRV_OP(x,y) SPIRMFF_##x = y,
-_SPRV_OP(Local, 1)
-_SPRV_OP(Global, 2)
-_SPRV_OP(Image, 4)
-#undef _SPRV_OP
+enum OCLMemFenceKind {
+ OCLMF_Local = 1,
+ OCLMF_Global = 2,
+ OCLMF_Image = 4,
};
-enum SPIRMemScopeKind {
- SPIRMS_work_item,
- SPIRMS_work_group,
- SPIRMS_device,
- SPIRMS_all_svm_devices,
- SPIRMS_sub_group,
- SPIRMS_Count,
+enum OCLMemScopeKind {
+ OCLMS_work_item,
+ OCLMS_work_group,
+ OCLMS_device,
+ OCLMS_all_svm_devices,
+ OCLMS_sub_group,
};
-enum SPIRMemoryOrderKind {
- SPIRMO_relaxed,
- SPIRMO_acquire,
- SPIRMO_release,
- SPIRMO_acq_rel,
- SPIRMO_seq_cst
+enum OCLMemOrderKind {
+ OCLMO_relaxed,
+ OCLMO_acquire,
+ OCLMO_release,
+ OCLMO_acq_rel,
+ OCLMO_seq_cst
};
template<> inline void
@@ -306,7 +304,6 @@ _SPRV_OP(fetch_max_explicit, AtomicSMax)
_SPRV_OP(fetch_and_explicit, AtomicAnd)
_SPRV_OP(fetch_or_explicit, AtomicOr)
_SPRV_OP(fetch_xor_explicit, AtomicXor)
-_SPRV_OP(work_item_fence, MemoryBarrier)
#undef _SPRV_OP
#define _SPRV_OP(x,y) add(#x, Op##y);
_SPRV_OP(dot, Dot)
@@ -392,7 +389,7 @@ _SPRV_OP(get_image_num_samples, ImageQuerySamples)
#undef _SPRV_OP
}
typedef SPRVMap<std::string, Op, SPRVInstruction>
- SPIRSPRVBuiltinInstMap;
+ OCLSPRVBuiltinMap;
template<> inline void
SPRVMap<GlobalValue::LinkageTypes, SPRVLinkageTypeKind>::init() {
@@ -435,28 +432,52 @@ typedef SPRVMap<Attribute::AttrKind, SPRVFunctionControlMaskKind>
SPIRSPRVFuncCtlMaskMap;
template<> inline void
-SPRVMap<SPIRMemFenceFlagKind, SPRVMemorySemanticsMaskKind>::init() {
-#define _SPRV_OP(x,y) add(SPIRMFF_##x, SPRVMSM_##y);
-_SPRV_OP(Local, WorkgroupLocalMemory)
-_SPRV_OP(Global, WorkgroupGlobalMemory)
-_SPRV_OP(Image, ImageMemory)
-#undef _SPRV_OP
+SPRVMap<OCLMemFenceKind, MemorySemanticsMask>::init() {
+ add(OCLMF_Local, MemorySemanticsWorkgroupLocalMemoryMask);
+ add(OCLMF_Global, MemorySemanticsWorkgroupGlobalMemoryMask);
+ add(OCLMF_Image, MemorySemanticsImageMemoryMask);
}
-typedef SPRVMap<SPIRMemFenceFlagKind, SPRVMemorySemanticsMaskKind>
- SPIRSPRVMemFenceFlagMap;
+typedef SPRVMap<OCLMemFenceKind, MemorySemanticsMask>
+ OCLMemFenceMap;
template<> inline void
-SPRVMap<SPIRMemScopeKind, SPRVMemoryScopeKind>::init() {
-#define _SPRV_OP(x,y) add(SPIRMS_##x, SPRVMS_##y);
- _SPRV_OP(work_item, Invocation)
- _SPRV_OP(work_group, Workgroup)
- _SPRV_OP(device, Device)
- _SPRV_OP(all_svm_devices, CrossDevice)
- _SPRV_OP(sub_group, Subgroup)
-#undef _SPRV_OP
+SPRVMap<OCLMemOrderKind, unsigned, MemorySemanticsMask>::init() {
+ add(OCLMO_relaxed, MemorySemanticsRelaxedMask);
+ add(OCLMO_acquire, MemorySemanticsAcquireMask);
+ add(OCLMO_release, MemorySemanticsReleaseMask);
+ add(OCLMO_acq_rel, MemorySemanticsAcquireMask|MemorySemanticsReleaseMask);
+ add(OCLMO_seq_cst, MemorySemanticsSequentiallyConsistentMask);
+}
+typedef SPRVMap<OCLMemOrderKind, unsigned, MemorySemanticsMask>
+ OCLMemOrderMap;
+
+inline unsigned mapOCLMemSemanticToSPRV(unsigned MemFenceFlag,
+ OCLMemOrderKind Order) {
+ return OCLMemOrderMap::map(Order) |
+ mapBitMask<OCLMemFenceMap>(MemFenceFlag);
+}
+
+inline std::pair<unsigned, OCLMemOrderKind>
+mapSPRVMemSemanticToOCL(unsigned Sema) {
+ return std::make_pair(rmapBitMask<OCLMemFenceMap>(Sema),
+ OCLMemOrderMap::rmap(Sema & 0xF));
+}
+
+inline OCLMemOrderKind
+mapSPRVMemOrderToOCL(unsigned Sema) {
+ return OCLMemOrderMap::rmap(Sema & 0xF);
+}
+
+template<> inline void
+SPRVMap<OCLMemScopeKind, Scope>::init() {
+ add(OCLMS_work_item, ScopeInvocation);
+ add(OCLMS_work_group, ScopeWorkgroup);
+ add(OCLMS_device, ScopeDevice);
+ add(OCLMS_all_svm_devices, ScopeCrossDevice);
+ add(OCLMS_sub_group, ScopeSubgroup);
}
-typedef SPRVMap<SPIRMemScopeKind, SPRVMemoryScopeKind>
- SPIRSPRVMemScopeMap;
+typedef SPRVMap<OCLMemScopeKind, Scope>
+ OCLMemScopeMap;
template<> inline void
SPRVMap<std::string, SPRVGroupOperationKind>::init() {
@@ -539,7 +560,12 @@ namespace kMangledName {
}
namespace kOCLBuiltinName {
+ const static char AtomPrefix[] = "atom_";
+ const static char AtomCmpXchg[] = "atom_cmpxchg";
const static char AtomicPrefix[] = "atomic_";
+ const static char AtomicCmpXchg[] = "atomic_cmpxchg";
+ const static char AtomicInit[] = "atomic_init";
+ const static char AtomicWorkItemFence[] = "atomic_work_item_fence";
const static char Barrier[] = "barrier";
const static char EnqueueKernel[] = "enqueue_kernel";
const static char GetFence[] = "get_fence";
@@ -547,6 +573,7 @@ namespace kOCLBuiltinName {
const static char GetImageDim[] = "get_image_dim";
const static char GetImageHeight[] = "get_image_height";
const static char GetImageWidth[] = "get_image_width";
+ const static char MemFence[] = "mem_fence";
const static char NDRangePrefix[] = "ndrange_";
const static char ToGlobal[] = "to_global";
const static char ToLocal[] = "to_local";
@@ -689,6 +716,31 @@ getTypes(T V) {
return Tys;
}
+/// Move elements of std::vector from [begin, end) to target.
+template <typename T>
+void move(std::vector<T>& V, size_t begin, size_t end, size_t target) {
+ assert(begin < end && end <= V.size() && target <= V.size() &&
+ !(begin < target && target < end));
+ if (begin <= target && target <= end)
+ return;
+ auto B = V.begin() + begin, E = V.begin() + end;
+ if (target > V.size())
+ target = V.size();
+ if (target > end)
+ target -= (end - begin);
+ std::vector<T> Segment(B, E);
+ V.erase(B, E);
+ V.insert(V.begin() + target, Segment.begin(), Segment.end());
+}
+
+/// Find position of first pointer type value in a vector.
+inline size_t findFirstPtr(const std::vector<Value *> &Args) {
+ auto PtArg = std::find_if(Args.begin(), Args.end(), [](Value *V){
+ return V->getType()->isPointerTy();
+ });
+ return PtArg - Args.begin();
+}
+
void removeFnAttr(LLVMContext *Context, CallInst *Call,
Attribute::AttrKind Attr);
void addFnAttr(LLVMContext *Context, CallInst *Call,
@@ -716,6 +768,12 @@ std::string decorateSPRVFunction(const std::string &S);
std::string undecorateSPRVFunction(const std::string &S);
bool isSPRVFunction(const Function *F, std::string *UndecName = nullptr);
+/// Get a canonical function name for a SPIR-V op code.
+std::string getSPRVFuncName(Op OC);
+
+/// Get SPIR-V op code given the canonical function name.
+Op getSPRVFuncOC(const std::string& S);
+
/// \param Name LLVM function name
/// \param OpenCLVer version of OpenCL source file. Suppotred values are 12, 20
/// and 21.
@@ -777,6 +835,14 @@ ConstantInt *getInt64(Module *M, int64_t value);
/// Get a 32 bit integer constant.
ConstantInt *getInt32(Module *M, int value);
+/// Map an unsigned integer constant by applying a function.
+ConstantInt *mapUInt(Module *M, ConstantInt *I,
+ std::function<unsigned(unsigned)> F);
+
+/// Map a signed integer constant by applying a function.
+ConstantInt *mapSInt(Module *M, ConstantInt *I,
+ std::function<int(int)> F);
+
/// Mangle name for OCL builtin functions.
/// \param UniqName is unique unmangled name for OCL builtin functions,
/// which is transformed and unique version of original unmangled
@@ -815,16 +881,28 @@ getSPRVSampledImageType(Module *M, Type *ImageType);
bool
eraseUselessFunctions(Module *M);
+// Check if a mangled type name is unsigned
+bool
+isMangledTypeUnsigned(char Mangled);
+
+// Check if a mangled function name contains unsigned atomic type
+bool
+containsUnsignedAtomicType(StringRef Name);
+
}
namespace llvm {
void initializeSPRVRegularizeOCL20Pass(PassRegistry&);
void initializeSPRVLowerOCLBlocksPass(PassRegistry&);
void initializeSPRVLowerBoolPass(PassRegistry&);
+void initializeSPRVToOCL20Pass(PassRegistry&);
+void initializeOCL20To12Pass(PassRegistry&);
ModulePass *createSPRVRegularizeOCL20();
ModulePass *createSPRVLowerOCLBlocks();
ModulePass *createSPRVLowerBool();
+ModulePass *createSPRVToOCL20();
+ModulePass *createOCL20To12();
}
#endif
diff --git a/lib/SPIRV/SPRVReader.cpp b/lib/SPIRV/SPRVReader.cpp
index f71afba..33b1dde 100644
--- a/lib/SPIRV/SPRVReader.cpp
+++ b/lib/SPIRV/SPRVReader.cpp
@@ -56,6 +56,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h"
+#include "llvm/PassManager.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Dwarf.h"
@@ -288,9 +289,10 @@ public:
bool transSourceExtension();
bool transCompilerOption();
Value *transConvertInst(SPRVValue* BV, Function* F, BasicBlock* BB);
- Instruction *transOCLBuiltinFromInst(const std::string& FuncName,
+ Instruction *transBuiltinFromInst(const std::string& FuncName,
SPRVInstruction* BI, BasicBlock* BB);
Instruction *transOCLBuiltinFromInst(SPRVInstruction *BI, BasicBlock *BB);
+ Instruction *transSPRVBuiltinFromInst(SPRVInstruction *BI, BasicBlock *BB);
Instruction *transOCLBarrierFence(SPRVInstruction* BI, BasicBlock *BB);
Instruction *transOCLDot(SPRVDot *BD, BasicBlock *BB);
void transOCLVectorLoadStore(std::string& UnmangledName,
@@ -619,10 +621,10 @@ SPRVToLLVM::transOCLGroupBuiltinName(std::string &DemangledName,
auto ES = IT->getExecutionScope();
std::string Prefix;
switch(ES) {
- case SPRVES_Workgroup:
+ case ScopeWorkgroup:
Prefix = kOCLBuiltinName::WorkPrefix;
break;
- case SPRVES_Subgroup:
+ case ScopeSubgroup:
Prefix = kOCLBuiltinName::SubPrefix;
break;
default:
@@ -1555,22 +1557,28 @@ SPRVToLLVM::transValueWithoutDecoration(SPRVValue *BV, Function *F,
}
break;
- default:
- if (isSPRVCmpInstTransToLLVMInst(static_cast<SPRVInstruction*>(BV))) {
- return mapValue(BV, transCmpInst(BV, BB, F));
- } else if (SPIRSPRVBuiltinInstMap::rfind(BV->getOpCode(), nullptr)) {
- return mapValue(BV, transOCLBuiltinFromInst(
- static_cast<SPRVInstruction *>(BV), BB));
- } else if (isBinaryShiftLogicalBitwiseOpCode(BV->getOpCode())) {
- return mapValue(BV, transShiftLogicalBitwiseInst(BV, BB, F));
- } else if (isCvtOpCode(BV->getOpCode())) {
- auto BI = static_cast<SPRVInstruction *>(BV);
- Value *Inst = nullptr;
- if (BI->hasFPRoundingMode() || BI->isSaturatedConversion())
- Inst = transOCLBuiltinFromInst(BI, BB);
- else
- Inst = transConvertInst(BV, F, BB);
- return mapValue(BV, Inst);
+ default: {
+ auto OC = BV->getOpCode();
+ if (isSPRVCmpInstTransToLLVMInst(static_cast<SPRVInstruction*>(BV))) {
+ return mapValue(BV, transCmpInst(BV, BB, F));
+ } else if (OCLSPRVBuiltinMap::rfind(OC, nullptr) &&
+ !isAtomicOpCode(OC)) {
+ return mapValue(BV, transOCLBuiltinFromInst(
+ static_cast<SPRVInstruction *>(BV), BB));
+ } else if (isBinaryShiftLogicalBitwiseOpCode(OC) ||
+ isLogicalOpCode(OC)) {
+ return mapValue(BV, transShiftLogicalBitwiseInst(BV, BB, F));
+ } else if (isCvtOpCode(OC)) {
+ auto BI = static_cast<SPRVInstruction *>(BV);
+ Value *Inst = nullptr;
+ if (BI->hasFPRoundingMode() || BI->isSaturatedConversion())
+ Inst = transOCLBuiltinFromInst(BI, BB);
+ else
+ Inst = transConvertInst(BV, F, BB);
+ return mapValue(BV, Inst);
+ }
+ return mapValue(BV, transSPRVBuiltinFromInst(
+ static_cast<SPRVInstruction *>(BV), BB));
}
SPRVDBG(bildbgs() << "Cannot translate " << *BV << '\n';)
@@ -1674,9 +1682,6 @@ SPRVToLLVM::transOCLBuiltinFromInstPreproc(SPRVInstruction* BI, Type *&RetTy,
BT->getVectorComponentCount());
else
llvm_unreachable("invalid compare instruction");
- } else if (OC == OpAtomicIIncrement ||
- OC == OpAtomicIDecrement) {
- Args.erase(Args.begin() + Args.size() - 2, Args.end());
}
}
@@ -1700,7 +1705,7 @@ SPRVToLLVM::transOCLBuiltinFromInstPostproc(SPRVInstruction* BI,
}
Instruction *
-SPRVToLLVM::transOCLBuiltinFromInst(const std::string& FuncName,
+SPRVToLLVM::transBuiltinFromInst(const std::string& FuncName,
SPRVInstruction* BI, BasicBlock* BB) {
std::string MangledName;
auto Ops = BI->getOperands();
@@ -1771,7 +1776,7 @@ SPRVToLLVM::getOCLBuiltinName(SPRVInstruction* BI) {
// Do nothing.
break;
}
- auto Name = SPIRSPRVBuiltinInstMap::rmap(OC);
+ auto Name = OCLSPRVBuiltinMap::rmap(OC);
transOCLGroupBuiltinName(Name, BI);
SPRVType *T = nullptr;
@@ -1798,7 +1803,13 @@ Instruction *
SPRVToLLVM::transOCLBuiltinFromInst(SPRVInstruction *BI, BasicBlock *BB) {
assert(BB && "Invalid BB");
auto FuncName = getOCLBuiltinName(BI);
- return transOCLBuiltinFromInst(FuncName, BI, BB);
+ return transBuiltinFromInst(FuncName, BI, BB);
+}
+
+Instruction *
+SPRVToLLVM::transSPRVBuiltinFromInst(SPRVInstruction *BI, BasicBlock *BB) {
+ assert(BB && "Invalid BB");
+ return transBuiltinFromInst(getSPRVFuncName(BI->getOpCode()), BI, BB);
}
bool
@@ -2173,7 +2184,7 @@ SPRVToLLVM::transOCLBarrierFence(SPRVInstruction* MB, BasicBlock *BB) {
Func->addFnAttr(Attribute::NoUnwind);
}
Value *Arg[] = {ConstantInt::get(Int32Ty,
- rmapBitMask<SPIRSPRVMemFenceFlagMap>(MemSema))};
+ rmapBitMask<OCLMemFenceMap>(MemSema))};
auto Call = CallInst::Create(Func, Arg, "", BB);
Call->setName(MB->getName());
setAttrByCalledFunc(Call);
@@ -2290,6 +2301,11 @@ llvm::ReadSPRV(LLVMContext &C, std::istream &IS, Module *&M,
BM->getError(ErrMsg);
Succeed = false;
}
+ PassManager PassMgr;
+ PassMgr.add(createSPRVToOCL20());
+ PassMgr.add(createOCL20To12());
+ PassMgr.run(*M);
+
if (DbgSaveTmpLLVM)
dumpLLVM(M, DbgTmpLLVMFileName);
if (!Succeed) {
diff --git a/lib/SPIRV/SPRVRegularizeOCL20.cpp b/lib/SPIRV/SPRVRegularizeOCL20.cpp
index 641be16..0c74ef9 100644
--- a/lib/SPIRV/SPRVRegularizeOCL20.cpp
+++ b/lib/SPIRV/SPRVRegularizeOCL20.cpp
@@ -1,4 +1,4 @@
-//===- LLVMSPRVRegularizeOCL20.cpp – Regularize OCL20 builtins---*- C++ -*-===//
+//===- SPRVRegularizeOCL20.cpp - Regularize OCL20 builtins-------*- C++ -*-===//
//
// The LLVM/SPIRV Translator
//
@@ -38,6 +38,7 @@
#define DEBUG_TYPE "spvcl20"
#include "SPRVInternal.h"
+#include "OCLUtil.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/Instructions.h"
@@ -50,8 +51,19 @@
using namespace llvm;
using namespace SPRV;
+using namespace OCLUtil;
namespace SPRV {
+static size_t
+getOCLCpp11AtomicMaxNumOps(StringRef Name) {
+ return StringSwitch<size_t>(Name)
+ .Cases("load", "flag_test_and_set", "flag_clear", 3)
+ .Cases("store", "exchange", 4)
+ .StartsWith("compare_exchange", 6)
+ .StartsWith("fetch", 4)
+ .Default(0);
+}
+
class SPRVRegularizeOCL20: public ModulePass,
public InstVisitor<SPRVRegularizeOCL20> {
public:
@@ -61,32 +73,64 @@ public:
virtual void getAnalysisUsage(AnalysisUsage &AU);
virtual bool runOnModule(Module &M);
virtual void visitCallInst(CallInst &CI);
- void visitCallGetFence(CallInst *CI, const std::string &DemangledName);
- void visitCallNDRange(CallInst *CI, const std::string &DemangledName);
+
+ /// Transform atomic_work_item_fence/mem_fence to __spirv_MemoryBarrier.
+ /// func(flag, order, scope) =>
+ /// __spirv_MemoryBarrier(map(scope), map(flag)|map(order))
+ void transMemoryBarrier(CallInst *CI, AtomicWorkItemFenceLiterals);
+
+ /// Transform atomic_* to __spirv_Atomic*.
+ /// atomic_x(ptr_arg, args, order, scope) =>
+ /// __spirv_AtomicY(ptr_arg, map(order), map(scope), args)
+ void transAtomicBuiltin(CallInst *CI, OCLBuiltinTransInfo &Info);
+
+ /// Transform atomic_work_item_fence to __spirv_MemoryBarrier.
+ /// atomic_work_item_fence(flag, order, scope) =>
+ /// __spirv_MemoryBarrier(map(scope), map(flag)|map(order))
+ void visitCallAtomicWorkItemFence(CallInst *CI);
/// Transform atom_cmpxchg/atomic_cmpxchg to atomic_compare_exchange.
/// In atom_cmpxchg/atomic_cmpxchg, the expected value parameter is a value.
/// However in atomic_compare_exchange it is a pointer. The transformation
/// adds an alloca instruction, store the expected value in the pointer, and
/// pass the pointer as argument.
- void visitCallAtomicCmpXchg(CallInst *CI, const std::string &DemangledName);
+ /// \returns the call instruction of atomic_compare_exchange_strong.
+ CallInst *visitCallAtomicCmpXchg(CallInst *CI, const std::string &DemangledName);
/// Transform atomic_init.
/// atomic_init(p, x) => store p, x
void visitCallAtomicInit(CallInst *CI);
- /// Transform read_image with sampler arguments.
- /// read_image(image, sampler, ...) =>
- /// sampled_image = __spirv_SampledImage__(image, sampler);
- /// return __spirv_ImageSampleExplicitLod__(sampled_image, ...);
- void visitCallReadImage(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
+ /// Transform legacy OCL 1.x atomic builtins to SPIR-V builtins for extensions
+ /// cl_khr_int64_base_atomics
+ /// cl_khr_int64_extended_atomics
+ /// Do nothing if the called function is not a legacy atomic builtin.
+ void visitCallAtomicLegacy(CallInst *CI, StringRef MangledName,
+ const std::string &DemangledName);
+
+ /// Transform OCL 2.0 C++11 atomic builtins to SPIR-V builtins.
+ /// Do nothing if the called function is not a C++11 atomic builtin.
+ void visitCallAtomicCpp11(CallInst *CI, StringRef MangledName,
+ const std::string &DemangledName);
/// Transform get_image_{width|height|depth|dim}.
/// get_image_xxx(...) =>
/// dimension = __spirv_ImageQuerySizeLod__(...);
/// return dimension.{x|y|z};
void visitCallGetImageSize(CallInst *CI, StringRef MangledName,
+ const std::string &DemangledName);
+
+ /// Transform mem_fence to __spirv_MemoryBarrier.
+ /// mem_fence(flag) => __spirv_MemoryBarrier(Workgroup, map(flag))
+ void visitCallMemFence(CallInst *CI);
+
+ void visitCallNDRange(CallInst *CI, const std::string &DemangledName);
+
+ /// Transform read_image with sampler arguments.
+ /// read_image(image, sampler, ...) =>
+ /// sampled_image = __spirv_SampledImage__(image, sampler);
+ /// return __spirv_ImageSampleExplicitLod__(sampled_image, ...);
+ void visitCallReadImage(CallInst *CI, StringRef MangledName,
const std::string &DemangledName);
void visitDbgInfoIntrinsic(DbgInfoIntrinsic &I){
@@ -97,6 +141,11 @@ public:
private:
Module *M;
LLVMContext *Ctx;
+
+ ConstantInt *addInt32(int I) {
+ return getInt32(M, I);
+ }
+
};
char SPRVRegularizeOCL20::ID = 0;
@@ -116,7 +165,7 @@ SPRVRegularizeOCL20::runOnModule(Module& Module) {
std::string Err;
raw_string_ostream ErrorOS(Err);
if (verifyModule(*M, &ErrorOS)){
- DEBUG(errs() << "Fails to verify module: " << Err);
+ DEBUG(errs() << "Fails to verify module: " << ErrorOS.str());
}
return true;
}
@@ -137,13 +186,23 @@ SPRVRegularizeOCL20::visitCallInst(CallInst& CI) {
visitCallNDRange(&CI, DemangledName);
return;
}
- if (DemangledName == "atom_cmpxchg" ||
- DemangledName == "atomic_cmpxchg") {
- visitCallAtomicCmpXchg(&CI, DemangledName);
- return;
- }
- if (DemangledName == "atomic_init") {
- visitCallAtomicInit(&CI);
+ if (DemangledName.find(kOCLBuiltinName::AtomicPrefix) == 0 ||
+ DemangledName.find(kOCLBuiltinName::AtomPrefix) == 0) {
+ auto PCI = &CI;
+ if (DemangledName == kOCLBuiltinName::AtomicInit) {
+ visitCallAtomicInit(PCI);
+ return;
+ }
+ if (DemangledName == kOCLBuiltinName::AtomicWorkItemFence) {
+ visitCallAtomicWorkItemFence(PCI);
+ return;
+ }
+ if (DemangledName == kOCLBuiltinName::AtomCmpXchg ||
+ DemangledName == kOCLBuiltinName::AtomicCmpXchg) {
+ PCI = visitCallAtomicCmpXchg(PCI, DemangledName);
+ }
+ visitCallAtomicLegacy(PCI, MangledName, DemangledName);
+ visitCallAtomicCpp11(PCI, MangledName, DemangledName);
return;
}
if (DemangledName.find(kOCLBuiltinName::ReadImage) == 0) {
@@ -157,6 +216,10 @@ SPRVRegularizeOCL20::visitCallInst(CallInst& CI) {
visitCallGetImageSize(&CI, MangledName, DemangledName);
return;
}
+ if (DemangledName == kOCLBuiltinName::MemFence) {
+ visitCallMemFence(&CI);
+ return;
+ }
}
@@ -200,18 +263,28 @@ SPRVRegularizeOCL20::visitCallNDRange(CallInst *CI,
}, true, &Attrs);
}
-void
+CallInst *
SPRVRegularizeOCL20::visitCallAtomicCmpXchg(CallInst* CI,
const std::string& DemangledName) {
AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInst(M, CI, [=](CallInst *, std::vector<Value *> &Args){
+ Value *Alloca = nullptr;
+ CallInst *NewCI = nullptr;
+ mutateCallInst(M, CI, [&](CallInst *, std::vector<Value *> &Args,
+ Type *&RetTy){
auto &CmpVal = Args[1];
- auto Alloca = new AllocaInst(CmpVal->getType(), "",
- CI->getParent()->getParent()->front().begin());
+ Alloca = new AllocaInst(CmpVal->getType(), "",
+ CI->getParent()->getParent()->getEntryBlock().getFirstInsertionPt());
auto Store = new StoreInst(CmpVal, Alloca, CI);
CmpVal = Alloca;
+ RetTy = Type::getInt1Ty(*Ctx);
return "atomic_compare_exchange_strong";
- }, true, &Attrs);
+ },
+ [&](CallInst *NCI)->Instruction * {
+ NewCI = NCI;
+ return new LoadInst(Alloca, "", false, NCI->getNextNode());
+ },
+ true, &Attrs);
+ return NewCI;
}
void
@@ -223,6 +296,160 @@ SPRVRegularizeOCL20::visitCallAtomicInit(CallInst* CI) {
}
void
+SPRVRegularizeOCL20::visitCallAtomicWorkItemFence(CallInst* CI) {
+ transMemoryBarrier(CI, getAtomicWorkItemFenceLiterals(CI));
+}
+
+void
+SPRVRegularizeOCL20::visitCallMemFence(CallInst* CI) {
+ transMemoryBarrier(CI, std::make_tuple(
+ cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue(),
+ OCLMO_relaxed,
+ OCLMS_work_group));
+}
+
+void SPRVRegularizeOCL20::transMemoryBarrier(CallInst* CI,
+ AtomicWorkItemFenceLiterals Lit) {
+ AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
+ mutateCallInst(M, CI, [=](CallInst *, std::vector<Value *> &Args){
+ Args.resize(2);
+ Args[0] = addInt32(map<Scope>(std::get<2>(Lit)));
+ Args[1] = addInt32(mapOCLMemSemanticToSPRV(std::get<0>(Lit),
+ std::get<1>(Lit)));
+ return getSPRVFuncName(OpMemoryBarrier);
+ }, true, &Attrs);
+}
+
+void
+SPRVRegularizeOCL20::visitCallAtomicLegacy(CallInst* CI,
+ StringRef MangledName, const std::string& DemangledName) {
+ StringRef Stem = DemangledName;
+ if (Stem.startswith("atom_"))
+ Stem = Stem.drop_front(strlen("atom_"));
+ else if (Stem.startswith("atomic_"))
+ Stem = Stem.drop_front(strlen("atomic_"));
+ else
+ return;
+
+ std::string Sign;
+ std::string Postfix;
+ std::string Prefix;
+ if (Stem == "add" ||
+ Stem == "sub" ||
+ Stem == "and" ||
+ Stem == "or" ||
+ Stem == "xor" ||
+ Stem == "min" ||
+ Stem == "max") {
+ if ((Stem == "min" || Stem == "max") &&
+ isMangledTypeUnsigned(MangledName.back()))
+ Sign = 'u';
+ Prefix = "fetch_";
+ Postfix = "_explicit";
+ } else if (Stem == "xchg") {
+ Stem = "exchange";
+ Postfix = "_explicit";
+ }
+ else if (Stem == "cmpxchg") {
+ Stem = "compare_exchange_strong";
+ Postfix = "_explicit";
+ }
+ else if (Stem == "inc" ||
+ Stem == "dec") {
+ // do nothing
+ } else
+ return;
+
+ OCLBuiltinTransInfo Info;
+ Info.UniqName = "atomic_" + Prefix + Sign + Stem.str() + Postfix;
+ std::vector<int> PostOps;
+ PostOps.push_back(OCLLegacyAtomicMemOrder);
+ if (Stem.startswith("compare_exchange"))
+ PostOps.push_back(OCLLegacyAtomicMemOrder);
+ PostOps.push_back(OCLLegacyAtomicMemScope);
+
+ Info.PostProc = [=](std::vector<Value *> &Ops){
+ for (auto &I:PostOps){
+ Ops.push_back(addInt32(I));
+ }
+ };
+ transAtomicBuiltin(CI, Info);
+}
+
+void
+SPRVRegularizeOCL20::visitCallAtomicCpp11(CallInst* CI,
+ StringRef MangledName, const std::string& DemangledName) {
+ StringRef Stem = DemangledName;
+ if (Stem.startswith("atomic_"))
+ Stem = Stem.drop_front(strlen("atomic_"));
+ else
+ return;
+
+ std::string NewStem = Stem;
+ std::vector<int> PostOps;
+ if (Stem.startswith("store") ||
+ Stem.startswith("load") ||
+ Stem.startswith("exchange") ||
+ Stem.startswith("compare_exchange") ||
+ Stem.startswith("fetch") ||
+ Stem.startswith("flag")) {
+ if ((Stem.startswith("fetch_min") ||
+ Stem.startswith("fetch_max")) &&
+ containsUnsignedAtomicType(MangledName))
+ NewStem.insert(NewStem.begin() + strlen("fetch_"), 'u');
+
+ if (!Stem.endswith("_explicit")) {
+ NewStem = NewStem + "_explicit";
+ PostOps.push_back(OCLMO_seq_cst);
+ if (Stem.startswith("compare_exchange"))
+ PostOps.push_back(OCLMO_seq_cst);
+ PostOps.push_back(OCLMS_device);
+ } else {
+ auto MaxOps = getOCLCpp11AtomicMaxNumOps(
+ Stem.drop_back(strlen("_explicit")));
+ if (CI->getNumArgOperands() < MaxOps)
+ PostOps.push_back(OCLMS_device);
+ }
+ } else if (Stem == "work_item_fence") {
+ // do nothing
+ } else
+ return;
+
+ OCLBuiltinTransInfo Info;
+ Info.UniqName = std::string("atomic_") + NewStem;
+ Info.PostProc = [=](std::vector<Value *> &Ops){
+ for (auto &I:PostOps){
+ Ops.push_back(addInt32(I));
+ }
+ };
+
+ transAtomicBuiltin(CI, Info);
+}
+
+void
+SPRVRegularizeOCL20::transAtomicBuiltin(CallInst* CI,
+ OCLBuiltinTransInfo& Info) {
+ AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
+ mutateCallInst(M, CI, [=](CallInst *, std::vector<Value *> &Args){
+ Info.PostProc(Args);
+ auto NumOrder = getAtomicBuiltinNumMemoryOrderArgs(Info.UniqName);
+ auto ScopeIdx = Args.size() - 1;
+ auto OrderIdx = Args.size() - NumOrder - 1;
+ Args[ScopeIdx] = mapUInt(M, cast<ConstantInt>(Args[ScopeIdx]),
+ [](unsigned I){
+ return map<Scope>(static_cast<OCLMemScopeKind>(I));
+ });
+ for (size_t I = 0; I < NumOrder; ++I)
+ Args[OrderIdx + I] = mapUInt(M, cast<ConstantInt>(Args[OrderIdx + I]),
+ [](unsigned Ord) {
+ return mapOCLMemSemanticToSPRV(0, static_cast<OCLMemOrderKind>(Ord));
+ });
+ move(Args, OrderIdx, Args.size(), findFirstPtr(Args) + 1);
+ return getSPRVFuncName(OCLSPRVBuiltinMap::map(Info.UniqName));
+ }, true, &Attrs);
+}
+
+void
SPRVRegularizeOCL20::visitCallReadImage(CallInst* CI,
StringRef MangledName, const std::string& DemangledName) {
if (MangledName.find(kMangledName::Sampler) == StringRef::npos)
diff --git a/lib/SPIRV/SPRVToOCL20.cpp b/lib/SPIRV/SPRVToOCL20.cpp
new file mode 100644
index 0000000..45758ae
--- /dev/null
+++ b/lib/SPIRV/SPRVToOCL20.cpp
@@ -0,0 +1,189 @@
+//===- SPRVToOCL20.cpp - Transform SPIR-V builtins to OCL20 builtins-------===//
+//
+// The LLVM/SPIRV Translator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// Copyright (c) 2014 Advanced Micro Devices, Inc. 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 Advanced Micro Devices, Inc., 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements transform SPIR-V builtins to OCL 2.0 builtins.
+//
+//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "spvtocl20"
+
+#include "SPRVInternal.h"
+#include "OCLUtil.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/InstVisitor.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Pass.h"
+#include "llvm/PassSupport.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace SPRV;
+using namespace OCLUtil;
+
+namespace SPRV {
+class SPRVToOCL20: public ModulePass,
+ public InstVisitor<SPRVToOCL20> {
+public:
+ SPRVToOCL20():ModulePass(ID), M(nullptr), Ctx(nullptr) {
+ initializeSPRVToOCL20Pass(*PassRegistry::getPassRegistry());
+ }
+ virtual bool runOnModule(Module &M);
+ virtual void visitCallInst(CallInst &CI);
+
+ /// Transform __spirv_MemoryBarrier to atomic_work_item_fence.
+ /// __spirv_MemoryBarrier(scope, sema) =>
+ /// atomic_work_item_fence(flag(sema), order(sema), map(scope))
+ void visitCallSPRVMemoryBarrier(CallInst *CI);
+
+ /// Transform __spirv_Atomic* to atomic_*.
+ /// __spirv_Atomic*(atomic_op, scope, sema, ops, ...) =>
+ /// atomic_*(atomic_op, ops, ..., order(sema), map(scope))
+ void visitCallSPRVAtomicBuiltin(CallInst *CI, Op OC);
+
+ /// Transform __spirv_* builtins to OCL 2.0 builtins.
+ /// No change with arguments.
+ void visitCallSPRVBuiltin(CallInst *CI, Op OC);
+
+ static char ID;
+private:
+ Module *M;
+ LLVMContext *Ctx;
+};
+
+char SPRVToOCL20::ID = 0;
+
+bool
+SPRVToOCL20::runOnModule(Module& Module) {
+ M = &Module;
+ Ctx = &M->getContext();
+ visit(*M);
+
+ DEBUG(dbgs() << "After SPRVToOCL20:\n" << *M);
+
+ std::string Err;
+ raw_string_ostream ErrorOS(Err);
+ if (verifyModule(*M, &ErrorOS)){
+ DEBUG(errs() << "Fails to verify module: " << ErrorOS.str());
+ }
+ return true;
+}
+
+void
+SPRVToOCL20::visitCallInst(CallInst& CI) {
+ DEBUG(dbgs() << "[visistCallInst] " << CI << '\n');
+ auto F = CI.getCalledFunction();
+ if (!F)
+ return;
+
+ auto MangledName = F->getName();
+ std::string DemangledName;
+ Op OC = OpNop;
+ if (!oclIsBuiltin(MangledName, 20, &DemangledName) ||
+ (OC = getSPRVFuncOC(DemangledName)) == OpNop)
+ return;
+ DEBUG(dbgs() << "DemangledName = " << DemangledName.c_str() << '\n'
+ << "OpCode = " << OC << '\n');
+
+ if (OC == OpMemoryBarrier) {
+ visitCallSPRVMemoryBarrier(&CI);
+ return;
+ }
+ if (isAtomicOpCode(OC)) {
+ visitCallSPRVAtomicBuiltin(&CI, OC);
+ return;
+ }
+ visitCallSPRVBuiltin(&CI, OC);
+
+}
+
+void SPRVToOCL20::visitCallSPRVMemoryBarrier(CallInst* CI) {
+ AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
+ mutateCallInst(M, CI, [=](CallInst *, std::vector<Value *> &Args){
+ auto getArg = [=](unsigned I){
+ return cast<ConstantInt>(Args[I])->getZExtValue();
+ };
+ auto MScope = static_cast<Scope>(getArg(0));
+ auto Sema = mapSPRVMemSemanticToOCL(getArg(1));
+ Args.resize(3);
+ Args[0] = getInt32(M, Sema.first);
+ Args[1] = getInt32(M, Sema.second);
+ Args[2] = getInt32(M, rmap<OCLMemScopeKind>(MScope));
+ return kOCLBuiltinName::AtomicWorkItemFence;
+ }, true, &Attrs);
+}
+
+void SPRVToOCL20::visitCallSPRVAtomicBuiltin(CallInst* CI, Op OC) {
+ AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
+ mutateCallInst(M, CI, [=](CallInst *, std::vector<Value *> &Args){
+ auto Ptr = findFirstPtr(Args);
+ auto Name = OCLSPRVBuiltinMap::rmap(OC);
+ auto NumOrder = getAtomicBuiltinNumMemoryOrderArgs(Name);
+ auto OrderIdx = Ptr + 1;
+ auto ScopeIdx = Ptr + 1 + NumOrder;
+ if (OC == OpAtomicIIncrement ||
+ OC == OpAtomicIDecrement) {
+ Args.erase(Args.begin() + OrderIdx, Args.begin() + ScopeIdx + 1);
+ } else {
+ Args[ScopeIdx] = mapUInt(M, cast<ConstantInt>(Args[ScopeIdx]),
+ [](unsigned I){
+ return rmap<OCLMemScopeKind>(static_cast<Scope>(I));
+ });
+ for (size_t I = 0; I < NumOrder; ++I)
+ Args[OrderIdx + I] = mapUInt(M, cast<ConstantInt>(Args[OrderIdx + I]),
+ [](unsigned Ord) {
+ return mapSPRVMemOrderToOCL(Ord);
+ });
+ move(Args, OrderIdx, ScopeIdx + 1, Args.size());
+ }
+ return Name;
+ }, true, &Attrs);
+}
+
+void SPRVToOCL20::visitCallSPRVBuiltin(CallInst* CI, Op OC) {
+ AttributeSet Attrs = CI->getCalledFunction()->getAttributes();
+ mutateCallInst(M, CI, [=](CallInst *, std::vector<Value *> &Args){
+ return OCLSPRVBuiltinMap::rmap(OC);
+ }, true, &Attrs);
+}
+
+}
+
+INITIALIZE_PASS(SPRVToOCL20, "spvtoocl20",
+ "Translate SPIR-V builtins to OCL 2.0 builtins", false, false)
+
+ModulePass *llvm::createSPRVToOCL20() {
+ return new SPRVToOCL20();
+}
diff --git a/lib/SPIRV/SPRVUtil.cpp b/lib/SPIRV/SPRVUtil.cpp
index 9bd4de1..b8770c9 100644
--- a/lib/SPIRV/SPRVUtil.cpp
+++ b/lib/SPIRV/SPRVUtil.cpp
@@ -291,6 +291,29 @@ undecorateSPRVFunction(const std::string& S) {
return S.substr(Start, End - Start);
}
+std::string
+prefixSPRVFunction(const std::string &S) {
+ return std::string(kSPRVName::Prefix) + S;
+}
+
+std::string
+dePrefixSPRVFunction(const std::string& S) {
+ StringRef R(S);
+ const size_t Start = strlen(kSPRVName::Prefix);
+ return R.startswith(kSPRVName::Prefix) ? R.drop_front(Start).str() : S;
+}
+
+std::string
+getSPRVFuncName(Op OC) {
+ return prefixSPRVFunction(getName(OC));
+}
+
+Op
+getSPRVFuncOC(const std::string& S) {
+ Op OC;
+ return getByName(dePrefixSPRVFunction(S), OC) ? OC : OpNop;
+}
+
bool oclIsBuiltin(const StringRef &Name, unsigned SrcLangVer,
std::string *DemangledName) {
if (!Name.startswith("_Z"))
@@ -323,6 +346,24 @@ bool oclIsBuiltin(const StringRef &Name, unsigned SrcLangVer,
return true;
}
+// Check if a mangled type name is unsigned
+bool
+isMangledTypeUnsigned(char Mangled) {
+ return Mangled == 'h' /* uchar */
+ || Mangled == 't' /* ushort */
+ || Mangled == 'j' /* uint */
+ || Mangled == 'm' /* ulong */;
+}
+
+// Check if a mangled function name contains unsigned atomic type
+bool
+containsUnsignedAtomicType(StringRef Name) {
+ auto Loc = Name.find(kMangledName::AtomicPrefix);
+ if (Loc == StringRef::npos)
+ return false;
+ return isMangledTypeUnsigned(Name[Loc + strlen(kMangledName::AtomicPrefix)]);
+}
+
bool
isFunctionPointerType(Type *T) {
if (isa<PointerType>(T) &&
@@ -461,6 +502,16 @@ getInt32(Module *M, int value) {
return ConstantInt::get(Type::getInt32Ty(M->getContext()), value, true);
}
+ConstantInt *mapUInt(Module *M, ConstantInt *I,
+ std::function<unsigned(unsigned)> F) {
+ return ConstantInt::get(I->getType(), F(I->getZExtValue()), false);
+}
+
+ConstantInt *mapSInt(Module *M, ConstantInt *I,
+ std::function<int(int)> F) {
+ return ConstantInt::get(I->getType(), F(I->getSExtValue()), true);
+}
+
bool
isSPRVFunction(const Function *F, std::string *UndecoratedName) {
if (!F->hasName() || !F->getName().startswith(kSPRVName::Prefix))
@@ -896,5 +947,6 @@ eraseUselessFunctions(Module *M) {
return changed;
}
+
}
diff --git a/lib/SPIRV/SPRVWriter.cpp b/lib/SPIRV/SPRVWriter.cpp
index 91d5bc0..d5e5fb8 100644
--- a/lib/SPIRV/SPRVWriter.cpp
+++ b/lib/SPIRV/SPRVWriter.cpp
@@ -49,6 +49,7 @@
#include "SPRVExtInst.h"
#include "SPRVUtil.h"
#include "SPRVInternal.h"
+#include "OCLUtil.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
@@ -63,8 +64,8 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
-#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Verifier.h"
+#include "llvm/PassManager.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -83,32 +84,12 @@
using namespace llvm;
using namespace SPRV;
+using namespace OCLUtil;
namespace SPRV{
bool SPRVDbgSaveRegularizedModule = false;
-static int
-getMDOperandAsInt(MDNode* N, unsigned I) {
- auto *C = dyn_cast_or_null<ConstantAsMetadata>(N->getOperand(I));
- return C->getValue()->getUniqueInteger().getZExtValue();
-}
-
-static std::string
-getMDOperandAsString(MDNode* N, unsigned I) {
- Metadata* Op = N->getOperand(I);
- if (!Op)
- return "";
- if (MDString* Str = dyn_cast<MDString>(Op)) {
- return Str->getString().str();
- } else
- return "";
-}
-
-static Type*
-getMDOperandAsType(MDNode* N, unsigned I) {
- return dyn_cast<ValueAsMetadata>(N->getOperand(I))->getType();
-}
static void
decodeMDNode(MDNode* N, unsigned& X, unsigned& Y, unsigned& Z) {
@@ -149,11 +130,11 @@ foreachKernelArgMD(MDNode *MD, SPRVFunction *BF,
}
/// Information for translating OCL builtin.
-struct OCLBuiltinTransInfo {
+struct OCLBuiltinSPRVTransInfo {
std::string UniqName;
/// Postprocessor of operands
std::function<void(std::vector<SPRVWord>&)> PostProc;
- OCLBuiltinTransInfo(){
+ OCLBuiltinSPRVTransInfo(){
PostProc = [](std::vector<SPRVWord>&){};
}
};
@@ -292,7 +273,6 @@ private:
bool isFuncParamSigned(const std::string& MangledName);
void eraseSubstitutionFromMangledName(std::string& MangledName);
- bool isMangledTypeUnsigned(char Mangled);
SPRVInstruction* transBinaryInst(BinaryOperator* B, SPRVBasicBlock* BB);
SPRVInstruction* transCmpInst(CmpInst* Cmp, SPRVBasicBlock* BB);
void mutateFunctionType(const std::map<unsigned, Type*>& ChangedType,
@@ -325,25 +305,11 @@ private:
const std::string &MangledName,
const std::string &DeMangledName, SPRVBasicBlock *BB);
- /// Transform OCL legacy atomic builtin functions for extensions:
- /// cl_khr_int64_base_atomics
- /// cl_khr_int64_extended_atomics
- /// \return true if the called function is a legacy atomic builtin.
- bool getOCLLegacyAtomicTransInfo(OCLBuiltinTransInfo &Info, CallInst *CI,
- const std::string &MangledName, const std::string &DeMangledName);
-
- /// Transform OCL C++11 atomic builtin functions.
- /// \return true if the called function is a C++11 atomic builtin.
- bool getOCLCpp11AtomicTransInfo(OCLBuiltinTransInfo &Info, CallInst *CI,
- const std::string &MangledName, const std::string &DeMangledName);
-
- bool getOCLImageBuiltinTransInfo(OCLBuiltinTransInfo &Info, CallInst *CI,
+ bool getOCLImageBuiltinTransInfo(OCLBuiltinSPRVTransInfo &Info, CallInst *CI,
const std::string &DeMangledName);
SPRVValue *oclTransBarrier(CallInst *Call,
const std::string &DeMangledName, SPRVBasicBlock *BB);
- SPRVValue *oclTransMemFence(CallInst *Call,
- const std::string &DeMangledName, SPRVBasicBlock *BB);
SPRVValue *oclTransWorkGroupBarrier(CallInst *Call,
const std::string &DeMangledName, SPRVBasicBlock *BB);
SPRVValue *transOCLBuiltinToInst(CallInst *Call,
@@ -366,15 +332,15 @@ private:
Function* F);
bool oclIsSamplerType(llvm::Type* RT);
- void getOCLBuiltinTransInfo(OCLBuiltinTransInfo &Info, CallInst *CI,
+ void getOCLBuiltinSPRVTransInfo(OCLBuiltinSPRVTransInfo &Info, CallInst *CI,
const std::string &MangledName, const std::string &DemangledName);
// Transform OpenCL group builtin function names from work_group_
// and sub_group_ to group_.
- bool getOCLGroupBuiltinTransInfo(OCLBuiltinTransInfo &Info, CallInst *CI,
+ bool getOCLGroupBuiltinTransInfo(OCLBuiltinSPRVTransInfo &Info, CallInst *CI,
const std::string &DemangledName);
// Transform OpenCL read_pipe/write_pipe builtin function names
// with reserve_id argument to reserved_read_pipe/reserved_write_pipe.
- bool getOCLPipeBuiltinTransInfo(OCLBuiltinTransInfo &Info, CallInst *CI,
+ bool getOCLPipeBuiltinTransInfo(OCLBuiltinSPRVTransInfo &Info, CallInst *CI,
const std::string &DemangledName);
SPRVValue *transSpcvCast(CallInst* CI, SPRVBasicBlock *BB);
SPRVValue *oclTransSpvcCastSampler(CallInst* CI, SPRVBasicBlock *BB);
@@ -423,7 +389,6 @@ LLVMToSPRV::oclIsBuiltinTransToInst(Function *F) {
SourceLanguage SourceLang = BM->getSourceLanguage(nullptr);
if (SourceLang == SourceLanguageOpenCL) {
return DemangledName == "barrier" ||
- DemangledName == "mem_fence" ||
DemangledName == "dot" ||
DemangledName.find("convert_") == 0 ||
DemangledName.find("atomic_") == 0 ||
@@ -431,7 +396,8 @@ LLVMToSPRV::oclIsBuiltinTransToInst(Function *F) {
DemangledName == "wait_group_events" ||
DemangledName.find("work_group_") == 0 ||
DemangledName.find("sub_group_") == 0 ||
- SPIRSPRVBuiltinInstMap::find(DemangledName);
+ getSPRVFuncOC(DemangledName) != OpNop ||
+ OCLSPRVBuiltinMap::find(DemangledName);
}
llvm_unreachable("not supported");
return false;
@@ -940,7 +906,7 @@ LLVMToSPRV::transCmpInst(CmpInst* Cmp, SPRVBasicBlock* BB) {
}
bool
-LLVMToSPRV::getOCLPipeBuiltinTransInfo(OCLBuiltinTransInfo &Info,
+LLVMToSPRV::getOCLPipeBuiltinTransInfo(OCLBuiltinSPRVTransInfo &Info,
CallInst *CI, const std::string &DemangledName) {
std::string NewName = DemangledName;
if (DemangledName.find(kOCLBuiltinName::ReadPipe) != 0 &&
@@ -956,7 +922,7 @@ LLVMToSPRV::getOCLPipeBuiltinTransInfo(OCLBuiltinTransInfo &Info,
// ToDo: Handle unsigned integer texel type
bool
-LLVMToSPRV::getOCLImageBuiltinTransInfo(OCLBuiltinTransInfo &Info,
+LLVMToSPRV::getOCLImageBuiltinTransInfo(OCLBuiltinSPRVTransInfo &Info,
CallInst *CI, const std::string &DemangledName) {
std::string NewName = DemangledName;
if (DemangledName.find(kOCLBuiltinName::ReadImage) == 0) {
@@ -972,7 +938,7 @@ LLVMToSPRV::getOCLImageBuiltinTransInfo(OCLBuiltinTransInfo &Info,
}
bool
-LLVMToSPRV::getOCLGroupBuiltinTransInfo(OCLBuiltinTransInfo &Info,
+LLVMToSPRV::getOCLGroupBuiltinTransInfo(OCLBuiltinSPRVTransInfo &Info,
CallInst *CI, const std::string &OrigDemangledName) {
auto F = CI->getCalledFunction();
std::vector<SPRVWord> PreOps;
@@ -981,10 +947,10 @@ LLVMToSPRV::getOCLGroupBuiltinTransInfo(OCLBuiltinTransInfo &Info,
return false;
if (DemangledName.find(kOCLBuiltinName::WorkGroupPrefix) == 0) {
DemangledName.erase(0, strlen(kOCLBuiltinName::WorkPrefix));
- PreOps.push_back(SPRVES_Workgroup);
+ PreOps.push_back(ScopeWorkgroup);
} else if (DemangledName.find(kOCLBuiltinName::SubGroupPrefix) == 0) {
DemangledName.erase(0, strlen(kOCLBuiltinName::SubPrefix));
- PreOps.push_back(SPRVES_Subgroup);
+ PreOps.push_back(ScopeSubgroup);
} else
return false;
@@ -1024,137 +990,11 @@ LLVMToSPRV::getOCLGroupBuiltinTransInfo(OCLBuiltinTransInfo &Info,
return true;
}
-bool
-LLVMToSPRV::getOCLLegacyAtomicTransInfo(OCLBuiltinTransInfo &Info,
- CallInst *CI, const std::string &MangledName,
- const std::string &DemangledName) {
- StringRef Stem = DemangledName;
- if (Stem.startswith("atom_"))
- Stem = Stem.drop_front(strlen("atom_"));
- else if (Stem.startswith("atomic_"))
- Stem = Stem.drop_front(strlen("atomic_"));
- else
- return false;
-
- std::string Sign;
- std::string Postfix;
- std::string Prefix;
- if (Stem == "add" ||
- Stem == "sub" ||
- Stem == "and" ||
- Stem == "or" ||
- Stem == "xor" ||
- Stem == "min" ||
- Stem == "max") {
- if (Stem == "min" || Stem == "max") {
- auto LastChar = MangledName.back();
- if (LastChar == 'j' || LastChar == 'm')
- Sign = 'u';
- }
- Prefix = "fetch_";
- Postfix = "_explicit";
- } else if (Stem == "xchg") {
- Stem = "exchange";
- Postfix = "_explicit";
- }
- else if (Stem == "cmpxchg") {
- Stem = "compare_exchange_strong";
- Postfix = "_explicit";
- }
- else if (Stem == "inc" ||
- Stem == "dec") {
- // do nothing
- } else
- return false;
-
- Info.UniqName = "atomic_" + Prefix + Sign + Stem.str() + Postfix;
-
- std::vector<int> PostOps;
- PostOps.push_back(SPIRMO_seq_cst);
- if (Stem.startswith("compare_exchange"))
- PostOps.push_back(SPIRMO_seq_cst);
- PostOps.push_back(SPIRMS_device);
-
- Info.PostProc = [=](std::vector<SPRVWord> &Ops){
- for (auto &I:PostOps)
- Ops.push_back(addInt32(I));
- };
- return true;
-}
-
-static size_t
-getOCLCpp11AtomicMaxNumOps(StringRef Name) {
- return StringSwitch<size_t>(Name)
- .Cases("load", "flag_test_and_set", "flag_clear", 3)
- .Cases("store", "exchange", 4)
- .StartsWith("compare_exchange", 6)
- .StartsWith("fetch", 4)
- .Default(0);
-}
-
-bool
-LLVMToSPRV::getOCLCpp11AtomicTransInfo(OCLBuiltinTransInfo &Info,
- CallInst *CI, const std::string &MangledName,
- const std::string &DemangledName) {
- StringRef Stem = DemangledName;
- if (Stem.startswith("atomic_"))
- Stem = Stem.drop_front(strlen("atomic_"));
- else
- return false;
-
- std::string NewStem = Stem;
- std::vector<int> PostOps;
- if (Stem.startswith("store") ||
- Stem.startswith("load") ||
- Stem.startswith("exchange") ||
- Stem.startswith("compare_exchange") ||
- Stem.startswith("fetch") ||
- Stem.startswith("flag")) {
- if (Stem.startswith("fetch_min") ||
- Stem.startswith("fetch_max")) {
- auto Loc = MangledName.find(kMangledName::AtomicPrefix);
- assert (Loc != std::string::npos && Loc + 1 < MangledName.size());
- auto LastChar = MangledName[Loc + strlen(kMangledName::AtomicPrefix)];
- if (LastChar == 'j' || LastChar == 'm')
- NewStem.insert(NewStem.begin() + strlen("fetch_"), 'u');
- }
-
- if (!Stem.endswith("_explicit")) {
- NewStem = NewStem + "_explicit";
- PostOps.push_back(SPIRMO_seq_cst);
- if (Stem.startswith("compare_exchange"))
- PostOps.push_back(SPIRMO_seq_cst);
- PostOps.push_back(SPIRMS_device);
- } else {
- auto MaxOps = getOCLCpp11AtomicMaxNumOps(
- Stem.drop_back(strlen("_explicit")));
- if (CI->getNumArgOperands() < MaxOps)
- PostOps.push_back(SPIRMS_device);
- }
- } else if (Stem == "work_item_fence") {
- // do nothing
- } else
- return false;
-
- Info.UniqName = std::string("atomic_") + NewStem;
- Info.PostProc = [=](std::vector<SPRVWord> &Ops){
- for (auto &I:PostOps){
- Ops.push_back(addInt32(I));
- }
- };
-
- return true;
-}
-
-void LLVMToSPRV::getOCLBuiltinTransInfo(OCLBuiltinTransInfo &Info,
+void LLVMToSPRV::getOCLBuiltinSPRVTransInfo(OCLBuiltinSPRVTransInfo &Info,
CallInst *CI, const std::string & MangledName,
const std::string &DemangledName) {
if (getOCLGroupBuiltinTransInfo(Info, CI, DemangledName))
return;
- if (getOCLLegacyAtomicTransInfo(Info, CI, MangledName, DemangledName))
- return;
- if (getOCLCpp11AtomicTransInfo(Info, CI, MangledName, DemangledName))
- return;
if (getOCLPipeBuiltinTransInfo(Info, CI, DemangledName))
return;
if (getOCLImageBuiltinTransInfo(Info, CI, DemangledName))
@@ -1600,7 +1440,7 @@ LLVMToSPRV::regularize() {
std::string Err;
raw_string_ostream ErrorOS(Err);
if (verifyModule(*M, &ErrorOS)){
- SPRVDBG(errs() << "Fails to verify module: " << Err;)
+ SPRVDBG(errs() << "Fails to verify module: " << ErrorOS.str();)
return false;
}
@@ -1919,7 +1759,7 @@ LLVMToSPRV::transOCLAsyncGroupCopy(CallInst *CI, const std::string &MangledName,
Args.insert(Args.begin()+3, ConstantInt::get(getSizetType(), 1));
}
auto BArgs = transValue(Args, BB);
- return BM->addAsyncGroupCopy(SPRVES_Workgroup, BArgs[0], BArgs[1], BArgs[2],
+ return BM->addAsyncGroupCopy(ScopeWorkgroup, BArgs[0], BArgs[1], BArgs[2],
BArgs[3], BArgs[4], BB);
}
@@ -1928,9 +1768,9 @@ LLVMToSPRV::transOCLGroupBuiltins(CallInst *CI, const std::string &MangledName,
const std::string &DemangledName, SPRVBasicBlock *BB) {
auto Args = getArguments(CI);
auto BArgs = transValue(Args, BB);
- return BM->addGroupInst(SPIRSPRVBuiltinInstMap::map(DemangledName),
+ return BM->addGroupInst(OCLSPRVBuiltinMap::map(DemangledName),
transType(CI->getType()),
- SPRVES_Workgroup, BArgs, BB);
+ ScopeWorkgroup, BArgs, BB);
}
SPRVWord LLVMToSPRV::oclGetVectorLoadWidth(const std::string& DemangledName) {
@@ -1987,25 +1827,13 @@ LLVMToSPRV::oclTransBarrier(CallInst *CI,
assert(CI->getNumArgOperands() == 1);
auto MemFenceFlagVal = CI->getArgOperand(0);
assert(isa<ConstantInt>(MemFenceFlagVal));
- SPRVValue * CB = BM->addControlBarrierInst(SPRVES_Workgroup, SPRVMS_Workgroup,
- mapBitMask<SPIRSPRVMemFenceFlagMap>(dyn_cast<ConstantInt>(
+ SPRVValue * CB = BM->addControlBarrierInst(ScopeWorkgroup, ScopeWorkgroup,
+ mapBitMask<OCLMemFenceMap>(dyn_cast<ConstantInt>(
MemFenceFlagVal)->getZExtValue()), BB);
return CB;
}
SPRVValue *
-LLVMToSPRV::oclTransMemFence(CallInst *CI,
- const std::string &DemangledName, SPRVBasicBlock *BB) {
- assert(CI->getNumArgOperands() == 1);
- auto MemFenceFlagVal = CI->getArgOperand(0);
- assert(isa<ConstantInt>(MemFenceFlagVal));
- auto MB = BM->addMemoryBarrierInst(SPRVES_Workgroup,
- mapBitMask<SPIRSPRVMemFenceFlagMap>(dyn_cast<ConstantInt>(
- MemFenceFlagVal)->getZExtValue()), BB);
- return MB;
-}
-
-SPRVValue *
LLVMToSPRV::oclTransWorkGroupBarrier(CallInst *CI,
const std::string &DemangledName, SPRVBasicBlock *BB) {
assert(CI->getNumArgOperands() == 1 || CI->getNumArgOperands() == 3);
@@ -2013,19 +1841,19 @@ LLVMToSPRV::oclTransWorkGroupBarrier(CallInst *CI,
assert(isa<ConstantInt>(MemFenceFlagVal));
if (CI->getNumArgOperands() == 1){
- return BM->addControlBarrierInst(SPRVES_Workgroup, SPRVMS_Workgroup,
- mapBitMask<SPIRSPRVMemFenceFlagMap>(dyn_cast<ConstantInt>
+ return BM->addControlBarrierInst(ScopeWorkgroup, ScopeWorkgroup,
+ mapBitMask<OCLMemFenceMap>(dyn_cast<ConstantInt>
(MemFenceFlagVal)->getZExtValue()), BB);
}
Value *MemScopeVal = CI->getArgOperand(1);
assert(isa<ConstantInt>(MemScopeVal));
- assert(dyn_cast<ConstantInt>(MemScopeVal)->getZExtValue() < SPIRMS_Count);
+ assert(dyn_cast<ConstantInt>(MemScopeVal)->getZExtValue() <= OCLMS_sub_group);
- SPRVValue * CB = BM->addControlBarrierInst(SPRVES_Workgroup,
- SPIRSPRVMemScopeMap::map(static_cast<SPIRMemScopeKind>(
+ SPRVValue * CB = BM->addControlBarrierInst(ScopeWorkgroup,
+ OCLMemScopeMap::map(static_cast<OCLMemScopeKind>(
dyn_cast<ConstantInt>(MemScopeVal)->getZExtValue())),
- mapBitMask<SPIRSPRVMemFenceFlagMap>(dyn_cast<ConstantInt>
+ mapBitMask<OCLMemFenceMap>(dyn_cast<ConstantInt>
(MemFenceFlagVal)->getZExtValue()), BB);
return CB;
}
@@ -2048,11 +1876,15 @@ LLVMToSPRV::oclGetMutatedArgumentTypesByBuiltin(
SPRVInstruction *
LLVMToSPRV::transOCLBuiltinToInstByMap(const std::string& DemangledName,
const std::string &MangledName, CallInst* CI, SPRVBasicBlock* BB) {
- auto OC = OpNop;
- OCLBuiltinTransInfo Info;
- getOCLBuiltinTransInfo(Info, CI, MangledName, DemangledName);
+ auto OC = getSPRVFuncOC(DemangledName);
+ OCLBuiltinSPRVTransInfo Info;
+
+ if (OC == OpNop) {
+ getOCLBuiltinSPRVTransInfo(Info, CI, MangledName, DemangledName);
+ OCLSPRVBuiltinMap::find(Info.UniqName, &OC);
+ }
- if (SPIRSPRVBuiltinInstMap::find(Info.UniqName, &OC)) {
+ if (OC != OpNop) {
if (isCmpOpCode(OC)) {
assert(CI && CI->getNumArgOperands() == 2 && "Invalid call inst");
auto ResultTy = CI->getType();
@@ -2112,8 +1944,6 @@ LLVMToSPRV::transOCLBuiltinToInst(CallInst *CI, const std::string &MangledName,
const std::string &DemangledName, SPRVBasicBlock *BB) {
if (DemangledName == "barrier")
return oclTransBarrier(CI, DemangledName, BB);
- if (DemangledName.find("mem_fence") != std::string::npos)
- return oclTransMemFence(CI, DemangledName, BB);
if (DemangledName == "work_group_barrier")
return oclTransWorkGroupBarrier(CI, DemangledName, BB);
if (DemangledName.find("convert_") == 0)
@@ -2138,11 +1968,6 @@ LLVMToSPRV::eraseSubstitutionFromMangledName(std::string& MangledName) {
}
bool
-LLVMToSPRV::isMangledTypeUnsigned(char Mangled) {
- return Mangled == 'h' || Mangled == 't' || Mangled == 'j' || Mangled == 'm';
-}
-
-bool
LLVMToSPRV::isFuncParamSigned(const std::string& MangledName) {
auto Copy = MangledName;
eraseSubstitutionFromMangledName(Copy);
@@ -2283,13 +2108,7 @@ LLVMToSPRV::transOCLKernelMetadata() {
bool
LLVMToSPRV::transSourceLanguage() {
- NamedMDNode *NamedMD = M->getNamedMetadata(SPIR_MD_OCL_VERSION);
- assert (NamedMD && "Invalid SPIR");
- assert (NamedMD->getNumOperands() == 1 && "Invalid SPIR");
- MDNode *MD = NamedMD->getOperand(0);
- unsigned Major = getMDOperandAsInt(MD, 0);
- unsigned Minor = getMDOperandAsInt(MD, 1);
- SrcLangVer = Major * 10 + Minor;
+ SrcLangVer = getOCLVersion(M);
BM->setSourceLanguage(SourceLanguageOpenCL, SrcLangVer);
return true;
}
@@ -2322,7 +2141,7 @@ LLVMToSPRV::dumpUsers(Value* V) {
void
LLVMToSPRV::oclRegularize() {
- legacy::PassManager PassMgr;
+ PassManager PassMgr;
PassMgr.add(createSPRVRegularizeOCL20());
PassMgr.add(createSPRVLowerOCLBlocks());
PassMgr.add(createSPRVLowerBool());
diff --git a/lib/SPIRV/libSPIRV/SPRVEnum.h b/lib/SPIRV/libSPIRV/SPRVEnum.h
index 1e15f1a..b9978c4 100644
--- a/lib/SPIRV/libSPIRV/SPRVEnum.h
+++ b/lib/SPIRV/libSPIRV/SPRVEnum.h
@@ -438,53 +438,12 @@ SPRVMap<SPRVBuiltinVariableKind, std::string>::init() {
typedef SPRVMap<SPRVBuiltinVariableKind, std::string>
SPRVBuiltinVariableNameMap;
-enum SPRVExecutionScopeKind {
-#define _SPRV_OP(x) SPRVES_##x,
-_SPRV_OP(CrossDevice)
-_SPRV_OP(Device)
-_SPRV_OP(Workgroup)
-_SPRV_OP(Subgroup)
-_SPRV_OP(Count)
-#undef _SPRV_OP
-};
-
-inline bool isValid(SPRVExecutionScopeKind Kind) {
- return (unsigned)Kind < (unsigned)SPRVES_Count;
+inline bool isValid(Scope Kind) {
+ return (unsigned)Kind <= (unsigned)ScopeInvocation;
}
-enum SPRVMemoryScopeKind {
-#define _SPRV_OP(x) SPRVMS_##x,
-_SPRV_OP(CrossDevice)
-_SPRV_OP(Device)
-_SPRV_OP(Workgroup)
-_SPRV_OP(Subgroup)
-_SPRV_OP(Invocation)
-_SPRV_OP(Count)
-#undef _SPRV_OP
-};
-
-inline bool isValid(SPRVMemoryScopeKind Kind) {
- return (unsigned)Kind < (unsigned)SPRVMS_Count;
-}
-
-enum SPRVMemorySemanticsMaskKind {
-#define _SPRV_OP(x, y) SPRVMSM_##x = y,
-_SPRV_OP(Relaxed, 1)
-_SPRV_OP(SequentiallyConsistent, 2)
-_SPRV_OP(Acquire, 4)
-_SPRV_OP(Release, 8)
-_SPRV_OP(UniformMemory, 16)
-_SPRV_OP(SubgroupMemory, 32)
-_SPRV_OP(WorkgroupLocalMemory, 64)
-_SPRV_OP(WorkgroupGlobalMemory, 128)
-_SPRV_OP(AtomicCounterMemory, 256)
-_SPRV_OP(ImageMemory, 512)
-_SPRV_OP(Max, 1023)
-#undef _SPRV_OP
-};
-
inline bool isValidSPRVMemSemanticsMask(SPRVWord MemMask) {
- return MemMask <= (unsigned)SPRVMSM_Max;
+ return MemMask < 1 << ((unsigned)MemorySemanticsImageMemoryShift + 1);
}
enum SPRVSamplerAddressingModeKind {
diff --git a/lib/SPIRV/libSPIRV/SPRVInstruction.h b/lib/SPIRV/libSPIRV/SPRVInstruction.h
index 6cf0220..75d1726 100644
--- a/lib/SPIRV/libSPIRV/SPRVInstruction.h
+++ b/lib/SPIRV/libSPIRV/SPRVInstruction.h
@@ -65,9 +65,9 @@ bool isSpecConstantOpAllowedOp(Op OC);
class SPRVComponentExecutionScope {
public:
- SPRVComponentExecutionScope(SPRVExecutionScopeKind TheScope = SPRVES_Count):
+ SPRVComponentExecutionScope(Scope TheScope = ScopeInvocation):
ExecScope(TheScope){}
- SPRVExecutionScopeKind ExecScope;
+ Scope ExecScope;
};
class SPRVComponentMemorySemanticsMask {
@@ -299,10 +299,10 @@ public:
return static_cast<SPRVGroupOperationKind>(Ops[1]);
}
- SPRVExecutionScopeKind getExecutionScope() const {
+ Scope getExecutionScope() const {
if(!hasExecScope())
- return SPRVES_Count;
- return static_cast<SPRVExecutionScopeKind>(Ops[0]);
+ return ScopeInvocation;
+ return static_cast<Scope>(Ops[0]);
}
bool hasVariableWordCount() const {
@@ -1528,8 +1528,8 @@ class SPRVControlBarrier:public SPRVInstruction {
public:
static const Op OC = OpControlBarrier;
// Complete constructor
- SPRVControlBarrier(SPRVExecutionScopeKind TheScope,
- SPRVMemoryScopeKind TheMemScope, SPRVWord TheMemSema,
+ SPRVControlBarrier(Scope TheScope,
+ Scope TheMemScope, SPRVWord TheMemSema,
SPRVBasicBlock *TheBB)
:SPRVInstruction(4, OC, TheBB),ExecScope(TheScope),
MemScope(TheMemScope), MemSema(TheMemSema){
@@ -1537,17 +1537,17 @@ public:
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
- SPRVControlBarrier():SPRVInstruction(OC), ExecScope(SPRVES_Count) {
+ SPRVControlBarrier():SPRVInstruction(OC), ExecScope(ScopeInvocation) {
setHasNoId();
setHasNoType();
}
void setWordCount(SPRVWord TheWordCount) {
SPRVEntry::setWordCount(TheWordCount);
}
- SPRVExecutionScopeKind getExecScope() const {
+ Scope getExecScope() const {
return ExecScope;
}
- SPRVMemoryScopeKind getMemScope() const {
+ Scope getMemScope() const {
return MemScope;
}
bool hasMemSemantic() const {
@@ -1565,8 +1565,8 @@ protected:
isValid(ExecScope);
isValid(MemScope);
}
- SPRVExecutionScopeKind ExecScope;
- SPRVMemoryScopeKind MemScope;
+ Scope ExecScope;
+ Scope MemScope;
SPRVWord MemSema;
};
@@ -1575,7 +1575,7 @@ public:
static const Op OC = OpAsyncGroupCopy;
static const SPRVWord WC = 9;
// Complete constructor
- SPRVAsyncGroupCopy(SPRVExecutionScopeKind TheScope, SPRVId TheId,
+ SPRVAsyncGroupCopy(Scope TheScope, SPRVId TheId,
SPRVValue *TheDest, SPRVValue *TheSrc, SPRVValue *TheNumElems,
SPRVValue *TheStride, SPRVValue *TheEvent, SPRVBasicBlock *TheBB)
:SPRVInstruction(WC, OC, TheEvent->getType(), TheId, TheBB),
@@ -1586,12 +1586,12 @@ public:
assert(TheBB && "Invalid BB");
}
// Incomplete constructor
- SPRVAsyncGroupCopy():SPRVInstruction(OC), ExecScope(SPRVES_Count),
+ SPRVAsyncGroupCopy():SPRVInstruction(OC), ExecScope(ScopeInvocation),
Destination(SPRVID_INVALID), Source(SPRVID_INVALID),
NumElements(SPRVID_INVALID), Stride(SPRVID_INVALID),
Event(SPRVID_INVALID){
}
- SPRVExecutionScopeKind getExecScope() const {
+ Scope getExecScope() const {
return ExecScope;
}
SPRVValue *getDestination()const { return getValue(Destination);}
@@ -1618,7 +1618,7 @@ protected:
SPRVInstruction::validate();
isValid(ExecScope);
}
- SPRVExecutionScopeKind ExecScope;
+ Scope ExecScope;
SPRVId Destination;
SPRVId Source;
SPRVId NumElements;
@@ -1741,7 +1741,7 @@ _SPRV_OP(AtomicSMax, true, 7)
_SPRV_OP(AtomicAnd, true, 7)
_SPRV_OP(AtomicOr, true, 7)
_SPRV_OP(AtomicXor, true, 7)
-_SPRV_OP(MemoryBarrier, false, 4)
+_SPRV_OP(MemoryBarrier, false, 3)
#undef _SPRV_OP
class SPRVImageInstBase:public SPRVInstTemplateBase {
diff --git a/lib/SPIRV/libSPIRV/SPRVModule.cpp b/lib/SPIRV/libSPIRV/SPRVModule.cpp
index 1b0a08f..31b0cd5 100644
--- a/lib/SPIRV/libSPIRV/SPRVModule.cpp
+++ b/lib/SPIRV/libSPIRV/SPRVModule.cpp
@@ -208,7 +208,7 @@ public:
// Instruction creation functions
virtual SPRVInstruction *addPtrAccessChainInst(SPRVType *, SPRVValue *,
std::vector<SPRVValue *>, SPRVBasicBlock *, bool);
- virtual SPRVInstruction *addAsyncGroupCopy(SPRVExecutionScopeKind Scope,
+ virtual SPRVInstruction *addAsyncGroupCopy(Scope Scope,
SPRVValue *Dest, SPRVValue *Src, SPRVValue *NumElems, SPRVValue *Stride,
SPRVValue *Event, SPRVBasicBlock *BB);
virtual SPRVInstruction *addExtInst(SPRVType *,
@@ -239,17 +239,17 @@ public:
virtual SPRVInstruction *addCopyMemorySizedInst(SPRVValue *, SPRVValue *,
SPRVValue *, const std::vector<SPRVWord>&, SPRVBasicBlock *);
virtual SPRVInstruction *addControlBarrierInst(
- SPRVExecutionScopeKind ExecKind, SPRVMemoryScopeKind MemKind,
+ Scope ExecKind, Scope MemKind,
SPRVWord MemSema, SPRVBasicBlock *BB);
virtual SPRVInstruction *addGroupInst(Op OpCode, SPRVType *Type,
- SPRVExecutionScopeKind Scope, const std::vector<SPRVValue *> &Ops,
+ Scope Scope, const std::vector<SPRVValue *> &Ops,
SPRVBasicBlock *BB);
virtual SPRVInstruction *addInstruction(SPRVInstruction *Inst,
SPRVBasicBlock *BB);
virtual SPRVInstruction *addInstTemplate(Op OC,
const std::vector<SPRVWord>& Ops, SPRVBasicBlock* BB, SPRVType *Ty);
virtual SPRVInstruction *addMemoryBarrierInst(
- SPRVExecutionScopeKind ScopeKind, SPRVWord MemFlag, SPRVBasicBlock *BB);
+ Scope ScopeKind, SPRVWord MemFlag, SPRVBasicBlock *BB);
virtual SPRVInstruction *addReturnInst(SPRVBasicBlock *);
virtual SPRVInstruction *addReturnValueInst(SPRVValue *, SPRVBasicBlock *);
virtual SPRVInstruction *addSelectInst(SPRVValue *, SPRVValue *, SPRVValue *,
@@ -804,7 +804,7 @@ SPRVModuleImpl::addSwitchInst(SPRVValue *Select, SPRVBasicBlock *Default,
SPRVInstruction *
SPRVModuleImpl::addGroupInst(Op OpCode, SPRVType *Type,
- SPRVExecutionScopeKind Scope, const std::vector<SPRVValue *> &Ops,
+ Scope Scope, const std::vector<SPRVValue *> &Ops,
SPRVBasicBlock *BB) {
auto WordOps = getIds(Ops);
WordOps.insert(WordOps.begin(), Scope);
@@ -922,14 +922,14 @@ SPRVModuleImpl::addCmpInst(Op TheOpCode, SPRVType *TheType,
}
SPRVInstruction *
-SPRVModuleImpl::addControlBarrierInst(SPRVExecutionScopeKind ExecKind,
- SPRVMemoryScopeKind MemKind, SPRVWord MemSema, SPRVBasicBlock *BB) {
+SPRVModuleImpl::addControlBarrierInst(Scope ExecKind,
+ Scope MemKind, SPRVWord MemSema, SPRVBasicBlock *BB) {
return addInstruction(
new SPRVControlBarrier(ExecKind, MemKind, MemSema, BB), BB);
}
SPRVInstruction *
-SPRVModuleImpl::addMemoryBarrierInst(SPRVExecutionScopeKind ScopeKind,
+SPRVModuleImpl::addMemoryBarrierInst(Scope ScopeKind,
SPRVWord MemFlag, SPRVBasicBlock *BB) {
return addInstruction(SPRVInstTemplateBase::create(OpMemoryBarrier,
nullptr, SPRVID_INVALID,
@@ -953,7 +953,7 @@ SPRVModuleImpl::addPtrAccessChainInst(SPRVType *Type, SPRVValue *Base,
}
SPRVInstruction *
-SPRVModuleImpl::addAsyncGroupCopy(SPRVExecutionScopeKind Scope,
+SPRVModuleImpl::addAsyncGroupCopy(Scope Scope,
SPRVValue *Dest, SPRVValue *Src, SPRVValue *NumElems, SPRVValue *Stride,
SPRVValue *Event, SPRVBasicBlock *BB) {
return addInstruction(new SPRVAsyncGroupCopy(Scope, getId(), Dest, Src,
diff --git a/lib/SPIRV/libSPIRV/SPRVModule.h b/lib/SPIRV/libSPIRV/SPRVModule.h
index a893c5a..5ffdec9 100644
--- a/lib/SPIRV/libSPIRV/SPRVModule.h
+++ b/lib/SPIRV/libSPIRV/SPRVModule.h
@@ -209,7 +209,7 @@ public:
// Instruction creation functions
virtual SPRVInstruction *addPtrAccessChainInst(SPRVType *, SPRVValue *,
std::vector<SPRVValue *>, SPRVBasicBlock *, bool) = 0;
- virtual SPRVInstruction *addAsyncGroupCopy(SPRVExecutionScopeKind Scope,
+ virtual SPRVInstruction *addAsyncGroupCopy(Scope Scope,
SPRVValue *Dest, SPRVValue *Src, SPRVValue *NumElems, SPRVValue *Stride,
SPRVValue *Event, SPRVBasicBlock *BB) = 0;
virtual SPRVInstruction *addBinaryInst(Op, SPRVType *, SPRVValue *,
@@ -240,17 +240,17 @@ public:
virtual SPRVInstruction *addCmpInst(Op, SPRVType *, SPRVValue *,
SPRVValue *, SPRVBasicBlock *) = 0;
virtual SPRVInstruction *addControlBarrierInst(
- SPRVExecutionScopeKind ExecKind, SPRVMemoryScopeKind MemKind,
+ Scope ExecKind, Scope MemKind,
SPRVWord MemSema, SPRVBasicBlock *BB) = 0;
virtual SPRVInstruction *addGroupInst(Op OpCode, SPRVType *Type,
- SPRVExecutionScopeKind Scope, const std::vector<SPRVValue *> &Ops,
+ Scope Scope, const std::vector<SPRVValue *> &Ops,
SPRVBasicBlock *BB) = 0;
virtual SPRVInstruction* addInstTemplate(Op OC,
const std::vector<SPRVWord>& Ops, SPRVBasicBlock* BB, SPRVType *Ty) = 0;
virtual SPRVInstruction *addLoadInst(SPRVValue *,
const std::vector<SPRVWord>&, SPRVBasicBlock *) = 0;
virtual SPRVInstruction *addMemoryBarrierInst(
- SPRVExecutionScopeKind ScopeKind, SPRVWord MemFlag, SPRVBasicBlock *BB)
+ Scope ScopeKind, SPRVWord MemFlag, SPRVBasicBlock *BB)
= 0;
virtual SPRVInstruction *addPhiInst(SPRVType *, std::vector<SPRVValue *>,
SPRVBasicBlock *) = 0;
diff --git a/tools/llvm-spirv/llvm-spirv.cpp b/tools/llvm-spirv/llvm-spirv.cpp
index b73bf6e..25c34c9 100644
--- a/tools/llvm-spirv/llvm-spirv.cpp
+++ b/tools/llvm-spirv/llvm-spirv.cpp
@@ -165,7 +165,7 @@ convertSPRVToLLVM() {
raw_string_ostream ErrorOS(Err);
if (verifyModule(*M, &ErrorOS)){
- errs() << "Fails to verify module: " << Err;
+ errs() << "Fails to verify module: " << ErrorOS.str();
return -1;
}